"use strict";

 var Service    = require('./service.js');
 var console    = require('gifer-console');
 var URL        = require('url');
 var internal   = require('./mctools/mcInternalConnection.js');
 var CMD        = require('./cmd/cmd').CMD;

 var Resources        = null;
 var HEAD_Processing  = null;
 var POST_Processing  = null;
 var cacheHandler     = null;
 var _clearCache      = null;
 var aliasesIDX       = null;

 try {
     POST_Processing  = require('./post_parser.js').Parse;
     HEAD_Processing  = require('./head_parser.js').do;
 } catch (e) {}

 function enableCache(useCache){
     if (!useCache) return;

     var cacheOptions = {
         watchDirectoryChange: false,
         watchFileChange     : true,
         maxSize  : 25000000,
         TTL      : 24,
         mandatory: [MCPathes.Updates + "mcupdate.zip", MCPathes.Plugins + "MediaCalls.zip"],
         hashAlgo : 'sha256',
         gzip     : true,
         etag     : true,
         lastmod  : true,
         expires  : 3600000,
         maxAge   : 3600
     };

     var fileCache = require('./filecache.js')(cacheOptions);
     var path      = '';
     var location  = '';
     var reportErrorTimer = null;
     var errString = "";

     function makeErrorReport(err){
         if (!reportErrorTimer){
             reportErrorTimer = setTimeout(function(){
                 var srt = err;

                 errString = "";

                 console.err("Cache file not found during scanning: " + srt, console.logLevel.ERROR);

                 reportErrorTimer = null;
             }, 3000);
         } else {
             errString += "\n" + err;

             if (errString.length > 30000){
                 console.err("Cache file not found during scanning: " + errString, console.logLevel.ERROR);

                 errString = "";
             }
         }
     }

     for (var i in Resources){
         if (Resources[i].cache){
             path     = Service.isString(Resources[i].source) ? Resources[i].source : Resources[i].source();
             location = (Resources[i].realPath || Resources[i].pathWWW).replace(/\/|\\/g,'');

             path += path[path.length - 1] !== '/' ? '/' : '';

             console.info('Caching folder: ' + path + location, console.logLevel.INFO);

             fileCache.load(path + location, {
                 prefix: location.length > 0 ? '/' + location : ''
             });
         }
     }

     fileCache.on('ready', function() {
         cacheHandler = fileCache.httpHandler(cacheOptions);
     });

     fileCache.on('error', function(error) {
         if (error.code && error.code === "ENOENT"){
             makeErrorReport(error.message);
         }
     });

     fileCache.on('errorLimit', function(error) {
         console.err("File doesn't added into cache, because it's too large:\n path - " + error.path + ", size - " + error.size + ', limit - ' + error.limit, console.logLevel.ERROR);
     });

     _clearCache = fileCache.clearCache;
 }

 function getCookies(request) {
    var cookies = {};

    if (request.headers && request.headers.cookie) {
        request.headers.cookie.split(';').forEach(function(cookie) {
            var parts = cookie.match(/(.*?)=(.*)$/);

            cookies[ parts[1].trim() ] = (parts[2] || '').trim();
        });
    }

    return cookies;
 }

 function checkPath(req, res, _IDX) {
     // === CORS Headers ===
     res.setHeader("Access-Control-Allow-Origin",  "*");
     res.setHeader("Access-Control-Allow-Methods", "*");
     res.setHeader("Access-Control-Allow-Headers", "origin, content-type, accept");

     switch (req.method){
         case "GET" :
             if ((_IDX === aliasesIDX.lobby  && !MCServer.Lobby) ||
                 (_IDX === aliasesIDX.admin  && !MCServer.Aliases.admin.enabled && req.remoteHostIp !== "127.0.0.1" && req.remoteHostIp !== "::1") ||
                 (_IDX === aliasesIDX.chat   && !MCServer.Aliases.chat.enabled) ||
                 (_IDX === aliasesIDX.forum  && !MCServer.Aliases.forum.enabled) ||
                 (_IDX === aliasesIDX.kanban && !MCServer.Aliases.kanban.enabled)
             ) {
                 res.statusCode = 403;
                 res.end(Service.Const.denied);

                 console.info("Service \"" + Resources[_IDX].pathWWW + "\", access denied for ip: " + req.remoteHostIp, console.logLevel.INFO);
             } else {
                 res.setHeader('Set-Cookie', 'SameSite=None; Secure'); // todo: хрень, пока не понимаю с чем ее есть

                 var uri   = URL.parse(req.url).pathname;
                 var _root = (Service.isFunction(Resources[_IDX].source)) ? Resources[_IDX].source() : Resources[_IDX].source;

                 if ( Resources[_IDX].realPath ){
                     uri = uri.replace(Resources[_IDX].pathWWW, Resources[_IDX].realPath);
                 }

                 if ( _IDX.length === 20 ){
                     uri   = Service.ExtractFileName(Resources[_IDX].source);
                     _root = Service.ExtractPath(Resources[_IDX].source);
                 }

                 if (MCServer.WEBUseCache && cacheHandler !== null){
                     cacheHandler(uri, _root, req, res, function(next) {
                         if (next) {
                             Service.sendFiles(req, res, uri, _root);
                         }
                     });
                 } else {
                     Service.sendFiles(req, res, uri, _root);
                 }
             }

             // _res = true;
         break;

         case "POST": POST_Processing.call(this, req, res); /*_res = true;*/ break;

         case "HEAD": HEAD_Processing(req, res); /*_res = true;*/ break;
     }
 }

 /**
  * @return {undefined}
  */
 function ParseRequest(req, res, noSSL){
 	var _IDX   = -1;
	var maxLen = -1;
    // var _res   = false;
    var _path  = URL.parse(req.url).pathname;
    var match  = false;
    var srch   = "";
    var socket = this;

    console.log("Request for " + _path + " received.", console.logLevel.DEBUG);

    if (_path) {
        srch = URL.parse(req.url).search;

        for (var i in Resources){
            match = _path.indexOf(Resources[i].pathWWW) === 0;

            if (noSSL && !Resources[i].noSSL){ // Если приходит запрос на дублирующий сервер для ХР на запрещенный путь - игнорим
                continue;
            }

            if (Resources[i].hasOwnProperty('redirect') && _path === Resources[i].redirect){
                res.writeHead(302, {
                    'Location': Resources[i].pathWWW + (srch || "")
                });
                res.end();

                _IDX = -1;

                break;
            }

            if ((_path === Resources[i].pathWWW) || (Resources[i].hasParams && match)) {
                _IDX = i;

                break;
            } else
            if (match){
                var _curLen = Resources[i].pathWWW.split('/').length - 1;

                if (maxLen < _curLen){
                    _IDX = i;
                    maxLen = _curLen;
                }
            }
        }

        if (_IDX !== -1 && Resources[_IDX].redirectTo){
            if (Resources[_IDX].redirectTo === aliasesIDX.lobby  && !MCServer.Lobby) {
                res.statusCode = 403;
                res.end(Service.Const.denied);

                console.info("Blocked access to Lobby for ip: " + socket.remoteHostIp, console.logLevel.INFO);
            } else {
                res.writeHead(302, {
                    'Location': req.url.replace(Resources[_IDX].pathWWW, Resources[Resources[_IDX].redirectTo].pathWWW) + (srch || "")
                });

                res.end();
            }
        } else
        if (_IDX !== -1){

            var localPath = Service.GetSubstringFrom(_path,Resources[_IDX].pathWWW);

            res.setHeader('MyChat-version', MCServer.ClientVersion);

            req.routePath = Resources[_IDX].pathWWW;

            if (Resources[_IDX].runFunc){
                Resources[_IDX].CallBack.call(null, req, res, localPath, cacheHandler, socket.remoteHostIp);
            } else {
                var type = Resources[_IDX].type

                if (type === CMD.ClientType.COMMON){
                    checkPath(req, res, _IDX);
                } else
                if (type && socket.isIpChecked && !socket.isIpChecked[type]) {
                    var hash = Service.RandomHash(7);

                    socket.sendDataInternal(CMD.ns_ip_filter + '=' + JSON.stringify({
                        hash: hash,
                        ip  : socket.remoteHostIp,
                        type: type
                    }), function(info){
                        if (info && info.access){
                            socket.isIpChecked[type] = true;
                            
                            checkPath(req, res, _IDX);
                        } else {
                            res.statusCode = 403;
                            res.end(Service.Const.denied);

                            console.info("Blocked by IP filter for ip: " + socket.remoteHostIp, console.logLevel.INFO);
                        }
                    }, hash);
                } else {
                    checkPath(req, res, _IDX);
                }
            }
        }
    }
 }

 /**
  * @return {number}
  */
 function AddRoutPath(_rout){
 	var Option = Service.Extend({
		host : MCServer.Host,
		pathWWW : '/',
		source : './',
		TTL : ''
	}, _rout || {});

    var res = undefined;
    var idx = Service.RandomHash(20);

    if (Resources[idx]) {
        res = AddRoutPath(Option)
    } else {
        Resources[idx] = Option;

        res = idx;
    }

    return res;
 }
 
 function AddRandomPath(_opt){
 	var Option = Service.Extend({
		host     : MCServer.Host,
		pathWWW  : '/',
		source   : './',
		email    : 'support@nsoft-s.com',
        fileName : '/img.jpg',
		TTL      : ''
	}, _opt || {});
	
	Option.pathWWW = '/' + Service.RandomHash(32) + Option.fileName;// + Service.ExtractFileName(Option.source);
	
	// Непостредственная вставка виртуального пути в список Роутер_лист
    var idx = AddRoutPath(Option);
	
	console.info("Added random path: " + Option.pathWWW + " for file: " + Option.source, console.logLevel.DEBUG);
	console.log("Total pathes: " + JSON.stringify(Resources), console.logLevel.DEBUG);

	return [idx, Option.pathWWW];
 }
 
 function DelRoutPath(idx){
     if (Resources[idx]) {
         delete Resources[idx];
     }
 }
 
 function LoadPathes(){
     //TODO: save pathes to the server and load on start
 }

 function clearCache() {
     if (_clearCache) {
         _clearCache();
     }
 }

 exports.setAliases     = function () {
     Resources  = require('./resourceList').list(MCServer.Aliases);
     aliasesIDX = require('./resourceList').aliasesIDX;
 };
 exports.enableCache    = enableCache;
 exports.clearCache     = clearCache;
 exports.GO             = ParseRequest;
 exports.AddRandomPath  = AddRandomPath;
 exports.AddPath        = AddRoutPath;
 exports.LoadPathes     = LoadPathes;
 exports.DelRoutPath    = DelRoutPath;