/* global API, Controller, debug, Config, Proxy, PushHelper*/
'use strict';

var NotificationController = (function NotificationController() {

    // Constants
    var PUSH_CHANNEL_OTP = '101';
    var PUSH_CHANNEL_UPDATEAPPS = '102';
    var PUSH_CHANNEL_OPBLOCKED = '103';
    var PUSH_CHANNEL_OPCHANGED = '104';
    var PUSH_CHANNEL_APPPAIRED = '105';
    var PUSH_CHANNEL_APPUNPAIRED = '106';
    var PUSH_CHANNEL_OPACCESSED = '107';
    var PUSH_CHANNEL_OPDISABLED = '108';
    var PUSH_CHANNEL_OPENABLED = '109';
    var PUSH_CHANNEL_NEW_SESSION = '110';

    var rparams = /([^?=&]+)(?:=([^&]*))?/g;
    var desktopNotificationsInitialized = false;

    var isRegistered = false;

    var init = function init() {
        Proxy.init(function () {
            initPush();
            initDesktopNotifications();
        });
    };

    function initPush() {
        var pushServer = window.PushHelper;

        pushServer.debug = Config && Config.environment && Config.environment.debug;
        pushServer.listen(PUSH_CHANNEL_OTP, API.resolveNotification, onOTP);
        pushServer.listen(PUSH_CHANNEL_UPDATEAPPS, function (version, channel, callback) {
            callback();
        }, onUpdateApps);
        pushServer.listen(PUSH_CHANNEL_OPBLOCKED, API.resolveNotification, onOperationBlocked);
        pushServer.listen(PUSH_CHANNEL_OPCHANGED, API.resolveNotification, onOpChanged);
        pushServer.listen(PUSH_CHANNEL_APPPAIRED, API.resolveNotification, onAppPaired);
        pushServer.listen(PUSH_CHANNEL_APPUNPAIRED, API.resolveNotification, onAppUnpaired);
        pushServer.listen(PUSH_CHANNEL_OPACCESSED, API.resolveNotification, onOperationAccessed);
        pushServer.listen(PUSH_CHANNEL_OPDISABLED, API.resolveNotification, onOperationDisabled);
        pushServer.listen(PUSH_CHANNEL_OPENABLED, API.resolveNotification, onOperationEnabled);
        pushServer.listen(PUSH_CHANNEL_NEW_SESSION, API.resolveNotification, onNewSession);
        pushServer.register(registerNotifications);

        pushServer.init();
    }

    function getParams(input) {
        var parsed = {};
        input.replace(rparams, function ($0, $1, $2) {
            parsed[$1] = $2;
        });
        return parsed;
    }

    function initDesktopNotifications() {
        if (desktopNotificationsInitialized) {
            return;
        }
        window.navigator.mozSetMessageHandler('notification',
                function onNotification(message) {
                    debug(' > on desktop notification ' + JSON.stringify(message));
                    var action = null;
                    var opId = null;

                    var params = getParams(message.imageURL);
                    action = params.action;
                    opId = params.opId;

                    navigator.mozApps.getSelf().onsuccess = function (evt) {
                        var app = evt.target.result;

                        app.launch();
                        switch (action) {
                            case 'otp':
                                Controller.dispatchOTPNotification(opId);
                                break;
                            case 'refresh':
                                Controller.dispatchUpdatedOperations();
                                break;
                            case 'operationBlocked':
                                Controller.dispatchOperationBlocked(opId);
                                break;
                            case 'operationDisabled':
                                Controller.dispatchOperationDisabled(opId);
                                break;
                            case 'operationEnabled':
                                Controller.dispatchOperationEnabled(opId);
                                break;
                            case 'applicationPaired':
                                Controller.dispatchPairedOperation(opId);
                                break;
                            case 'applicationUnpaired':
                                Controller.dispatchUnpairedOperation(opId);
                                break;
                            case 'operationAccessed':
                                Controller.dispatchOperationAccessed(opId);
                                break;
                            case 'newSession':
                                Controller.dispatchNewSession(opId);
                                break;
                            default:
                                break;
                        }
                    };
                    // This function can be called twice, ensure that doesnt
                    // register two handlers
                    desktopNotificationsInitialized = true;
                });
    }

    function onOTP(err, data) {
        if (!!err) {
            debug(' > > ERROR onOTP: ' + JSON.stringify(err));
            ErrorManager.checkError(err);
            return;
        }
        if (data && data.id) {
            Controller.dispatchOTPNotification(data.id);
        }
    }

    function onOperationBlocked(err, data) {
        debug(' > onOperationBlocked ');
        if (!!err) {
            debug(' > > ERROR onOpBlocked: ' + JSON.stringify(err));
            ErrorManager.checkError(err);
            return;
        }
        if (data && data.id) {
            debug(' > > Operation blocked' + JSON.stringify(data));
            Controller.dispatchOperationBlocked(data.id);
        }
    }

    function onOpChanged(err, data) {
        debug(' > onOpChanged ');
        if (!!err) {
            debug(' > > ERROR onOpChanged: ' + JSON.stringify(err));
            ErrorManager.checkError(err);
            return;
        }
        if (data && data.id) {
            debug(' > > Operation changed' + JSON.stringify(data));
            Controller.dispatchOperationChanged(data.id);
        }
    }

    function onOperationAccessed(err, data) {
        debug(' > onOperationAccessed ');
        if (!!err) {
            debug(' > > ERROR onOperationAccessed: ' + JSON.stringify(err));
            ErrorManager.checkError(err);
            return;
        }
        if (data && data.id) {
            debug(' > > Operation accessed' + JSON.stringify(data));
            Controller.dispatchOperationAccessed(data.id);
        }
    }

    function onUpdateApps(err, data) {
        debug(' > onUpdateApps ');
        if (!!err) {
            debug(' > > ERROR onUpdateApps: ' + JSON.stringify(err));
            ErrorManager.checkError(err);
        } else {
            debug(' > > Operation list updated' + JSON.stringify(data));
            Controller.dispatchUpdatedOperations();
        }
    }
    function onAppPaired(err, data) {
        debug(' > onAppPaired ');
        if (!!err) {
            debug(' > > ERROR onAppPaired: ' + JSON.stringify(err));
            ErrorManager.checkError(err);
        } else {
            debug(' > > App paired' + JSON.stringify(data));
            Controller.dispatchPairedOperation(data.id);
        }
    }
    function onAppUnpaired(err, data) {
        debug(' > onAppUnpaired ');
        if (!!err) {
            debug(' > > ERROR onAppUnpaired: ' + JSON.stringify(err));
            ErrorManager.checkError(err);
        } else {
            debug(' > > App unpaired' + JSON.stringify(data));
            Controller.dispatchUnpairedOperation(data.id);
        }
    }

    function onOperationDisabled(err, data) {
        debug(' > onOperationDisabled ');
        if (!!err) {
            debug(' > > ERROR onOperationDisabled: ' + JSON.stringify(err));
            ErrorManager.checkError(err);
            return;
        }
        if (data && data.id) {
            debug(' > > Operation disabled' + JSON.stringify(data));
            Controller.dispatchOperationDisabled(data.id);
        }
    }

    function onOperationEnabled(err, data) {
        debug(' > onOperationEnabled ');
        if (!!err) {
            debug(' > > ERROR onOperationEnabled: ' + JSON.stringify(err));
            ErrorManager.checkError(err);
            return;
        }
        if (data && data.id) {
            debug(' > > Operation enabled' + JSON.stringify(data));
            Controller.dispatchOperationEnabled(data.id);
        }
    }

    function onNewSession(err, data) {
        debug(' > onNewSession ');
        if (!!err) {
            debug(' > > ERROR onNewSession: ' + JSON.stringify(err));
            ErrorManager.checkError(err);
            return;
        }

        if (data && data.id) {
            debug(' > > Dispatch new session' + JSON.stringify(data));
            Controller.dispatchNewSession(data.id);
        }
    }

    /**
     * Once we get all the 3 channels, stores them in localStorage
     * for next usage. Also save the encoded header with all the channels
     * that will be used in our request to the API
     * @param channels Object
     */
    function registerNotifications(channels) {
        if (channels) {
            debug('> How many channels? ' + channels.length);
        }
        if (!channels || channels.length !== 10) {
            debug('> dont have channels');
            /**
             * Abort generating the cookie but setup a
             * connectivity listener, check if we need to ask for
             * push urls once we have connectivity back
             */
            window.addEventListener('online', function () {
                debug('> recover connectivity asking for push urls');
                if (isRegistered) {
                    return;
                }
                PushHelper.reset();
                initPush();
            }, false);
            return;
        }
        var headerObject = {};
        try {
            headerObject[PUSH_CHANNEL_OTP] = JSON.parse(
                    localStorage[PUSH_CHANNEL_OTP]).endPoint;
            headerObject[PUSH_CHANNEL_UPDATEAPPS] = JSON.parse(
                    localStorage[PUSH_CHANNEL_UPDATEAPPS]).endPoint;
            headerObject[PUSH_CHANNEL_OPBLOCKED] = JSON.parse(
                    localStorage[PUSH_CHANNEL_OPBLOCKED]).endPoint;
            headerObject[PUSH_CHANNEL_OPCHANGED] = JSON.parse(
                    localStorage[PUSH_CHANNEL_OPCHANGED]).endPoint;
            headerObject[PUSH_CHANNEL_APPPAIRED] = JSON.parse(
                    localStorage[PUSH_CHANNEL_APPPAIRED]).endPoint;
            headerObject[PUSH_CHANNEL_APPUNPAIRED] = JSON.parse(
                    localStorage[PUSH_CHANNEL_APPUNPAIRED]).endPoint;
            headerObject[PUSH_CHANNEL_OPACCESSED] = JSON.parse(
                    localStorage[PUSH_CHANNEL_OPACCESSED]).endPoint;
            headerObject[PUSH_CHANNEL_OPDISABLED] = JSON.parse(
                    localStorage[PUSH_CHANNEL_OPDISABLED]).endPoint;
            headerObject[PUSH_CHANNEL_OPENABLED] = JSON.parse(
                    localStorage[PUSH_CHANNEL_OPENABLED]).endPoint;
            headerObject[PUSH_CHANNEL_NEW_SESSION] = JSON.parse(
                    localStorage[PUSH_CHANNEL_NEW_SESSION]).endPoint;
        } catch (e) {
            console.error('Not able to parse the push channels');
        }
        if (headerObject !== {}) {
            var mspToken = btoa(JSON.stringify(headerObject));
            localStorage['X-msp-token'] = mspToken;
            isRegistered = true;
            debug(' > register for push with ' + mspToken);
        }
    }

    function reset() {
        // Clean any values from localStorage
        delete localStorage['X-msp-token'];
        isRegistered = false;
        if (PushHelper) {
            debug(' Unregistering channels ' + JSON.stringify([
                PUSH_CHANNEL_OTP,
                PUSH_CHANNEL_OPBLOCKED,
                PUSH_CHANNEL_UPDATEAPPS,
                PUSH_CHANNEL_OPCHANGED,
                PUSH_CHANNEL_APPPAIRED,
                PUSH_CHANNEL_APPUNPAIRED,
                PUSH_CHANNEL_OPACCESSED,
                PUSH_CHANNEL_OPDISABLED,
                PUSH_CHANNEL_OPENABLED,
                PUSH_CHANNEL_NEW_SESSION
            ]));
            PushHelper.reset([
                PUSH_CHANNEL_OTP,
                PUSH_CHANNEL_OPBLOCKED,
                PUSH_CHANNEL_UPDATEAPPS,
                PUSH_CHANNEL_OPCHANGED,
                PUSH_CHANNEL_APPPAIRED,
                PUSH_CHANNEL_APPUNPAIRED,
                PUSH_CHANNEL_OPACCESSED,
                PUSH_CHANNEL_OPDISABLED,
                PUSH_CHANNEL_OPENABLED,
                PUSH_CHANNEL_NEW_SESSION
            ]);
        }
    }

    return {
        init: init,
        reset: reset,
        PUSH_CHANNEL_OTP: PUSH_CHANNEL_OTP,
        PUSH_CHANNEL_OPBLOCKED: PUSH_CHANNEL_OPBLOCKED,
        PUSH_CHANNEL_UPDATEAPPS: PUSH_CHANNEL_UPDATEAPPS,
        PUSH_CHANNEL_OPCHANGED: PUSH_CHANNEL_OPCHANGED,
        PUSH_CHANNEL_APPPAIRED: PUSH_CHANNEL_APPPAIRED,
        PUSH_CHANNEL_APPUNPAIRED: PUSH_CHANNEL_APPUNPAIRED,
        PUSH_CHANNEL_OPACCESSED: PUSH_CHANNEL_OPACCESSED,
        PUSH_CHANNEL_OPDISABLED: PUSH_CHANNEL_OPDISABLED,
        PUSH_CHANNEL_OPENABLED: PUSH_CHANNEL_OPENABLED,
        PUSH_CHANNEL_NEW_SESSION: PUSH_CHANNEL_NEW_SESSION
    };

})();

NotificationController.init();
