"use strict";

// var CRLF = "\r\n";
var CR   = "\r";
// var LF   = "\n";

var Service	  = require('./service.js');
var console	  = require('gifer-console');
var MCConnect = require('./mcconnect');
var uuid      = require('node-uuid');
var CMD       = require('./cmd/cmd').CMD;

var inc             = 0;
var ParseFunctions  = {};
var key             = uuid.v1(); //Service.RandomHash(256); // "supersecretkey"

/**
 * @return {string}
 */
function SessionID_Generator (){
    inc ++;

    return inc + Service.RandomHash(50);
}

function _Auth(_data, cmd, CallBack, Host){
    var socket        = this.socket || this;
    var isWs          = !this.socket;
    var id            = SessionID_Generator();
    var data          = Service.StringToObj(_data);
    var originPass    = "";
    var originSrvPass = "";

    socket.mcSessionID = id;

    function doLogin(id, data,  encrypted){
        MCConnect.MakeClientConnection({
            login      : data.UIN,
            pass       : originPass,

            Gender               : data.Gender,
            Email                : data.Email,
            SecretQuestionNumber : data["SecretN"] || -1,
            SecretAnswer         : data["SecretA"] || "",
            ClientType           : data.ClientType || "web",
            Style                : data.Style,
            NodeUserAgent        : data.UserAgent,
            NodeReferral         : data.Referral,
            State                : data.State,
            Lang                 : data.Lang,
            NodeLanguage         : data["Language"],
            NodeOS               : data.OS,
            SessionID            : data.SessionID,
            AuthService          : data.AuthService,
            AutoLogin            : data.AutoLogin,
            // hmhWHO               : data.WHO,
            Token                : data.Token,
            UTC                  : data.UTC,

            ServPass             : originSrvPass,

            PingDelay  : data.PingDelay || 25,
            host       : MCServer.Host,
            port       : MCServer.MCPort,
            clientIP   : Host,
            sessionID  : id,
            authType   : cmd,

            isWs : isWs,
            io   : isWs ? socket : null
        });

        if (CallBack){
            var pwd = "";

            if (encrypted) {
                pwd = CR + data.Pass + CR + (data.ServPass || "");
            } else {
                pwd = CR + ((data.Pass)     ? Service.Encrypt(key + Host + data.UserAgent, data.Pass)     : "") +
                      CR + ((data.ServPass) ? Service.Encrypt(key + Host + data.UserAgent, data.ServPass) : "");
            }

            CallBack(CMD.OK + CR + id + pwd);
        } else {
            console.err('Not assigned CallBack on CMD:' + cmd, console.logLevel.ERROR);
        }
    }

    function _go(){
        var data = Service.StringToObj(_data);
        var encrypted = false;

        try {
            originPass    = (data.RM) ? Service.Decrypt(key + Host + data.UserAgent, data.Pass) : data.Pass;
            originSrvPass = (data.ServPass && data.RM) ? Service.Decrypt(key + Host + data.UserAgent, data.ServPass) : (data.ServPass || "");

            encrypted = true;
        } catch (e){
            originPass    = data.Pass || "";
            originSrvPass = data.ServPass || "";
        }

        if (MCConnect.getPenaltyUser(data.UIN) && cmd === CMD.Login){
            setTimeout(function(){
                doLogin(id, data, encrypted);
            }, 3000);
        } else {
            doLogin(id, data, encrypted);
        }
    }

    // ==========================

    var hash = Service.RandomHash(30);

    if (socket && socket.sendDataInternal) {
        socket.sendDataInternal(CMD.ns_ip_filter + '=' + JSON.stringify({
            hash: hash,
            ip  : Host, // socket.remoteHostIp,
            type: data.ClientType
        }), function(info){
            if (info && info.access){
                _go();
            } else {
                CallBack(CMD.Blocked + CR + info.error);
            }
        }, hash);
    } else {
        _go();
    }
}

ParseFunctions[CMD.Login]       = function Login(_data, SendDataToWebClient, Host){
    _Auth.call(this, _data, CMD.Login, SendDataToWebClient, Host);
};

ParseFunctions[CMD.Register]    = function Register(_data, SendDataToWebClient, Host){
    _Auth.call(this, _data, CMD.Register, SendDataToWebClient, Host);
};

ParseFunctions[CMD.cs_login_by_token]    = function cs_login_by_token(_data, SendDataToWebClient, Host){
    _Auth.call(this, _data, CMD.cs_login_by_token, SendDataToWebClient, Host); // hmh_cs_register : "0001", // зарегистрировать нового юзера
};

ParseFunctions[CMD.Ping]        = function Ping(_data, SendDataToWebClient){ // sessionID
    var data = _data.split(CR);
    var sID  = data[0];
    var out  = null;

    if (MCConnect.HasConnection(sID)){
        out = MCConnect.GetConnection(sID).UsersInBuffer.GetFromInBuf(MCServer.sendBufferSize);

        if (SendDataToWebClient) SendDataToWebClient(CMD.Ping + CR + out);

        MCConnect.SendDataToServer(sID, MCConnect.CMD.cs_ping);
    } else {
        out = MCConnect.getFromErrorBuffer(sID) || {};
        out[MCConnect.CMD.sc_drop_connect] = {};

        SendDataToWebClient(CMD.Ping + CR + JSON.stringify(out));
    }
};

ParseFunctions[CMD.ns_check_invite] = function(_data, SendDataToWebClient, _host){
    var data      = _data.split(CR);
    var invite    = data[0];
    var userAgent = data[1];
    var socket    = this.socket || this;

    // console.log("ns_check_invite userAgent: " + userAgent);

    if (!invite || !Service.isString(invite) || invite.length !== 32){
        SendDataToWebClient(CMD.sn_invite + CR + JSON.stringify({
            passed: false
        }));
    } else {
        var hash  = Service.RandomHash(10);

        socket.sendDataInternal(CMD.ns_check_invite + '=' + JSON.stringify({
            hash      : hash,
            invite    : invite,
            useragent : userAgent,
            ip        : _host
        }), function (data) {
            SendDataToWebClient(data.CMD + CR + JSON.stringify(data));
        }, hash);
    }
};

ParseFunctions[CMD.ns_check_group_invite] = function(_data, SendDataToWebClient, _host){
    var data      = _data.split(CR);
    var invite    = data[0];
    var userAgent = data[1];
    var socket    = this.socket || this;

    if (!invite || !Service.isString(invite) || invite.length !== 32){
        SendDataToWebClient(CMD.sn_check_group_invite + CR + JSON.stringify({
            passed: false
        }));
    } else {
        var hash  = Service.RandomHash(10);

        socket.sendDataInternal(CMD.ns_check_group_invite + '=' + JSON.stringify({
            hash      : hash,
            invite    : invite,
            useragent : userAgent,
            ip        : _host
        }), function (data) {
            SendDataToWebClient(data.CMD + CR + JSON.stringify(data));
        }, hash);
    }
};

ParseFunctions[CMD.ns_get_by_groups] = function(_data, SendDataToWebClient, _host){
    var ids    = _data;
    var socket = this.socket || this;
    var hash   = Service.RandomHash(10);

    socket.sendDataInternal(CMD.ns_get_by_groups + '=' + JSON.stringify({
        hash : hash,
        id   : ids
    }), function (data) {
        SendDataToWebClient(data.CMD + CR + JSON.stringify(data.Users));
    }, hash);
};

ParseFunctions[CMD.ns_get_by_uins] = function(_data, SendDataToWebClient, _host){
    var ids    = _data;
    var socket = this.socket || this;
    var hash   = Service.RandomHash(10);

    socket.sendDataInternal(CMD.ns_get_by_uins + '=' + JSON.stringify({
        hash : hash,
        uins : ids
    }), function (data) {
        SendDataToWebClient(data.CMD + CR + JSON.stringify(data.Users));
    }, hash);
};

function UniversalParser (_CMD, _data, SendDataToWebClient, isIO){
    if (ParseFunctions.hasOwnProperty(_CMD)) {
        var _host = this.conn ? this.conn.remoteAddress : this.remoteHostIp;

        ParseFunctions[_CMD].call(this, _data, SendDataToWebClient, _host);
    } else {
        var data = _data.split(CR);
        var sID  = data.shift().toString();

        MCConnect.SendDataToServer(sID, _CMD, data);

        if (SendDataToWebClient && isIO !== true) {
            SendDataToWebClient(CMD.OK);
        }
    }
}

exports.UniversalParser = UniversalParser;