/* jslint node: true */
'use strict';

//  ENiGMA½
var Log             = require('./logger.js').log;
var renegadeToAnsi  = require('./color_codes.js').renegadeToAnsi;

var iconv           = require('iconv-lite');
var assert          = require('assert');
var _               = require('lodash');

exports.ClientTerminal  = ClientTerminal;

function ClientTerminal(output) {
    this.output     = output;

    var outputEncoding = 'cp437';
    assert(iconv.encodingExists(outputEncoding));

    //  convert line feeds such as \n -> \r\n
    this.convertLF      = true;

    //
    //  Some terminal we handle specially
    //  They can also be found in this.env{}
    //
    var termType        = 'unknown';
    var termHeight      = 0;
    var termWidth       = 0;
    var termClient      = 'unknown';

    this.currentSyncFont    = 'not_set';

    //  Raw values set by e.g. telnet NAWS, ENVIRONMENT, etc.
    this.env            = {};

    Object.defineProperty(this, 'outputEncoding', {
        get : function() {
            return outputEncoding;
        },
        set : function(enc) {
            if(iconv.encodingExists(enc)) {
                outputEncoding = enc;
            } else {
                Log.warn({ encoding : enc }, 'Unknown encoding');
            }
        }
    });

    Object.defineProperty(this, 'termType', {
        get : function() {
            return termType;
        },
        set : function(ttype) {
            termType = ttype.toLowerCase();

            if(this.isANSI()) {
                this.outputEncoding = 'cp437';
            } else {
                //  :TODO: See how x84 does this -- only set if local/remote are binary
                this.outputEncoding = 'utf8';
            }

            //  :TODO: according to this: http://mud-dev.wikidot.com/article:telnet-client-identification
            //  Windows telnet will send "VTNT". If so, set termClient='windows'
            //  there are some others on the page as well

            Log.debug( { encoding : this.outputEncoding }, 'Set output encoding due to terminal type change');
        }
    });

    Object.defineProperty(this, 'termWidth', {
        get : function() {
            return termWidth;
        },
        set : function(width) {
            if(width > 0) {
                termWidth = width;
            }
        }
    });

    Object.defineProperty(this, 'termHeight', {
        get : function() {
            return termHeight;
        },
        set : function(height) {
            if(height > 0) {
                termHeight = height;
            }
        }
    });

    Object.defineProperty(this, 'termClient', {
        get : function() {
            return termClient;
        },
        set : function(tc) {
            termClient = tc;

            Log.debug( { termClient : this.termClient }, 'Set known terminal client');
        }
    });
}

ClientTerminal.prototype.disconnect = function() {
    this.output = null;
};

ClientTerminal.prototype.isNixTerm = function() {
    //
    //  Standard *nix type terminals
    //
    if(this.termType.startsWith('xterm')) {
        return true;
    }

    return [ 'xterm', 'linux', 'screen', 'dumb', 'rxvt', 'konsole', 'gnome', 'x11 terminal emulator' ].includes(this.termType);
};

ClientTerminal.prototype.isANSI = function() {
    //
    //  ANSI terminals should be encoded to CP437
    //
    //  Some terminal types provided by Mercyful Fate / Enthral:
    //      ANSI-BBS
    //      PC-ANSI
    //      QANSI
    //      SCOANSI
    //      VT100
    //      QNX
    //
    //  Reports from various terminals
    //
    //  NetRunner v2.00beta 20
    //      * This version adds 256 colors and reports as "ansi-256color"
    //
    //  syncterm:
    //      * SyncTERM
    //
    //  xterm:
    //      * PuTTY
    //
    //  ansi-bbs:
    //      * fTelnet
    //
    //  pcansi:
    //      * ZOC
    //
    //  screen:
    //      * ConnectBot (Android)
    //
    //  linux:
    //      * JuiceSSH (note: TERM=linux also)
    //
    return [ 'ansi', 'pcansi', 'pc-ansi', 'ansi-bbs', 'qansi', 'scoansi', 'syncterm', 'ansi-256color', 'ansi-256color-rgb' ].includes(this.termType);
};

//  :TODO: probably need to update these to convert IAC (0xff) -> IACIAC (escape it)

ClientTerminal.prototype.write = function(s, convertLineFeeds, cb) {
    this.rawWrite(this.encode(s, convertLineFeeds), cb);
};

ClientTerminal.prototype.rawWrite = function(s, cb) {
    if(this.output && this.output.writable) {
        this.output.write(s, err => {
            if(cb) {
                return cb(err);
            }

            if(err) {
                Log.warn( { error : err.message }, 'Failed writing to socket');
            }
        });
    }
};

ClientTerminal.prototype.pipeWrite = function(s, cb) {
    this.write(renegadeToAnsi(s, this), null, cb);    //  null = use default for |convertLineFeeds|
};

ClientTerminal.prototype.encode = function(s, convertLineFeeds) {
    convertLineFeeds = _.isBoolean(convertLineFeeds) ? convertLineFeeds : this.convertLF;

    if(convertLineFeeds && _.isString(s)) {
        s = s.replace(/\n/g, '\r\n');
    }
    return iconv.encode(s, this.outputEncoding);
};


