/**
 * base-server.js
 * Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
 *
 * Contact:
 * DongHee Yang <donghee.yang@samsung.com>
 * Sungmin Kim <sm.art.kim@samsung.com>
 * Jiil Hyoun <jiil.hyoun@samsung.com>
 * Jonghwan Park <iwin100.park@samsung.com>
 * Kitae Kim <kt920.kim@samsung.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Contributors:
 * - S-Core Co., Ltd
**/

var net = require('net');
var os = require('os');
var path = require('path');
var async = require('async');
var fs = require('fs');
var _ = require('underscore');
var diskspace = require('diskspace');

var dibs = require('./dibs.js');
var rpc = require('./rpc.js');
var utils = require('../lib/utils.js');
var DError = require('./exception.js');
var EventManager = require('./event-manager.js');
var TriggerManager = require('./trigger-manager.js');
var DHandle = require('./error-handler.js');

/**
 * @module core/base-server
 */

/**
 * callback callback_err_serverid
 * @param {error|undefined} error
 * @param {string} serverid
 * @memberOf module:core/base-server
 */

/**
 * callback callback_err_server
 * @param {error|undefined} error
 * @param {module:core/base-server.BaseServer} server
 * @memberOf module:core/base-server
 */

/**
 * @typedef {object} logger
 * @property {log} error
 * @property {log} warn
 * @property {log} error
 * @memberOf module:core/base-server
 */

/**
 * @typedef {object} options
 * @property {string} key - key : value format Hash object for server option
 * @memberOf module:core/base-server
 */

/**
 * @typedef {object} status
 * @property {string} status
 * @property {number} cpuUsage
 * @property {number} memUsage
 * @property {number} diskUsage
 * @memberOf module:core/base-server
 */

/**
 * @typedef {object} osinfo
 * @property {string} platform
 * @property {string} arch
 * @property {number} totalmem
 * @property {number} freemem
 * @memberOf module:core/base-server
 */

/**
 * @constructor
 * @param {string} sid - server id
 * @param {string} stype - server type
 * @memberOf module:core/base-server
 */
function BaseServer(sid, stype) {
    /**
     * @constant {string} STATUS_RUNNING
     * @default "RUNNING"
     * @memberOf module:core/base-server.BaseServer
     */
    BaseServer.STATUS_RUNNING = 'RUNNING';
    /**
     * @constant {string} STATUS_INITIALIZING
     * @default "INITIALIZING"
     * @memberOf module:core/base-server.BaseServer
     */
    BaseServer.STATUS_INITIALIZING = 'INITIALIZING';
    /**
     * @constant {string} STATUS_INITIALIZED
     * @default "INITIALIZED"
     * @memberOf module:core/base-server.BaseServer
     */
    BaseServer.STATUS_INITIALIZED = 'INITIALIZED';
    /**
     * @constant {string} STATUS_TERMINATED
     * @default "TERMINATED"
     * @memberOf module:core/base-server.BaseServer
     */
    BaseServer.STATUS_TERMINATED = 'TERMINATED';

    /** type {string} */
    this.status = BaseServer.STATUS_INITIALIZING;
    /** type {string} */
    var self = this;
    /** type {string} */
    this.id = sid;
    /** type {string} */
    this.type = stype;
    /** type {string} */
    this.host = null;
    /** type {string} */
    this.port = null;
    /** type {number} */
    this.cpuUsage = 0;
    /** type {number} */
    this.memUsage = 0;
    /** type {number} */
    this.diskUsage = 0;
    /** type {boolean} */
    this.diskspaceShortage = false;

    //os info
    /** type {string} */
    this.platform = null;
    /** type {string} */
    this.arch = null;
    /** type {number} */
    this.totalmem = 0;
    /** type {number} */
    this.freemem = 0;

    /** type {module:core/base-server.logger} */
    this.log = {
        info: console.log,
        warn: console.log,
        error: console.log
    };


    this.serverHandle = null;
    // handle for agent server(optional)
    this.agentServer = null;

    var connectionHandlers = {};

    var scheduledActions = {};
    // For maintaining all connected sockets
    var sockets = {};
    var nextSocketId = 0;

    // For managing event listener
    var eventManager = EventManager.create(self);

    // For managing trigger
    var triggerManager = TriggerManager.create(self);

    // Add RPC methods
    var methods = rpc.getRpcModule(stype);
    if (methods !== null) {
        for (var fname in methods) {
            /**
             * @type {rpc_call_module}
             * @memberOf module:core/base-server.BaseServer
             */
            this[fname] = rpc.createRpcCall(fname);
        }
    }


    // handler MUST have function 'handleConnection( header, connection )'
    this.addConnectionHandler = function (type, handler) {
        connectionHandlers[type] = handler;
    };


    /**
     * @function start
     * @param {string} port
     * @param {module:core/base-server.options} options
     * @returns {undefined}
     * @memberOf module:core/base-server.BaseServer
     */
    this.start = function (port, options, callback) {
        dibs.thisServer = this;
        self.status = 'INITIALIZING';
        self.host = utils.getHostIp();
        self.port = port;
        if (options === undefined) {
            options = {};
        }
        self.startOptions = options;

        var baseConfig = dibs.config.getBaseConfig({
            id: self.id,
            host: self.host,
            port: self.port,
            type: self.type
        });
        var defaultConfig = this.getDefaultConfiguration(baseConfig);
        self.config = dibs.config.openServerConfig(this, defaultConfig);

        var logDbHost = self.config.get('remote_log_db_host') || null;
        var logDbName = self.config.get('remote_log_db_name') || null;
        var serverLog = self.config.get('server_log') || true;
        var logOptions = {};
        if (serverLog) {
            if (serverLog === 'file') {
                logOptions.filename = path.join(dibs.config.getConfigDir(), self.id, 'log');
            } else if (serverLog === 'remote') {
                logOptions.remoteLogDbHost = logDbHost;
                logOptions.remoteLogDbName = logDbName;
            } else if (serverLog === 'console') {

            } else { // default setting is all
                logOptions.filename = path.join(dibs.config.getConfigDir(), self.id, 'log');
                logOptions.remoteLogDbHost = logDbHost;
                logOptions.remoteLogDbName = logDbName;
            }
        }
        logOptions.debug = self.config.get('debug') || false;

        self.log = dibs.log.open(self.id, logOptions);

        self.log.info('Server is started');
        self.log.info('id: [' + self.id + ']');
        self.log.info('address: [' + self.host + ']');
        self.log.info('port: [' + self.port + ']');

        //set server information
        setServerEnvironment();

        // set scheduled-action handler
        HandleScheduledActions();

        var server = this;

        async.series([
            function (cb) {
                if (server.OnServerStarting !== undefined) {
                    server.log.info('Executing \'OnServerStarting\' CALLBACK...');
                    server.OnServerStarting(cb);
                } else {
                    cb(null);
                }
            },
            function (cb) {
                server.log.info('Starting TCP/IP server...');
                rpc.createLogger(path.join(dibs.config.getConfigDir(), self.id, 'rpc.log'));
                self.serverHandle = net.createServer(onConnection);
                self.serverHandle.listen(port);
                self.serverHandle.on('error', function (err) {
                    if (err.code === 'EADDRINUSE') {
                        cb(new DError('ERR002', {
                            host: self.host,
                            port: self.port
                        }));
                    }
                });
                self.serverHandle.on('listening', function () {

                    cb(null);
                });
            },
            function (cb) {
                console.log('Server is LISTENING!');
                self.status = BaseServer.STATUS_INITIALIZED;

                // Wait connect master server
                if (self.type !== 'master' && self.type !== 'agent') {
                    var wait = setInterval(function () {
                        if (isConnectMaster() === true) {
                            server.log.warn('Connected master server...');
                            clearInterval(wait);
                            cb(null);
                        } else {
                            server.log.warn('Waiting for connecting master server...');
                        }
                    }, 1000);
                } else {
                    cb(null);
                }
            },
            function (cb) {
                // register server information(ex. environment)
                if (self.type !== 'master' && self.type !== 'agent') {
                    var info = {};
                    info.environments = self.environments;
                    dibs.rpc.master.registerServerInfo(self.id, info, cb);
                } else {
                    cb(null);
                }
            },
            function (cb) {
                if (server.OnServerStarted !== undefined) {
                    server.log.info('Executing "OnServerStarted" CALLBACK...');
                    server.OnServerStarted(cb);
                } else {
                    cb(null);
                }
            },
            function (cb) {
                server.status = 'RUNNING';
                server.log.info('Server is READY!');
                console.log('Server is READY!');
                cb(null);
            },
            function (cb) {
                // waiting master server ready
                if (server.type !== 'agent') {
                    masterServerIsReady(cb);
                }
            },
            function (cb) {
                if (server.OnMasterServerIsReady !== undefined) {
                    server.log.info('Executing "OnMasterServerIsReady" CALLBACK...');
                    server.OnMasterServerIsReady(cb);
                } else {
                    cb(null);
                }
            },
            function (cb) {
                if (server.type !== 'agent') {
                    registerTriggerActions(cb);
                }
            }
        ],
        function (err) {
            if (err) {
                server.log.error(err);
            } else {
                // write PORT_NUMBER
                var workingPortFile = path.join(dibs.config.getConfigDir(), self.id, 'PORT');
                fs.writeFileSync(workingPortFile, self.port);
            }
            callback(err);
        });
    };


    /**
     * @function terminate
     * @param {module:lib/utils.callback_error} callback
     * @memberOf module:core/base-server.BaseServer
     */
    this.terminate = function (options, callback) {
        var server = this;

        // check whether this server is already in terminating
        if (server.status === 'TERMINATING' ||
            server.status === 'TERMINATED') {

            server.log.warn('Server is already in \'TERMINATING\' or \'TERMINATED\' state!');
            callback(new DError('ERR005', {
                sid: server.id
            }));
            return;
        }

        // move new status to "TERMINTING"
        server.status = 'TERMINATING';

        var cbCalled = false; /* for checking error on 'OnServerTerminating' callback */
        async.series([
            function (cb) {
                if (server.OnServerTerminating) {
                    server.log.info('Executing \'OnServerTerminating\' CALLBACK...');
                    server.OnServerTerminating(cb);
                } else {
                    cb(null, null);
                }
            },
            function (cb) {
                server.log.info('Server terminated!');
                server.status = 'TERMINATED';
                setTimeout(function () {
                    // destroy all opened sockets
                    var sockCount = 0;
                    for (var socketId in sockets) {
                        sockets[socketId].destroy();
                        sockCount++;
                    }
                    server.log.info('Connected sockets are destroyed forcely : ' + sockCount);
                    var called = false;
                    server.serverHandle.close(function () {
                        if (!called) {
                            cb(null); called = true;
                        }
                    });
                    setTimeout(function () {
                        if (!called) {
                            server.log.info('Closing server handle timed out!');
                            cb(null); called = true;
                        }
                    }, 1000);
                }, 500);
                callback(null);
                cbCalled = true;
            },
            function (cb) {
                if (!options.noProcessExit) {
                    server.log.info('Process exiting...');
                    setTimeout(function () {
                        process.exit(0);
                    }, 100);
                }
                cb(null, null);
            }
        ], function (err) {
            if (!cbCalled) {
                callback(err);
            }
        });
    };


    /**
     * @method updateServerInformations
     * @param {object} server - server id
     * @returns {module:core/base-server.status}
     * @memberOf module:core/base-server.BaseServer
     */
    this.updateServerInformations = function (servers) {
        var oldServers = dibs.getAllServers();
        var olds = _.map(oldServers, genConfigKey);
        var news = _.map(servers, genConfigKey);
        var removes = _.difference(olds, news);

        _.each(removes, function (removeKey) {
            dibs.removeServer(parseConfigKey(removeKey));
        });

        _.each(servers, updateServerInformation);
    };

    function updateServerInformation(s) {
        var server = dibs.getServer(s.id);

        if (server === null) {
            server = dibs.createServer(s.id, s.type);
            server.host = s.host;
            server.port = s.port;
            server.status = s.status;
            dibs.addServer(server);
            self.log.info('Added new server information!:' + s.id + ',' + s.status);
        } else {
            if (server.status !== s.status) {
                server.status = s.status;
                self.log.info('Server status is changed!:' + s.id + ',' + s.status);
                self.emitEvent({
                    event: 'SERVER_STATUS_CHANGED',
                    status: s.status,
                    server: s
                });

            }

            if (server.platform !== s.platform) {
                server.platform = s.platform;
                server.arch = s.arch;

                self.log.info('Server os information is registered: ' + s.id + ',' + s.platform);
            }

            if (!_.isEqual(server.environments, s.environments)) {
                server.environments = s.environments;

                self.log.info('Server environments information is registered: ' + s.id);
            }

            if (!_.isEqual(server.config, s.config)) {
                self.log.info('Server configurations is registered: ' + s.id);

                if (s.config) {
                    var conf = null;
                    if (s.config.getConfigData) {
                        conf = s.config.getConfigData();
                    } else {
                        conf = s.config;
                    }
                    server.config = dibs.config.newServerConfig(server, conf);
                    if (s.id === self.id) {
                        dibs.config.createServerConfig(self, conf);
                        self.config = server.config;
                    }
                }
            }
        }

        return;
    }

    function genConfigKey(config) {
        return config.id + ':' + config.host + ':' + config.port + ':' + config.type;
    }

    function parseConfigKey(key) {
        var info = key.split(':');
        return {
            id: info[0],
            host: info[1],
            port: info[2],
            type: info[3]
        };
    }

    /**
     * @method getStatus
     * @param {module:core/base-server.status} callback
     * @memberOf module:core/base-server.BaseServer
     */
    this.getStatus = function (callback) {
        var server = {};
        var mountPath;

        if (os.platform() === 'win32') {
            mountPath = process.env.SYSTEMROOT.toString().split(':')[0];
        } else {
            mountPath = process.env.HOME;
        }

        if (this.id === dibs.thisServer.id) {
            var handler = {
                try: function () {
                    diskspace.check(mountPath, function (err, total, free, status) {
                        if (err) {
                            self.log.error('failed to get diskspace');
                            self.log.error(err);
                        } else {
                            server.status = dibs.thisServer.status;
                            server.cpuUsage = os.loadavg()[0].toFixed(1);
                            server.memUsage = ((os.totalmem() - os.freemem()) / os.totalmem() * 100).toFixed(1);
                            server.diskUsage = (((total - free) / total) * 100).toFixed(0);
                        }
                        callback(null, server);
                    });
                },
                catch: function (err) {}
            };

            DHandle.run(handler);
        } else {
            server.status = this.status;
            server.cpuUsage = this.cpuUsage;
            server.memUsage = this.memUsage;
            server.diskUsage = this.diskUsage;
            callback(null, server);
        }
    };

    this.isOnline = function () {
        return (this.status === 'INITIALIZED' || this.status === 'RUNNING');
    };



    /**
     * @method onConnection
     * @param {object} connection
     * @returns {undefined}
     * @memberOf module:core/base-server.BaseServer
     */
    function onConnection(c) {

        var header = null;
        var receivedStr = '';
        var outStream = null;

        if (c.remoteAddress && c.remotePort) {
            header = {
                remoteAddress: c.remoteAddress,
                remotePort: c.remotePort
            };
        }

        // Add new socket
        var socketId = nextSocketId++;
        sockets[socketId] = c;

        var d = rpc.createStream(self, header);

        // setup pipe
        var errorHandler = function (err) {
            self.log.error(new DError('RPC009', {
                sid: '--',
                functionName: '----'
            }, err));
            self.log.error(err);
        };
        c.on('error', errorHandler)
            .pipe(d).on('error', errorHandler)
            .pipe(c).on('error', errorHandler);

        //self.serverHandle.getConnections( function(err, cnt) {
            //    self.log.info("Connections:"+cnt );
            //});

        // Remove socket when closed
        c.once('close', function () {
            delete sockets[socketId];
        });
    /* NOTE. This code can be used when merging RPC, DFS protocol
    // overide 'readable' event
    c.on( 'readable', function() {
        // check header exist
        if ( header === null ) {
            // read from stream, but less than 1024
            var buf = c.read(1024);
            if (!buf) buf = c.read();
            if (!buf) return;

            // extract header
            var matches = buf.toString().match( /^{.*}\|\|/g );
            if ( matches === null ) {
                c.unshift( buf );
                return;
            }
            header = JSON.parse( matches[0].slice(0, matches[0].length - 2 ) );

            // unshift
            c.unshift( buf.slice( matches[0].length ) );

            if ( header.type == 'rpc' ) {
                // create stream
                outStream = rpc.createStream( self, header );

                if ( !outStream ) { c.destroy(); return; }

                // setup pipe
                var errorHandler = function(err) {
                    self.log.error( new DError("RPC009", {
                        sid: header.sid,
                        functionName: header.fname }, err ) );
                };
                c.on( 'error', errorHandler )
                    .pipe( outStream ).on( 'error', errorHandler )
                    .pipe( c ).on( 'error', errorHandler );
            } else {
                if ( connectionHandlers[ header.type ] !== undefined ) {
                    connectionHandlers[header.type].handleConnection( header, c );
                } else {
                    self.log.error( new DError("NET001", { host: c.remoteAddress } ) );
                    c.destroy(); return;
                }
            }
        }
    });
    */
    }


    /**
     * @method setServerEnvironment
     * @memberOf module:core/base-server.BaseServer
     */
    function setServerEnvironment() {
        utils.getCurrentEnvironmentsByServer(self, function (result) {
            self.environments = result;
        });
    }


    function HandleScheduledActions() {
        setInterval(function () {
            executeScheduledActionsInternal(function (err) {});
        }, 1000);
    }


    function executeScheduledActionsInternal(callback) {
        var removeActions = [];

        async.each(Object.keys(scheduledActions),
            function (key, cb) {
                var action = scheduledActions[key];
                // NOTE. while executing this action, the entry can be deleted.
                //   So, the following code is needed

                if (!action) {
                    self.log.error('[' + key + '] scheduledAction is undefined');
                    cb(null);
                    return;
                }
                var date = new Date();
                if ((dibs.thisServer.status === 'INITIALIZED' ||
                    dibs.thisServer.status === 'RUNNING') &&
                    action.nextTick.getTime() - date.getTime() <= 0) {

                    // check if previous execution is finished
                    if (action.isExecuting) {
                        cb(null);
                        return;
                    }

                    action.isExecuting = true;
                    // TODO: Need to review timeout control
                    //var timeoutProcess;
                    //if(action.timeout !== -1) {
                    //    timeoutProcess = setTimeout(function() {
                    //        cb(new DError("SAH002", {key: key}));
                    //    }, action.timeout);
                    //}

                    action.execute(function (err) {
                        //clearTimeout(timeoutProcess);

                        if (action.period && action.period !== -1) {
                            var calcNextTick = new Date(action.nextTick.getTime() + action.period);
                            var currTick = new Date();
                            if (calcNextTick.getTime() - currTick.getTime() > 0) {
                                action.nextTick = calcNextTick;
                            } else {
                                action.nextTick = new Date(currTick.getTime());
                            }
                        } else {
                            removeActions.push(key);
                        }

                        // if notification set, notify its completion
                        if (action.notify) {
                            action.notify.forEach(function (notification) {
                                notification(err);
                            });
                            delete action['notify'];
                        }

                        // NOTE. MUST BE null to execute sheduled actions
                        action.isExecuting = false;
                        cb(null);
                    });
                } else {
                    cb(null);
                }
            },
            function (err) {
                // Remove executed non-periodic actions
                removeActions.forEach(function (key) {
                    delete scheduledActions[key];
                });

                callback(err);
            });
    }


    this.addScheduledAction = function (key, options, action) {
        self.log.info('Adding scheduled action... ' + key);

        var nextTick = options.startTime;
        var period = options.period;
        var timeout = options.timeout || -1;
        if (!nextTick) {
            nextTick = new Date();
        }

        // check if startTime is Date object
        if (!(nextTick instanceof Date)) {
            self.log.error('[' + key + '] nextTick instance is not \'Date\'');
            return false;
        }

        if (!period || period <= 0) {
            period = -1;
        }

        // check if action is function type
        if (typeof action !== 'function') {
            self.log.error('[' + key + '] action type is not \'function\'');
            return false;
        }

        // if already exists, replace it
        scheduledActions[key] = {
            execute: action,
            nextTick: nextTick,
            period: period,
            timeout: timeout
        };

        return true;
    };


    this.removeScheduledAction = function (key) {
        self.log.info('Removing scheduled action...' + key);
        if (scheduledActions[key] !== undefined) {
            delete scheduledActions[key];
        }
    };


    this.getScheduledAction = function (key) {
        if (scheduledActions[key]) {
            return scheduledActions[key];
        } else {
            return null;
        }
    };


    this.waitForNextScheduledAction = function (key, callback) {
        if (!scheduledActions[key]) {
            callback(new DError('SAH001', {
                key: key
            }));
            return;
        }

        var action = scheduledActions[key];
        if (action.notify) {
            action.notify.push(callback);
        } else {
            action.notify = [callback];
        }
    };


    // add event listener
    this.addEventListener = function (evtName, evtOpts, listener, callback) {
        eventManager.addEventListener(evtName, evtOpts, listener, callback);
    };


    this.addEventListener2 = function (evtListener, callback) {
        eventManager.addEventListener2(evtListener, callback);
    };


    // remove event listener
    this.removeEventListener = function (evtListener, callback) {
        eventManager.removeEventListener(evtListener, callback);
    };


    // emit server event
    this.emitEvent = function (evtObj) {
        eventManager.emitEvent(evtObj);
    };


    // execute event listener
    this.executeEventListeners = function (evtObj, callback) {
        eventManager.executeEventListeners(evtObj, callback);
    };


    // get list of listeners
    this.getEventListeners = function (event, callback) {
        eventManager.getEventListeners(event, callback);
    };


    // add trigger
    this.addTriggerAction = function (trigger, callback) {
        triggerManager.addTriggerAction(trigger, callback);
    };


    // remove trigger
    this.removeTriggerAction = function (triggerId, callback) {
        triggerManager.removeTriggerAction(triggerId, callback);
    };


    // search triggers
    this.searchTriggerActions = function (condition, callback) {
        triggerManager.searchTriggerActions(condition, callback);
    };


    // modify trigger
    this.modifyTriggerAction = function (trigger, callback) {
        triggerManager.modifyTriggerAction(trigger, callback);
    };


    function registerTriggerActions(callback) {
        async.waterfall([
            function (cb) {
                var datamgrServer = dibs.getServersByType('datamgr')[0];
                if (datamgrServer) {
                    datamgrServer.searchTriggers({
                        serverType: self.type
                    }, cb);
                } else {
                    dibs.log.info('cannot use data-manager server');
                    cb(null, []);
                }
            },
            function (triggers, cb) {
                async.each(triggers, function (trigger, cb1) {
                    self.addTriggerAction(trigger, cb1);
                },
                    function (err) {
                        if (err) {
                            dibs.log.error(err);
                        }
                        cb(err);
                    });
            }
        ],
        function (err) {
            if (err) {
                dibs.log.error('Failed to register triggers in server: ' + self.type);
            }
            callback(err);
        });
    }


    function masterServerIsReady(callback) {
        var statusListener = null;
        var masterServer = dibs.getServersByType('master')[0];

        // agent server is stand-alone type
        if (self.type === 'agent') {
            callback(null);
        } else if (!masterServer) {
            self.log.error('Can not get master-server');
            callback(new Error('Can not get master-server'));
        } else {
            if (masterServer.status === 'RUNNING') {
                callback(null);
            } else {
                // waiting server ready
                self.addEventListener('SERVER_STATUS_CHANGED', { }, function (evtObj, listenerCB) {
                    if (evtObj.server.type === 'master' && evtObj.status === 'RUNNING') {
                        if (statusListener) {
                            self.removeEventListener(statusListener, function (err) {
                                if (err) {
                                    self.log.warn('Fail remove listener:');
                                    self.log.warn(err);
                                }
                            });
                        }
                        callback(null);
                    }
                    listenerCB(null);
                }, function (err, listener) {
                    if (err) {
                        self.log.error('Fail register listener');
                        self.log.error(err);
                        callback(err);
                    }
                    statusListener = listener;
                });
            }
        }
    }
}


/**
 * @function createServer
 * @param {string} server id - server id
 * @param {string} server type - server type
 * @returns {module:module:core/base-server.BaseServer}
 * @memberOf module:core/base-server
 */

module.exports.createServer = function (sid, stype) {
    return new BaseServer(sid, stype);
};

function isConnectMaster() {
    var master = dibs.getMasterServer();

    if (master === null) {
        return false;
    } else {
        return true;
    }
}
