/**
 * Created by Gifer on 10.07.2017.
 */

const jsFTP        = require("jsftp");
const console      = require("gifer-console");
const EventEmitter = require('events').EventEmitter;
const os           = require('os');
const Service      = require('./service');
const EVENTS       = {
    TIMEOUT   : -2,
    ERROR     : -1,
    FILE_LIST : 1,
    CONNECTED : 2,
    LOGGED_IN : 3,
    PROGRESS  : 4,
    DEBUG     : 5,
    DOWNLOADED: 6,
    UPLOADED  : 7,
    MD_DONE   : 8
};
const COMMANDS     = {
    // Commands without parameters
    'abor': 'abor', 'pwd' : 'pwd' , 'cdup': 'cdup', 'feat': 'feat',
    'noop': 'noop', 'quit': 'quit', 'pasv': 'pasv', 'syst': 'syst',
    
    // Commands with one or more parameters
    'appe': 'appe', 'cwd' : 'cwd ' , 'dele': 'dele', 'list': 'list',
    'mdtm': 'mdtm', 'mkd' : 'mkd' , 'mode': 'mode', 'nlst': 'nlst',
    'pass': 'pass', 'retr': 'retr', 'rmd' : 'rmd' , 'rnfr': 'rnfr',
    'rnto': 'rnto', 'site': 'site', 'stat': 'stat', 'stor': 'stor',
    'type': 'type', 'user': 'user', 'xrmd': 'xrmd', 'opts': 'opts',
    'rest': 'rest',

    // Extended features
    'chmod': 'chmod', 'size': 'size', 'mlst': 'mlst', 'mlsd': 'mlsd'
};
const ext          = require('./service.js').ExtractFileExtension;

function CreateFtpConnection(mainWindow, dialogs) {
    let Ftp        = null;
    let features   = [];
    let isLoggedIn = false;
    let selfFTP    = this;
    let cwd        = "/";
    let progressData = {};

    let seconds_between = 1;
    let start_time      = (new Date()).getTime();
    let trSize          = 0;
    let speed           = 0;
    let current_size    = 0;
    let downloadStart   = false;

    EventEmitter.call(this);

    this.openDialog = function (path, file, isOpenDialog) {
        return new Promise(function (resolve, reject) {
            if (dialogs){
                let openPath = "";
                let fileExt  = ext(file || "*");

                if (os.platform() === 'win32') {
                    openPath = path.replace(/\//g, '\\');

                    if (openPath[openPath.length - 1] !== '\\'){
                        openPath += "\\";
                    }
                } else {
                    openPath = path.replace(/\\/g, '/');

                    if (openPath[openPath.length - 1] !== '/'){
                        openPath += "/";
                    }
                }

                dialogs[isOpenDialog ? "showOpenDialog" : "showSaveDialog"](mainWindow, {
                    defaultPath: decodeURI(openPath + (file || "")),
                    //properties : ['openDirectory']
                    filters: [{
                        name: fileExt === "*" ? "All Files" : fileExt,
                        extensions: [fileExt]
                    }]
                })
                .then(function ({canceled, filePath}) {
                    // download(filename, url, path, onError);
                    resolve([filePath, canceled]);
                });
            } else {
                reject('[ftpDownloadFile]: dialogs is undefined!');
                // console.error('[downloadFile]: dialogs is undefined!');
            }
        });
    };

    this.checkLogin = function () {
        return isLoggedIn;
    };

    this.connect = function (opts) {
        Ftp = new jsFTP({
             useList: true,
             host: opts.host || MCServer.Host,
             port: opts.port || MCServer.PortFTP,
             user: opts.login,
             pass: opts.pwd
        });

        Ftp.auth(opts.login, opts.pwd, function () {
            Ftp.execute('CLNT MyChat', function () {
                Ftp.execute('OPTS UTF8 ON', function () {
                    selfFTP.emit(EVENTS.LOGGED_IN, features);
                });
            });
        });

        Ftp.on('jsftp_receive', function(data) {
            selfFTP.emit(EVENTS.DEBUG, "RECEIVE", JSON.stringify(data, null, 2));
        });

        Ftp.on('jsftp_send', function(data) {
            selfFTP.emit(EVENTS.DEBUG, "SEND", JSON.stringify(data, null, 2));
        });

        Ftp.on('connect', function () {
            isLoggedIn = true;

            selfFTP.emit(EVENTS.CONNECTED, arguments);
        });

        Ftp.on('closed', function () {
            isLoggedIn    = true;
            progressData  = {};
            downloadStart = false;

            selfFTP.emit(EVENTS.CONNECTED, arguments);
        });

        Ftp.on('timeout', function () {
            isLoggedIn    = false;
            progressData  = {};
            downloadStart = false;

            selfFTP.emit(EVENTS.TIMEOUT, arguments);
        });

        Ftp.on('error', function (err) {
            isLoggedIn    = false;
            progressData  = {};
            downloadStart = false;

            selfFTP.emit(EVENTS.ERROR, err);
        });

        Ftp.on('progress', function (data) {
            if (downloadStart){
                if (seconds_between === 0) {
                    seconds_between = 1;
                }

                trSize  = current_size + (data.transferred || 0); //(data.transferred || data.total) ;
                speed   = Math.round((speed + trSize / seconds_between) / 2);
                percent = (trSize / progressData.onePercent).toFixed();

                seconds_between = Math.round(((new Date()).getTime() - start_time) / 1000);

                // console.log(percent);

                progressData = {
                    // trSize : trSize,
                    text   : Service.format_size(trSize),
                    speed  : speed,
                    percent: percent,
                    // total  : progressData.total,
                    size   : progressData.size,
                    onePercent: progressData.onePercent
                };

                selfFTP.emit(EVENTS.PROGRESS, progressData);
            } else {
                selfFTP.emit(EVENTS.PROGRESS, data);
            }
        });
    };

    this.fileList = function (path, cb) {
        return new Promise(function (resolve, reject) {
            Ftp.ls(path || '/', function (err, res) {
                if (cb) {
                    cb.apply(null, arguments);
                } else
                if (err) {
                    selfFTP.emit(EVENTS.ERROR, err);

                    reject(err);
                } else {
                    selfFTP.emit(EVENTS.FILE_LIST, res);

                    resolve(res);
                }
            });
        });
    };
    
    this.download = function (pathToFile, downloadTo, fileSize) {
        seconds_between = 1;
        start_time      = (new Date()).getTime();
        trSize          = 0;
        speed           = 0;
        downloadStart   = true;
        progressData    = {};

        progressData.onePercent = fileSize / 100;
        progressData.size = Service.format_size(fileSize);
        
        return new Promise(function (resolve, reject) {
            Ftp.get(pathToFile, downloadTo, function (err) {
                downloadStart = false;

                if (err){
                    selfFTP.emit(EVENTS.ERROR, err);

                    reject(err);
                } else {
                    selfFTP.emit(EVENTS.DOWNLOADED);

                    resolve();
                }
            });
        });
    };

    this.getProgress = function () {
        return progressData;
    };

    this.abort = function () {
        return new Promise(function (resolve, reject) {
            if (Ftp) {
                Ftp.execute("abor");
                resolve();
            } else reject('No FTP connection!');
        });
    };

    this.upload = function (fromPath, toPath) {
        return new Promise(function (resolve, reject) { // resolve, reject
            if (Ftp) {
                Ftp.put(fromPath, toPath, function (data) {
                    selfFTP.emit(EVENTS.UPLOADED, data);

                    resolve();
                })
            } else reject('No FTP connection!');
        });
    };

    this.getCWD = function () {
        return cwd;
    };

    this.PWD = function () {
        Ftp.execute("pwd");
    };

    this.CWD = function (path) {
        return new Promise(function (resolve, reject) {
            Ftp.execute(COMMANDS.cwd + path, function (err, data) {
                if (err && err.code === 550) {
                    reject(err.code, err);
                } else {
                    cwd = path;

                    resolve(path);
                }
            });
        });
    };

    this.close = function (quit) {
        if (quit) {
            try {
                Ftp.execute(COMMANDS.quit, function () {
                    try {
                        Ftp.destroy();
                    } catch (e) {}
                });
            } catch(e){}
        } else {
            try {
                Ftp.destroy();
            } catch (e) {}
        }

        isLoggedIn = false;
        features   = [];
        Ftp        = null;
        cwd        = "/";
        progressData = {};
    };

    this.md = function (path) {  // make dir
        return new Promise(function () { // resolve, reject
            Ftp.execute(COMMANDS.mkd, path, function (err, data) {
                if (err) {
                    selfFTP.emit(EVENTS.ERROR, err);
                } else {
                    selfFTP.emit(EVENTS.MD_DONE, data, path);
                }
            });
        });
    };

    this.keepAlive = function () {
        Ftp.keepAlive();
    };

    this.sendCMD = function (cmd) {
        Ftp.execute(cmd);
    };

    this.const = EVENTS;

    this.commands = COMMANDS;
}

require('util').inherits(CreateFtpConnection, EventEmitter);

module.exports = CreateFtpConnection;
