const type = require('../../core').type;
const EventEmitter = require('events').EventEmitter;
const caps = require('./caps');
const log = require('../../core').log;
const data = require('./data');



/**
 * Cliprdr channel for all clipboard
 * capabilities exchange
 */
class Cliprdr extends EventEmitter {

    constructor(transport) {
        super();
        this.transport = transport;
        // must be init via connect event
        this.userId = 0;
        this.serverCapabilities = [];
        this.clientCapabilities = [];
    }

}


/**
 * Client side of Cliprdr channel automata
 * @param transport
 */
class Client extends Cliprdr {

    constructor(transport, fastPathTransport) {

        super(transport, fastPathTransport);

        this.transport.once('connect', (gccCore, userId, channelId) => {
            this.connect(gccCore, userId, channelId);
        }).on('close', function () {
            //this.emit('close');
        }).on('error', function (err) {
            //this.emit('error', err);
        });

        this.content = '';

    }

    /**
     * connect function
     * @param gccCore {type.Component(clientCoreData)}
     */
    connect(gccCore, userId, channelId) {
        this.gccCore = gccCore;
        this.userId = userId;
        this.channelId = channelId;
        this.transport.once('cliprdr', (s) => {
            this.recv(s);
        });
    }


    send(message) {
        this.transport.send('cliprdr', new type.Component([
            // Channel PDU Header
            new type.UInt32Le(message.size()),
            // CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST | CHANNEL_FLAG_SHOW_PROTOCOL
            new type.UInt32Le(0x13),
            message
        ]));
    };

    recv(s) {
        s.offset = 18;
        const pdu = data.clipPDU().read(s), type = data.ClipPDUMsgType;

        switch (pdu.obj.header.obj.msgType.value) {
            case type.CB_MONITOR_READY:
                this.recvMonitorReadyPDU(s);
                break;
            case type.CB_FORMAT_LIST:
                this.recvFormatListPDU(s);
                break;
            case type.CB_FORMAT_LIST_RESPONSE:
                this.recvFormatListResponsePDU(s);
                break;
            case type.CB_FORMAT_DATA_REQUEST:
                this.recvFormatDataRequestPDU(s);
                break;
            case type.CB_FORMAT_DATA_RESPONSE:
                this.recvFormatDataResponsePDU(s);
                break;
            case type.CB_TEMP_DIRECTORY:
                break;
            case type.CB_CLIP_CAPS:
                this.recvClipboardCapsPDU(s);
                break;
            case type.CB_FILECONTENTS_REQUEST:
        }

        this.transport.once('cliprdr', (s) => {
            this.recv(s);
        });
    }

    /**
     * Receive capabilities from server
     * @param s {type.Stream}
     */
    recvClipboardCapsPDU(s) {
        // Start at 18
        s.offset = 18;
        // const pdu = data.clipPDU().read(s);
        // console.log('recvClipboardCapsPDU', s);
    }


    /**
     * Receive monitor ready from server
     * @param s {type.Stream}
     */
    recvMonitorReadyPDU(s) {
        s.offset = 18;
        // const pdu = data.clipPDU().read(s);
        // console.log('recvMonitorReadyPDU', s);

        this.sendClipboardCapsPDU();
        // this.sendClientTemporaryDirectoryPDU();
        this.sendFormatListPDU();
    }


    /**
     * Send clipboard capabilities PDU
     */
    sendClipboardCapsPDU() {
        this.send(new type.Component({
            msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_CLIP_CAPS),
            msgFlags: new type.UInt16Le(0x00),
            dataLen: new type.UInt32Le(0x10),
            cCapabilitiesSets: new type.UInt16Le(0x01),
            pad1: new type.UInt16Le(0x00),
            capabilitySetType: new type.UInt16Le(0x01),
            lengthCapability: new type.UInt16Le(0x0c),
            version: new type.UInt32Le(0x02),
            capabilityFlags: new type.UInt32Le(0x02)
        }));
    }


    /**
     * Send client temporary directory PDU
     */
    sendClientTemporaryDirectoryPDU(path = '') {
        // TODO
        this.send(new type.Component({
            msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_TEMP_DIRECTORY),
            msgFlags: new type.UInt16Le(0x00),
            dataLen: new type.UInt32Le(0x0208),
            wszTempDir: new type.BinaryString(Buffer.from('D:\\Vectors' + Array(251).join('\x00'), 'ucs2'), { readLength: new type.CallableValue(520) })
        }));
    }


    /**
     * Send format list PDU
     */
    sendFormatListPDU() {
        this.send(new type.Component({
            msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_FORMAT_LIST),
            msgFlags: new type.UInt16Le(0x00),

            dataLen: new type.UInt32Le(0x24),

            formatId6: new type.UInt32Le(0xc004),
            formatName6: new type.BinaryString(Buffer.from('Native\x00', 'ucs2'), { readLength: new type.CallableValue(14) }),

            formatId8: new type.UInt32Le(0x0d),
            formatName8: new type.UInt16Le(0x00),

            formatId9: new type.UInt32Le(0x10),
            formatName9: new type.UInt16Le(0x00),

            formatId0: new type.UInt32Le(0x01),
            formatName0: new type.UInt16Le(0x00),

            // dataLen: new type.UInt32Le(0xe0),

            // formatId1: new type.UInt32Le(0xc08a),
            // formatName1: new type.BinaryString(Buffer.from('Rich Text Format\x00' , 'ucs2'), { readLength : new type.CallableValue(34)}),

            // formatId2: new type.UInt32Le(0xc145),
            // formatName2: new type.BinaryString(Buffer.from('Rich Text Format Without Objects\x00' , 'ucs2'), { readLength : new type.CallableValue(66)}),

            // formatId3: new type.UInt32Le(0xc143),
            // formatName3: new type.BinaryString(Buffer.from('RTF As Text\x00' , 'ucs2'), { readLength : new type.CallableValue(24)}),

            // formatId4: new type.UInt32Le(0x01),
            // formatName4: new type.BinaryString(0x00),

            formatId5: new type.UInt32Le(0x07),
            formatName5: new type.UInt16Le(0x00),

            // formatId6: new type.UInt32Le(0xc004),
            // formatName6: new type.BinaryString(Buffer.from('Native\x00' , 'ucs2'), { readLength : new type.CallableValue(14)}),

            // formatId7: new type.UInt32Le(0xc00e),
            // formatName7: new type.BinaryString(Buffer.from('Object Descriptor\x00' , 'ucs2'), { readLength : new type.CallableValue(36)}),

            // formatId8: new type.UInt32Le(0x03),
            // formatName8: new type.UInt16Le(0x00),

            // formatId9: new type.UInt32Le(0x10),
            // formatName9: new type.UInt16Le(0x00),

            // formatId0: new type.UInt32Le(0x07),
            // formatName0: new type.UInt16Le(0x00),
        }));

    }

    /**
     * Recvie format list PDU from server
     * @param {type.Stream} s 
     */
    recvFormatListPDU(s) {
        s.offset = 18;
        // const pdu = data.clipPDU().read(s);
        // console.log('recvFormatListPDU', s);
        this.sendFormatListResponsePDU();
    }


    /**
     * Send format list reesponse
     */
    sendFormatListResponsePDU() {
        this.send(new type.Component({
            msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_FORMAT_LIST_RESPONSE),
            msgFlags: new type.UInt16Le(0x01),
            dataLen: new type.UInt32Le(0x00),
        }));

        this.sendFormatDataRequestPDU();
    }


    /**
     * Receive format list response from server
     * @param s {type.Stream}
     */
    recvFormatListResponsePDU(s) {
        s.offset = 18;
        // const pdu = data.clipPDU().read(s);
        // console.log('recvFormatListResponsePDU', s);
        // this.sendFormatDataRequestPDU();
    }


    /**
     * Send format data request PDU
     */
    sendFormatDataRequestPDU(formartId = 0x0d) {
        this.send(new type.Component({
            msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_FORMAT_DATA_REQUEST),
            msgFlags: new type.UInt16Le(0x00),
            dataLen: new type.UInt32Le(0x04),
            requestedFormatId: new type.UInt32Le(formartId),
        }));
    }


    /**
     * Receive format data request PDU from server
     * @param s {type.Stream}
     */
    recvFormatDataRequestPDU(s) {
        s.offset = 18;
        // const pdu = data.clipPDU().read(s);
        // console.log('recvFormatDataRequestPDU', s);
        this.sendFormatDataResponsePDU();
    }


    /**
     * Send format data reesponse PDU
     */
    sendFormatDataResponsePDU() {

        const bufs = Buffer.from(this.content + '\x00', 'ucs2');

        this.send(new type.Component({
            msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_FORMAT_DATA_RESPONSE),
            msgFlags: new type.UInt16Le(0x01),
            dataLen: new type.UInt32Le(bufs.length),
            requestedFormatData: new type.BinaryString(bufs, { readLength: new type.CallableValue(bufs.length) })
        }));

    }


    /**
     * Receive format data response PDU from server
     * @param s {type.Stream}
     */
    recvFormatDataResponsePDU(s) {
        s.offset = 18;
        // const pdu = data.clipPDU().read(s);
        const str = s.buffer.toString('ucs2', 26, s.buffer.length - 2);
        // console.log('recvFormatDataResponsePDU', str);
        this.content = str;
        this.emit('clipboard', str)
    }


    // =====================================================================================
    setClipboardData(content) {
        this.content = content;
        this.sendFormatListPDU();
    }

}


module.exports = {
    Client
}