/* globals Config, ErrorManager, debug */
'use strict';

var API = new function() {
    var protocol = Config.environment.protocol,
        host = Config.environment.host,
        apiVersion = Config.environment.apiVersion,
        client = Config.environment.client,
        clientVersion = Config.environment.clientVersion,
        timeOut = Config.environment.apiTimeout || '5000',
        authenticationCookie = null;

    function cleanReceivedData(xhr){
        return xhr && xhr.response && xhr.response.data ? xhr.response.data : null;
    }
    /**
     * Setup all the headers needed in the application for any request to the
     * server.
     * @param xhr XMLHttpRequest request object
     */
    function setRequestHeaders(xhr) {
        xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
        xhr.setRequestHeader('X-Client-Version', client + '/' + clientVersion);
        xhr.setRequestHeader('Cookie', authenticationCookie);

        // Check if we have the notifications header
        var mspToken = localStorage['X-msp-token'];
        if (!mspToken) {
            // The server will understand this value for
            // X-msp-token as the code to clean the
            // internal push tokens for this user.
            mspToken = '!';
        }
        xhr.setRequestHeader('X-msp-token', mspToken);
    }

    function makeRequest(type, path, data, callback) {

        var finalURL = protocol + '://' + host + '/control/' +
                apiVersion + '/' + path;

        var xhr = new XMLHttpRequest({mozSystem: true});

        xhr.open(type, finalURL, true);

        setRequestHeaders(xhr);

        xhr.withCredentials = true;
        xhr.responseType = 'json';

        xhr.timeout = timeOut;

        xhr.onload = function () {
            debug('RESPONSE:');
            debug('--status: ' + xhr.status);
            if (xhr.status !== 200) {
                callback(xhr.status);
                return;
            }

            var error = null;
            if (xhr.response) {
                error = xhr.response.error;
            }
            if (ErrorManager.checkError(error)) {
                callback(null, xhr);
            } else {
                callback(error, null);
            }
        };

        xhr.onerror = function (error) {
            callback(error);
        };
        xhr.ontimeout = function () {
            callback(ErrorManager.errorList.server);
        };

        debug('sending call to ' + finalURL);
        xhr.send(data);
    }

    var backgroundProcess;
    var backgroundProcessIsRunning = false;

    function setAuthCookie(cookie) {
        authenticationCookie = cookie;

        debug('API > background process established');

        if (cookie) {
            debug('background cookie: ' + cookie);
            if (!backgroundProcessIsRunning) {
                backgroundProcessIsRunning = true;
                backgroundProcess = setInterval(function () {

                    debug('Background process running: ' + backgroundProcess);
                    makeRequest('GET', 'heartBeat', null, function() {});
                // 86400000 = 24 * 60 * 60 * 1000
                }, 86400000);
            }
        }
        else {

            asyncStorage.removeItem(Proxy.KEY_AUTH_COOKIE, function() {
                debug('Clearing background process: ' + backgroundProcess);
                clearInterval(backgroundProcess);
                backgroundProcessIsRunning = false;
            });

        }
    }
    function authenticate(data, callback) {

        makeRequest('POST', 'authenticate', data,
                function(error, xhr) {
                    callback(error,
                            xhr && xhr.getResponseHeader('Set-Cookie').split(';')[0]);
                });
    }

    function getAuthDetails(id, callback) {

        makeRequest('GET', 'authDetails/' + id, null,
                function(error, xhr) {
                    callback(error, cleanReceivedData(xhr));
                });
    }

    function pairingToken(callback) {
        debug('> API > getPairingToken');

        // Check that we are logged in
        if (!authenticationCookie) {
            debug('No auth cookie stored, you need to LOG IN');
            callback(ErrorManager.errorList.authentication);
            return;
        }

        makeRequest('GET', 'pairingToken', null,
                function(error, xhr) {
                    callback(error, cleanReceivedData(xhr));
                });
    }

    function log(from, to, opId, callback) {
        debug('> API > log');

        // Check that we are logged in
        if (!authenticationCookie) {
            debug('No auth cookie stored, you need to LOG IN');
            callback(ErrorManager.errorList.authentication);
            return;
        }

        var path = 'history/'+opId+'/'+from+'/'+to;

        makeRequest('GET', path, null,
                function(error, xhr) {
                    callback(error, cleanReceivedData(xhr));
                });
    }

    function listApplications(callback) {
        debug('> API > list applications');

        // Check that we are logged in
        if (!authenticationCookie) {
            debug('No auth cookie stored, you need to LOG IN');
            callback(ErrorManager.errorList.authentication);
            return;
        }

        makeRequest('GET', 'applications', null,
                function(error, xhr) {
                    callback(error, cleanReceivedData(xhr));
                });
    }

    /**
     * Retrieves the preferences of the logged user from server
     */
    function preferences(callback) {
        debug('> API > get preferences');

        // Check that we are logged in
        if (!authenticationCookie) {
            debug('No auth cookie stored, you need to LOG IN');
            callback(ErrorManager.errorList.authentication);
            return;
        }

        var preferences = {};

        makeRequest('GET', 'appPreferences', null,
                function(error, xhr) {
                    preferences = cleanReceivedData(xhr);

                    callback(error, preferences);
                });
    }

    /**
     * Lists the sessions existing in the backend
     */
    function listSessions(callback) {
        debug('> API > list sessions');

        // Check that we are logged in
        if (!authenticationCookie) {
            debug('No auth cookie stored, you need to LOG IN');
            callback(ErrorManager.errorList.authentication);
            return;
        }

        var sessions = {};

        makeRequest('GET', 'sessions', null,
                function(error, xhr) {
                    sessions = cleanReceivedData(xhr);

                    callback(error, sessions);
                });
    }

    function closeOtherSession(sessionId, callback) {
        debug('> API > Close single session');

        // Check that we are logged in
        if (!authenticationCookie) {
            debug('No auth cookie stored, you need to LOG IN');
            callback(ErrorManager.errorList.authentication);
            return;
        }

        var endpoint = 'sessions';
        if (sessionId !== ''){
            endpoint += '/'+sessionId;
        }

        makeRequest('DELETE', endpoint, '',
                function (error) {
                    callback(error);
                });
    }

    /**
     * Stores the preferences of the logged user into server
     */
    function storePreferences(preferences, callback) {
        debug('> API > store preferences');

        // Check that we are logged in
        if (!authenticationCookie) {
            debug('No auth cookie stored, you need to LOG IN');
            callback(ErrorManager.errorList.authentication);
            return;
        }

        makeRequest('POST', 'appPreferences', "appPreferences=" + JSON.stringify(preferences),
                function(error, xhr) {
                    callback(error, cleanReceivedData(xhr));
                });
    }

    function addAppToGroup(data, callback) {
        debug('> API > addAppToGroup');

        // Check that we are logged in
        if (!authenticationCookie) {
            debug('No auth cookie stored, you need to LOG IN');
            callback(ErrorManager.errorList.authentication);
            return;
        }

        makeRequest('POST', 'group/addApps', data,
                function(error, xhr) {
                    callback(error, cleanReceivedData(xhr));
                });
    }

    function removeAppFromGroup(data, callback) {
        debug('> API > removeAppFromGroup');

        // Check that we are logged in
        if (!authenticationCookie) {
            debug('No auth cookie stored, you need to LOG IN');
            callback(ErrorManager.errorList.authentication);
            return;
        }

        makeRequest('POST', 'group/removeApps', data,
                function(error, xhr) {
                    callback(error, cleanReceivedData(xhr));
                });
    }

    function createGroup(data, callback) {
        debug('> API > create group');

        // Check that we are logged in
        if (!authenticationCookie) {
            debug('No auth cookie stored, you need to LOG IN');
            callback(ErrorManager.errorList.authentication);
            return;
        }

        makeRequest('POST', 'groups', data,
                function(error, xhr) {
                    callback(error, cleanReceivedData(xhr));
                });
    }


    function deleteGroup(groupId, callback) {
        debug('> API > delete group');

        // Check that we are logged in
        if (!authenticationCookie) {
            debug('No auth cookie stored, you need to LOG IN');
            callback(ErrorManager.errorList.authentication);
            return;
        }

        makeRequest('DELETE', 'groups/' + groupId, null,
                function(error, xhr) {
                    callback(error, cleanReceivedData(xhr));
                });
    }

    /** Change the status of the operations received as parameters
     *  @parameter data Associative array with an operation and updates for it
     *  @parameter callback Callback with server response/errors when finished
     */
    function updateStatus(data, callback) {
        debug('> API > update status with ' + data);

        // Check that we are logged in
        if (!authenticationCookie) {
            debug('No auth cookie stored, you need to LOG IN');
            callback(ErrorManager.errorList.authentication);
            return;
        }

        makeRequest('POST', 'update', data,
                function(error, xhr) {
                    callback(error, cleanReceivedData(xhr));
                });
    }

    function twoFactorToken(id, callback) {
        debug('> API > 2FactorToken with id = ' + id);

        // Check that we are logged in
        if (!authenticationCookie) {
            debug('No auth cookie stored, you need to LOG IN');
            callback(ErrorManager.errorList.authentication);
            return;
        }

        makeRequest('GET', ('twoFactorToken/' + id), null,
                function(error, xhr) {
                    callback(error, cleanReceivedData(xhr));
                });
    }

    function logout(callback) {
        debug('> API > logout');

        // Check that we are logged in
        if (!authenticationCookie) {
            callback(ErrorManager.errorList.authentication);
            return;
        }

        makeRequest('GET', 'logout', null,
                function(error, xhr) {
                    callback(error, cleanReceivedData(xhr));
                });
    }

    function resolveNotification(version, channel, callback) {
        if (typeof callback !== 'function') {
            return;
        }

        debug('> API > resolveNotification ');

        // Decide the op type based on the channel that we got the nofitication
        var opType = localStorage[channel];
        if (!opType) {
            debug('> API > resolveNotification > unkonwn channel: ' + channel);
            return;
        }

        debug('Need to resolve message ' + version +
                ' for op ' + opType + ' on channel ' + channel);

        var path = 'mspResolveVersion/' + opType + '/' + version;

        makeRequest('GET', path, null, function(error, xhr) {
            if (error || xhr === null) {
                callback(error || ErrorManager.errorList.noResponse);
                return;
            }
            callback(null, cleanReceivedData(xhr));
        });
    }

    var calls = {
        setAuthCookie: setAuthCookie,
        authenticate: authenticate,
        getAuthDetails: getAuthDetails,
        pairingToken: pairingToken,
        applications: listApplications,
        status: updateStatus,
        twoFactorToken: twoFactorToken,
        logout: logout,
        resolveNotification: resolveNotification,
        preferences: preferences,
        storePreferences: storePreferences,
        createGroup: createGroup,
        deleteGroup: deleteGroup,
        addAppToGroup: addAppToGroup,
        removeAppFromGroup: removeAppFromGroup,
        log: log,
        listSessions: listSessions,
        closeOtherSession: closeOtherSession
    };

    return calls;
};
