var OU = OU || {};

OU.saver = (function() {
    var online = VLE.serverversion;
    var local = (typeof Storage !== 'undefined');
    var activityId = '';
    var itemId = '';
    var courseId = '';
    var saveMsg = document.getElementById('save-msg') || null;

    /**
     * @param {object} cfg
     * @param {object} cfg.names
     * @param {boolean} [cfg.id]
     * @param {boolean} [cfg.user]
     * @param {boolean} [cfg.local] fallback to localStorage, default is false
     * @param {function} [cfg.callback]
     */
    var retrieve = function(cfg) {
        cfg.user = (cfg.user !== false); //true unless == false
        cfg.local = (cfg.local === true);

        if (cfg.id) {
            activityId = cfg.id;
        }

        if (typeof cfg.callback != 'function') {
            cfg.callback = function() {};
        }

        if (online) {
            retrieveDataFromVLE(cfg);
        }
        else {
            if (local && cfg.local) {
                retrieveDataFromLocalStorage(cfg);
            }
            else {
                cfg.callback({});
            }
        }
    };

    var retrieveDataFromVLE = function(cfg) {
        var ok = function(data) {
            var out = decode(data);
            cfg.callback(out, data);
            console.log('Retrieved ' + ((cfg.user) ? 'user' : 'group') + ' data: ', out);
        };
        var error = function(msg) {
            if (msg !== null) {
                console.log(msg);
            }

            cfg.callback({});
            console.log('get_server_data has failed.');
        };
        var p, names = [];

        for (p in cfg.names) {
            if (cfg.names.hasOwnProperty(p)) {
                names.push(p);
            }
        }

        console.log('Data to be retrieved: ' + names);
        VLE.get_server_data(cfg.user, names, ok, error, activityId, itemId, courseId);
    };

    var retrieveDataFromLocalStorage = function(cfg) {
        var outObj = {};
        var item, p;

        for (p in cfg.names) {
            if (cfg.names.hasOwnProperty(p)) {
                item = localStorage.getItem(activityId + p);
                outObj[p] = (item === null) ? '' : item;
            }
        }

        outObj = decode(outObj);
        cfg.callback(outObj);
        console.log('Retrieved ' + (cfg.user ? 'user' : 'group') + ' data: ', outObj);
    };

    /**
     * @param {object} cfg
     * @param {object} cfg.values
     * @param {object} [cfg.id]
     * @param {object} [cfg.previous]
     * @param {boolean} [cfg.user]
     * @param {boolean} [cfg.local] fallback to localStorage, default is false
     * @param {function} [cfg.retry]
     * @param {function} [cfg.callback]
     */
    var save = function(cfg) {
        var saveObj = encode(cfg.values);

        cfg.user = (cfg.user !== false); //true unless == false
        cfg.local = (cfg.local === true);

        if (cfg.id) {
            activityId = cfg.id;
        }

        if (typeof cfg.callback != 'function') {
            cfg.callback = function() {};
        }

        if (saveMsg !== null) {
            fadeSaveMsg();
        }

        console.log((cfg.user ? 'User' : 'Group') + ' data to be saved: ', cfg.values);

        if (online) {
            saveDataToVLE(saveObj, cfg);
        }
        else { /* don't use local storage unless offline */
            if (local && cfg.local) {
                saveToLocalStorage(saveObj, cfg);
            }
            else {
                cfg.callback(false);

                if (saveMsg) {
                    saveMsg.textContent = 'cannot save offline';
                }
            }
        }
    };

    var saveDataToVLE = function(saveObj, cfg) {
        var user = (cfg.user !== false);
        var ok = function() {
            cfg.callback(true);
            console.log('set_server_data (' + (user ? 'user' : 'group') + ') was successful');
        };
        var error = function(msg) {
            if (msg !== null) {
                console.log(msg);
            }
            cfg.callback(false);
            console.log('set_server_data has failed');
        };
        var previousValues = cfg.previous;
        var retry = function(obj) {
            cfg.retry(obj);
            console.log('Retry data: ', obj);
        };

        VLE.set_server_data(user, saveObj, ok, error, previousValues, retry, activityId, itemId, courseId);
    };

    var saveToLocalStorage = function(saveObj, cfg) {
        //TODO alert message on first save - Any data saved in this context will only be available later on this device. Continue?
        for (var p in saveObj) {
            if (saveObj.hasOwnProperty(p)) {
                localStorage.setItem(activityId + p, saveObj[p]);
            }
        }

        cfg.callback(true);
    };

    var fadeSaveMsg = function() {
        var opacity = 0;
        var fadeIn, fadeOut;

        fadeIn = (function fadeIn() {
            saveMsg.style.opacity = (opacity += (1/30));
            if (opacity < 1) {
                requestAnimationFrame(fadeIn.bind(this));
            }
            else {
                setInterval(fadeOut, 500);
            }
        }.bind(this))();

        fadeOut = function fadeOut() {
            saveMsg.style.opacity = (opacity -= (1/30));
            if (opacity > 0) {
                requestAnimationFrame(fadeOut.bind(this));
            }
        }.bind(this);
    };

    var makeIdFromOrigin = function() {
        var theId = '';
        var theOrigin, i;

        /*
         takes the alpha-numeric characters from the origin and pathname and uses
         them to make an 'activity id' which should be safe for use with the VLE
         */
        if (!window.location.origin) { /* i.e. IE */
            window.location.origin = window.location.protocol + "//" +  window.location.hostname + (window.location.port ? ':' + window.location.port : '');
        }

        theOrigin = window.location.origin + window.location.pathname;

        for (i = 0; i < theOrigin.length; i++) {
            if (theOrigin.charCodeAt(i) > 96 && theOrigin.charCodeAt(i) < 123) {
                theId += theOrigin.charAt(i);
            }
        }
        for (i = 0; i < theOrigin.length; i++) {
            if (theOrigin.charCodeAt(i) > 64 && theOrigin.charCodeAt(i) < 91) {
                theId += theOrigin.charAt(i);
            }
        }
        for (i = 0; i < theOrigin.length; i++) {
            if (theOrigin.charCodeAt(i) > 47 && theOrigin.charCodeAt(i) < 58) {
                theId += theOrigin.charAt(i);
            }
        }

        // since this id is only to be used for local storage it can be more than 20 characters
        return theId;
    };

    var encode = function(obj) {
        var encoded = {};

        for (var p in obj) {
            if (obj.hasOwnProperty(p)) {
                encoded[p] = encodeURIComponent(obj[p]);
            }
        }

        return encoded;
    };

    var decode = function(obj) {
        var decoded = {};

        for (var p in obj) {
            if (obj.hasOwnProperty(p)) {
                decoded[p] = decodeURIComponent(obj[p]);
            }
        }

        return decoded;
    };

    if (online) {
        activityId = VLE.get_param('activityId') || VLE.get_param('_a');
        itemId = VLE.get_param('documentId') || VLE.get_param('_i');
        courseId = VLE.get_param('courseId') || VLE.get_param('_c');
    }
    else {
        activityId = makeIdFromOrigin();
    }

    return {
        retrieve: retrieve,
        save: save
    };
})();