/**
 * 应用程序入口。
 */
var express = require('express');
var swagger = require("swagger-node-express");
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var log = require('./util/log');

// server configurations
var APIv1 = require('./include/endpoints').APIv1;
var PAGES = require('./include/endpoints').PAGES;

var configFile = require('./include/commons').CONFIG_FILE;
var config = require('./resources/config/' + configFile);

// pages
var index = require('./controllers/index');
var socket = require('./controllers/socket');

// endpoints
var application = require('./endpoints/application.endpoint');
var users = require('./endpoints/users.endpoint');
var groups = require('./endpoints/groups.endpoint');
var chats = require('./endpoints/chats.endpoint');
var management = require('./endpoints/management.endpoint');

// handlers
var socketHandler = require('./handlers/socket.handler');

// initialize express application
var app = express();
app.set('port', config.serverPort);

// view engine
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

// logger, body parser, cookie parser and view path
app.use(favicon(__dirname + '/public/favicon.ico', null));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

// pages
app.use(PAGES.Home.Index, index);
app.use(PAGES.Socket.Index, socket);

// setup rest endpoints
app.use(APIv1.Application.Base, application);
app.use(APIv1.Chats.Base, chats);
app.use(APIv1.Users.Base, users);
app.use(APIv1.Groups.Base, groups);
app.use(APIv1.Management.Base, management);

// error handler, only handle the sync call exception
app.use(function (err, req, res, next) {
    if (err) {
        res
            .status(err.httpStatus || 500)
            .send({message: err.message});
    }

    next(err);
});

// In development mode, error handler will print stacktrace, only handle the sync call exception
if (app.get('env') === 'development') {
    app.use(function (err, req, res, next) {
        log.error(err);

        next(err);
    });
}

// only handle the sync call exception
process.on('uncaughtException', function (err) {
    console.error(err);
});

// now enable http server and socket.io
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);

server.listen(config.serverPort);

// event listener for HTTP server "error" event
server.on('error', function(error) {
    if (error.syscall !== 'listen') throw error;

    var bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port;

    // handle specific listen errors with friendly messages
    switch (error.code) {
        case 'EACCES':
            console.error(bind + ' requires elevated privileges');
            process.exit(1);
            break;
        case 'EADDRINUSE':
            console.error(bind + ' is already in use');
            process.exit(1);
            break;
        default:
            throw error;
    }
});

// event listener for HTTP server "listening" event
server.on('listening', function onListening() {
    var addr = server.address();
    var bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port;
});

io.sockets.on('connection', socketHandler.onConnection);

log.info('Starting IM server, version', config.version, ',', new Date().toLocaleString());
log.info('Server running on port', server.address().port);

module.exports = app;
