/*
Copyright 2018 - 2019 Intel Corporation

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

function heciRedirector()
{
    this.redirect = function redirect(options)
    {
        options.protocol = 'ws:';
        options.method = 'GET';
        options.path = '/heciRedirect'
        var heciRedirect =
            {
                ObjectID: 'heci.heciRedirect',
                create: function create()
                {
                    console.log('Heci Redirection: Create()');
                    var stream = require('stream');
                    var retVal = new stream.Duplex({
                        read: function read()
                        {
                            console.log('read');
                        },
                        write: function write(chunk, callback)
                        {
                            console.log('received chunk of ' + chunk.length + ' bytes');
                            this.request._WS.WriteDrains.push(callback);
                            this.request._WS.write(chunk, function onWriteFlushed() { this.WriteDrains.shift().apply(this, []);});
                        },
                        final: function final()
                        {
                        }
                    });

                    retVal._ObjectID = 'heci.redirectedSession';
                    retVal.GUIDS = this.GUIDS;
                    retVal.options = this.options;
                    retVal.parent = this;
                    retVal.request = require('http').request(this.options);
                    console.log('HECI Redirection Client', this.options);
                    var utils = require('events').inherits(retVal);
                    utils.createEvent('connect');
                    utils.createEvent('error');

                    retVal.request.redirector = retVal;
                    retVal.request.on('upgrade', function onclientUpgrade(resp, sck, head)
                    {
                        console.log('Heci Redirection Tunnel established');
                        this._WS = sck;
                        this._WS.redirector = this.redirector;
                        this._WS.WriteDrains = [];
                        sck.on('data', function onClientRedirectData(chunk)
                        {
                            if (typeof chunk == 'string')
                            {
                                var cmd = JSON.parse(chunk);
                                switch(cmd.Command)
                                {
                                    case 'Event':
                                        console.log('emitting [' + cmd.Name + ']');
                                        this.redirector.emit(cmd.Name, cmd.Data);
                                        console.log('done emitting');
                                        break;
                                }
                            }
                            else
                            {
                                if (chunk.length > 0)
                                {
                                    console.log('pushing');
                                    if(!this.redirector.push(chunk))
                                    {
                                        this.pause();
                                    }
                                }
                            }
                        });
                        if (this.redirector.connectcmd)
                        {
                            console.log('writing connect command');
                            this._WS.write(JSON.stringify(this.redirector.connectcmd));
                        }
                    });
                    retVal.request.on('error', function onRequestError(e) { console.log('Could not connect HECI tunnel', e); });
                    utils.addMethod('connect', function _connect(target, options)
                    {
                        // This method needs to be added using utils, because it needs to be added as a defproperty, due to the event of the same name
                        console.log('HECI Redirection Client: Connect');
                        var cmd = { Command: 'Connect', Data: { Service: target, Options: options } };
                        if (!this._WS) { this.connectcmd = cmd; }
                        else
                        {
                            this._WS.write(JSON.stringify(cmd));
                        }
                    });
                    retVal.disconnect = function disconnect()
                    {
                        console.log('disconnecting');
                        this.request._WS.end();
                        delete this.request._WS;
                        this.request._WS = null;
                    };
                    retVal.request.end();
                    return (retVal);
                },
                GUIDS: { LME: 'LME', AMT: 'AMT' },
                options: options
            };
        addModuleObject('heci', heciRedirect);
    };
    this.listen = function listen(options)
    {
        console.log('Starting Heci Redirection Server on port: ' + options.port);
        this._server = require('http').createServer();
        this._server.redirector = this;
        this._server.options = options;
        this._server.listen(options);
        this._server.on('upgrade', function onUpgrade(req, sck, head)
        {
            this.redirector.WS = sck.upgradeWebSocket();
            this.redirector.WS.redirector = this.redirector;
            console.log('Heci Redirection Tunnel Established');
            this.redirector.WS.on('data', function onRedirectorServerData(chunk)
            {
                if(typeof chunk == 'string')
                {
                    var cmd = JSON.parse(chunk);
                    switch(cmd.Command)
                    {
                        default:
                            console.log('Unknown Command: ' + cmd.Command);
                            delete this.redirector.WS;
                            this.end();
                            break;
                        case 'Connect':
                            console.log("'Connect' received'");
                            this.heci = require('heci').create();
                            this.heci.WS = this;
                            this.heci.WS.redirector = this;
                            switch(cmd.Data.Service)
                            {
                                case 'AMT':
                                    console.log('Connecting to PTHI Service');
                                    this.heci.connect(require('heci').GUIDS.AMT, cmd.Data.Options);
                                    break;
                                case 'LME':
                                    console.log('Connecting to LME Service')
                                    this.heci.connect(require('heci').GUIDS.LME, cmd.Data.Options);
                                    break;
                                default:
                                    console.log('Invalid Service Request: ' + cmd.Data.Service);
                                    delete this.redirector.WS;
                                    this.end();
                                    break;
                            }
                            this.heci.once('error', function onHeciError(e) { console.log('HECI Error: ', e); delete this.redirector.WS; this.end(JSON.stringify({ Command: 'Event', Name: 'error', Data: e.toString() })); });
                            this.heci.on('connect', function onHeciConnect()
                            {
                                console.log('HECI Service Connection Established');
                                this.WS.write(JSON.stringify({ Command: 'Event', Name: 'connect' }));
                                this.pipe(this.WS).pipe(this, { end: false });
                                this.WS.on('end', function wsEndSink() { console.log('HECI Session Closed'); this.redirector.end(); });
                            });
                            break;
                    }
                }
            });
        });
    };
}

module.exports = new heciRedirector();