/**
 * Created by Gifer on 24.05.2017.
 */

var net            = require('net');
var console        = require('gifer-console');
var domainInternal = require('domain').create();
var Service        = require('../service');
var CMD            = require('../cmd/cmd').CMD;
var fs             = require('fs');

var mychatConnect  = null;
var autoCMD        = [
    CMD.sn_invite,
    CMD.sn_iApi,
    CMD.sn_ip_filter,
    CMD.sn_rest_request,
    CMD.sn_operators,
    CMD.sn_support_options,
    CMD.sn_check_token,
    CMD.sn_user_conf_info
];

function MyChatConnect () {
    var CRLF = "\r\n";
    // var CR             = "\r";
    var cmdParser = {};
    var self = this;
    var server = null;
    var MagicPacket = '\u0017\u0006';
    var limitDU = 0;
    var serverSocket = null;

    this.onClose = null;

    this.startInternalServer = function () {
        var data__buffer = "";
        var requests = {};

        console.log('Try start internal server on ' + process.argv.slice(2));

        server = net.createServer(function (socket) {
            socket.on('data', function (data) {
                data__buffer += data.toString();

                parsing.call(socket);
            });

            socket.on('close', function () {
                if (self.onClose) {
                    self.onClose.call(socket, 'END');
                }

                socket.destroy();
            });

            socket.on('error', function (err) {
                if (self.onClose) {
                    self.onClose.call(socket, 'ERROR', err);
                }

                socket.destroy();
            });

            socket.on('timeout', function () {
                if (self.onClose) {
                    self.onClose.call(socket, 'TIMEOUT');
                }

                socket.destroy();
            });

            self.sendDataFromInternalServer = function (data, cb, hash) {
                if (data && (data !== "")) {
                    console.log('sendDataFromInternalServer: ' + data, console.logLevel.DEBUG);

                    if (cb && hash) requests[hash] = cb;

                    socket.write(Service.convertToEntities(data) + CRLF);
                } else {
                    console.err('sendDataFromInternalServer. Nothing send to server, _data is empty', console.logLevel.ERROR);
                }
            };
        });

        domainInternal.on('error', function (err) {
            var port = process.argv[2].toString();
            var ip = process.argv[3] ? process.argv[3].toString() : '127.0.0.1';

            if (process.argv[4] && process.argv[4].toString() === "nologsbuf") {
                console.SetDropTime(-1);
            }

            fs.appendFileSync('../CRASH.log', '[' + new Date() + '] ' + "Can't bind: " + ip + ":" + port + '\n');
            fs.appendFileSync('../CRASH.log', '[' + new Date() + '] ' + "FATAL - " + err.message + '\n');
            fs.appendFileSync('../CRASH.log', '[' + new Date() + '] ' + err.stack + '\n');

            process.exit(702);
        });

        domainInternal.run(function () {
            server.on('connection', function (socket) {
                socket.remoteHostIp = socket.remoteAddress;

                console.log('TCP Connection from: ' + socket.remoteHostIp);
            });

            var ip = '127.0.0.1';
            var port = 2004;

            try {
                port = process.argv[2].toString();

                ip = process.argv.length === 4 && Service.isValidIpAddress(process.argv[3].toString())
                    ? process.argv[3].toString()
                    : '127.0.0.1';

                server.listen(port, ip, function () {
                    console.log('Internal server started on: ' + ip + ":" + port);
                });
            } catch (e) {
                if (self.onClose) {
                    self.onClose('ERROR', 'Incorrect params:' + Array.prototype.join.call(process.argv, ' | '));
                }
            }
        });

        function parsing() {
            var socket = this;

            if (data__buffer.indexOf(CRLF) !== -1) {
                var data = Service.GetSubstring(data__buffer, CRLF);

                data__buffer = Service.GetSubstringFrom(data__buffer, CRLF);

                if (data !== '') {
                    if (data === MagicPacket) {
                        socket.isMyChatServer = true;
                        socket.write(MagicPacket + CRLF);

                        serverSocket = socket;

                        console.log('MyChat Server connected to internal server!');
                    } else
                    if (socket.isMyChatServer) {
                        var CMD_numb = Service.GetSubstring(data, "=").toString();
                        var CMD_data = Service.GetSubstringFrom(data, "=");
                        var Obj = Service.StringToObj(CMD_data);

                        console.log('Internal server send CMD: ' + CMD_numb, console.logLevel.DEBUG);
                        console.log('Internal server send data: ' + CMD_data, console.logLevel.DEBUG);

                        Obj.CMD = CMD_numb; // "sn_" commands // 7.7

                        if (cmdParser.hasOwnProperty(CMD_numb)) {
                            cmdParser[CMD_numb].apply(self, [Obj, requests]);
                        } else
                        // если нужна ответка по hаsh-у, то нужно добавить ответную команду в список autoCMD
                        if (autoCMD.indexOf(CMD_numb) !== -1) {
                            uni_proc(Obj, requests);
                        }
                    }

                    if (socket.isMyChatServer && data__buffer.length > 0) {
                        process.nextTick(function () {
                            parsing.call(socket);
                        });
                    }
                }
            }

            if (!socket.isMyChatServer) {
                socket.destroy();
            }
        }

        function uni_proc(Obj, requests) {
            if (Service.isObject(Obj) && Obj.hasOwnProperty('hash') && requests[Obj.hash]) {
                requests[Obj.hash](Obj);

                delete requests[Obj.hash];
            } else {
                console.err('Hash not found: ' + (Service.isObject(Obj) ? Obj.hash : "unknown data"), console.logLevel.ERROR);
            }
        }

        server.maxConnections = 10;
    };

    this.addCmdParser = function (cmd, func) {
        cmdParser[cmd] = func;
    };

    this.delCmdParser = function (cmd) {
        if (cmdParser.hasOwnProperty(cmd)) {
            delete cmdParser[cmd];
        }
    };

    this.closeServer = function () {
        if (serverSocket){
            serverSocket.destroy();
        } else {
            process.exit(666);
        }
    };

    this.getDownloadUpdatesLimit = function () {
        return limitDU;
    };

    this.setDownloadUpdatesLimit = function (limit) {
        limitDU = limit;
    };
}

if (!(mychatConnect instanceof MyChatConnect)) {
    mychatConnect = new MyChatConnect();
}

module.exports = mychatConnect;
