let Printer = function () {
    "use strict";

    let data;

    let cmd = {
        // Feed control sequences
        CTL_LF: [0x0a],						    // Print and line feed
        CTL_FF: [0x0c],						    // Form feed
        CTL_CR: [0x0d],						    // Carriage return
        CTL_HT: [0x09],						    // Horizontal tab
        CTL_VT: [0x0b],						    // Vertical tab

        // Printer hardware
        HW_INIT: [0x1b, 0x40],					// Clear data in buffer and reset modes
        HW_SELECT: [0x1b, 0x3d, 0x01],			// Printer select
        HW_RESET: [0x1b, 0x3f, 0x0a, 0x00],		// Reset printer hardware

        // Cash Drawer
        CD_KICK_2: [0x1b, 0x70, 0x00],			// Sends a pulse to pin 2 []
        CD_KICK_5: [0x1b, 0x70, 0x01],			// Sends a pulse to pin 5 []

        // Paper
        PAPER_FULL_CUT: [0x1d, 0x56, 0x00],		// Full cut paper
        PAPER_PART_CUT: [0x1d, 0x56, 0x01],		// Partial cut paper

        // Text format
        TXT_NORMAL: [0x1b, 0x21, 0x00],			// Normal text
        TXT_2HEIGHT: [0x1b, 0x21, 0x10],			// Double height text
        TXT_2WIDTH: [0x1b, 0x21, 0x20],			// Double width text
        TXT_UNDERL_OFF: [0x1b, 0x2d, 0x00],		// Underline font OFF
        TXT_UNDERL_ON: [0x1b, 0x2d, 0x01],		// Underline font 1-dot ON
        TXT_UNDERL2_ON: [0x1b, 0x2d, 0x02],		// Underline font 2-dot ON
        TXT_BOLD_OFF: [0x1b, 0x45, 0x00],		// Bold font OFF
        TXT_BOLD_ON: [0x1b, 0x45, 0x01],		// Bold font ON
        TXT_FONT_A: [0x1b, 0x4d, 0x00],			// Font type A
        TXT_FONT_B: [0x1b, 0x4d, 0x01],			// Font type B
        TXT_ALIGN_LT: [0x1b, 0x61, 0x00],		// Left justification
        TXT_ALIGN_CT: [0x1b, 0x61, 0x01],		// Centering
        TXT_ALIGN_RT: [0x1b, 0x61, 0x02],		// Right justification

        // Barcode format
        BARCODE_TXT_OFF: [0x1d, 0x48, 0x00],	// HRI barcode chars OFF
        BARCODE_TXT_ABV: [0x1d, 0x48, 0x01],	// HRI barcode chars above
        BARCODE_TXT_BLW: [0x1d, 0x48, 0x02],	// HRI barcode chars below
        BARCODE_TXT_BTH: [0x1d, 0x48, 0x03],	// HRI barcode chars both above and below
        BARCODE_FONT_A: [0x1d, 0x66, 0x00],		// Font type A for HRI barcode chars
        BARCODE_FONT_B: [0x1d, 0x66, 0x01],		// Font type B for HRI barcode chars
        BARCODE_HEIGHT: [0x1d, 0x68, 0x64],		// Barcode Height [1-255]
        BARCODE_WIDTH: [0x1d, 0x77, 0x03],		// Barcode Width  [2-6]
        BARCODE_UPC_A: [0x1d, 0x6b, 0x00],		// Barcode type UPC-A
        BARCODE_UPC_E: [0x1d, 0x6b, 0x01],		// Barcode type UPC-E
        BARCODE_EAN13: [0x1d, 0x6b, 0x02],		// Barcode type EAN13
        BARCODE_EAN8: [0x1d, 0x6b, 0x03],		// Barcode type EAN8
        BARCODE_CODE39: [0x1d, 0x6b, 0x04],		// Barcode type CODE39
        BARCODE_ITF: [0x1d, 0x6b, 0x05],		// Barcode type ITF
        BARCODE_NW7: [0x1d, 0x6b, 0x06],		// Barcode type NW7

        // Image format
        S_RASTER_N: [0x1d, 0x76, 0x30, 0x00], 	// Set raster image normal size
        S_RASTER_2W: [0x1d, 0x76, 0x30, 0x01], 	// Set raster image double width
        S_RASTER_2H: [0x1d, 0x76, 0x30, 0x02], 	// Set raster image double height
        S_RASTER_Q: [0x1d, 0x76, 0x30, 0x03]	// Set raster image quadruple
    }

    let write = function(str) {
        data = data.concat(str);
    }

    let getDefaultPrinter = function () {
        let printer_name = printer.getDefaultPrinterName();
        return printer_name;
    }

    let fontA = function () {
        write(cmd.TXT_FONT_A);
    }

    let fontB = function (n) {
        write(cmd.TXT_FONT_B);
    }

    let br = function(n) {
        if (!n) { n = 0; }

        n = parseInt(n);
        if (!n) {
            n = 1;
        }

        for (let i=0; i<n; i++) {
            write(cmd.CTL_LF);
        }
    }

    let underline = function() {
        write(cmd.TXT_UNDERL_ON);
    }

    let underline2 = function() {
        write(cmd.TXT_UNDERL2_ON);
    }

    let underlineOff = function() {
        write(cmd.TXT_UNDERL_OFF);
    }

    let emphasizedOff = function() {
        write(cmd.TXT_NORMAL);
    }

    let center = function() {
        write(cmd.TXT_ALIGN_CT);
    }

    let left = function() {
        write(cmd.TXT_ALIGN_LT);
    }

    let right = function() {
        write(cmd.TXT_ALIGN_RT);
    }

    let bold = function() {
        write(cmd.TXT_BOLD_ON);
    }

    let boldOff = function() {
        write(cmd.TXT_BOLD_OFF);
    }

    let print = function() {
        write(cmd.PAPER_FULL_CUT);
        let defp = getDefaultPrinter();

        printer.printDirect({
            data: new Buffer(data),
            printer:defp,//'RONGTA RP80 Printer',
            type: 'RAW',
            success:function(jobID) {
                console.log("sent to printer with ID: "+jobID);
            },
            error:function(err) {                console.log(err);
            }
        });
    }

    /**
     * @param BARCONTENT: Barcode
     * @param BARTYPE: 65: UPC-A 66: UPC-B  67: EAN-13 68: EAN-8 69: Code39 70: Interleaved 2of5  71: Codabar 72: Code-39 73: Code-128 74: UCC/Ean-128
     * @param BARWIDTH: range 2 to 6
     * @param BARHEIGHT: INTEGER range 1 to 255 (dots)
     * @param HRIFONT: 0 for Printerfont A, 1 for Printerfont B
     * @param HRIPOSITION: INTEGER 0: not printed , 1: above Code, 2: below Code, 3 above and below
     */
    let barcode = function(BARCONTENT, BARTYPE, BARWIDTH, BARHEIGHT, HRIFONT, HRIPOSITION) {

        let parametercommands = new Buffer(12);

        //barcode Height
        parametercommands[0] = '0x1D';
        parametercommands[1] = '0x68';
        parametercommands[2] = BARHEIGHT;

        // barcode width
        parametercommands[3] = '0x1D';
        parametercommands[4] = '0x77';
        parametercommands[5] = BARWIDTH;

        //Human readable charcters size
        parametercommands[6] = '0x1D';
        parametercommands[7] = '0x66';
        parametercommands[8] = HRIFONT;

        // human readable position
        parametercommands[9] = '0x1D';
        parametercommands[10] = '0x48';
        parametercommands[11] = HRIPOSITION;

        let printcommand = new Buffer(4);
        printcommand[0] = '0x1D';
        printcommand[1] = '0x6B';

        //codetyp
        printcommand[2] = BARTYPE;
        printcommand[3] = BARCONTENT.length;

        let output = parametercommands.toString('utf8') + printcommand.toString('utf8') + BARCONTENT+String.fromCharCode(10);

        center();
        write(output.toBytes());
    }

    /**
     * @param QRDATA
     * @param QRMODEL: 49: Model 1 , 50: Model 2 , 51: Micro QR
     * @param QRSIZE: 1 - 16 depends on Printer up to which size this will work default in ESCPOS is 3
     * @param QRERRORC: 48: 7%, 49: 15% , 50: 25%, 51: 30%
     */
    let qrcode = function(QRDATA, QRMODEL, QRSIZE, QRERRORC) {
        let output = "";
        let store_len = QRDATA.length + 3;
        let sizebytes = new Buffer(2);
        sizebytes[0] = store_len % 256;
        sizebytes[1] = store_len / 256;

        // QR Code: Select the model
        //let QRMODEL = new Buffer([0x1d, 0x28, 0x6b, 0x04, 0x00, 0x31, 0x41, 0x32, 0x00])
        let modelQR = new Buffer('1d286b04003141'+("00"+QRMODEL.toString(16)).slice(-2)+'00','hex');

        // QR Code: Set the size of module
        let sizeQR = new Buffer('1d286b03003143'+("00"+QRSIZE.toString(16)).slice(-2),'hex');

        // QR Code: Set the errorcorrection level    //          Hex     1D      28      6B      03      00      31      45      n
        let errorQR = new Buffer('1d286b03003145'+("00"+QRERRORC.toString(16)).slice(-2),'hex');

        // QR Code: Store the data in the symbol storage area
        // needed to do this in three parts to include the appropriate two bites with the length information
        let storeQR1 = new Buffer('1d286b','hex');
        let storeQR2 = new Buffer('315030','hex');
        let storeQR = storeQR1.toString('ascii')+sizebytes.toString('ascii')+storeQR2.toString('ascii');

        // QR Code: Print the symbol data in the symbol storage area
        let printQR = new Buffer('1d286b0300315130','hex');

        output = output + modelQR.toString('utf8');
        output = output + sizeQR.toString('utf8');
        output = output + errorQR.toString('utf8');
        output = output + storeQR;
        //output = output + ESCPOS_QRDATA;
        output = output + new Buffer(QRDATA,'binary').toString('utf8');
        output = output + printQR.toString('utf8');
        //output = output + String.fromCharCode(10);

        write(output.toBytes());
    }

    return {
        init: function () {
            this.reset();
        },

        reset: function () {
            data = cmd.TXT_FONT_A;
        },

        write: function (str) {
            write(str.toBytes());
            return this;
        },

        line: function (str) {
            write(str.toBytes());
            br();
        },

        br: br,
        fontA: fontA,
        fontB: fontB,
        underline: underline,
        underline2: underline2,
        underlineOff: underlineOff,
        emphasized: function() {
            write(cmd.TXT_2HEIGHT);
            //write(cmd.TXT_2WIDTH);
        },
        emphasizedOff: emphasizedOff,
        center: center,
        left: left,
        right: right,
        bold: bold,
        boldOff: boldOff,
        barcode: barcode,
        qrcode: qrcode,
        print: print
    }
}();