/**
 * JIO Local Storage. Type = 'local'.
 * Local browser "database" storage.
 */
var newLocalStorage = function (spec, my) {

    spec = spec || {};
    var that = my.basicStorage(spec, my),
        priv = {},

        /*
        * Wrapper for the localStorage used to simplify instion of any kind of
        * values
        */
        localstorage = {
            getItem: function (item) {
                return JSON.parse(localStorage.getItem(item));
            },
            setItem: function (item, value) {
                return localStorage.setItem(item, JSON.stringify(value));
            },
            deleteItem: function (item) {
                delete localStorage[item];
            }
        },
        storage_user_array_name,
        storage_file_array_name;

    // attributes
    priv.username = spec.username || '';
    priv.applicationname = spec.applicationname || 'untitled';

    storage_user_array_name = 'jio/local_user_array';
    storage_file_array_name = 'jio/local_file_name_array/' +
        priv.username + '/' + priv.applicationname;

    /**
     * Returns a list of users.
     * @method getUserArray
     * @return {array} The list of users.
     */
    priv.getUserArray = function () {
        return localstorage.getItem(storage_user_array_name) || [];
    };

    /**
     * Adds a user to the user list.
     * @method addUser
     * @param  {string} user_name The user name.
     */
    priv.addUser = function (user_name) {
        var user_array = priv.getUserArray();
        user_array.push(user_name);
        localstorage.setItem(storage_user_array_name, user_array);
    };

    /**
     * checks if a user exists in the user array.
     * @method doesUserExist
     * @param  {string} user_name The user name
     * @return {boolean} true if exist, else false
     */
    priv.doesUserExist = function (user_name) {
        var user_array = priv.getUserArray(), i, l;
        for (i = 0, l = user_array.length; i < l; i += 1) {
            if (user_array[i] === user_name) {
                return true;
            }
        }
        return false;
    };

    /**
     * Returns the file names of all existing files owned by the user.
     * @method getFileNameArray
     * @return {array} All the existing file paths.
     */
    priv.getFileNameArray = function () {
        return localstorage.getItem(storage_file_array_name) || [];
    };

    /**
     * Adds a file name to the local file name array.
     * @method addFileName
     * @param  {string} file_name The new file name.
     */
    priv.addFileName = function (file_name) {
        var file_name_array = priv.getFileNameArray();
        file_name_array.push(file_name);
        localstorage.setItem(storage_file_array_name, file_name_array);
    };

    /**
     * Removes a file name from the local file name array.
     * @method removeFileName
     * @param  {string} file_name The file name to remove.
     */
    priv.removeFileName = function (file_name) {
        var i, l, array = priv.getFileNameArray(), new_array = [];
        for (i = 0, l = array.length; i < l; i+= 1) {
            if (array[i] !== file_name) {
                new_array.push(array[i]);
            }
        }
        localstorage.setItem(storage_file_array_name, new_array);
    };

    /**
     * Extends [obj] adding 0 to 3 values according to [command] options.
     * @method manageOptions
     * @param  {object} obj The obj to extend
     * @param  {object} command The JIO command
     * @param  {object} doc The document object
     */
    priv.manageOptions = function (obj, command, doc) {
        obj = obj || {};
        if (command.getOption('revs')) {
            obj.revisions = doc._revisions;
        }
        if (command.getOption('revs_info')) {
            obj.revs_info = doc._revs_info;
        }
        if (command.getOption('conflicts')) {
            obj.conflicts = {total_rows:0, rows:[]};
        }
        return obj;
    };

    /**
     * Update [doc] the document object and remove [doc] keys
     * which are not in [new_doc]. It only changes [doc] keys not starting
     * with an underscore.
     * ex: doc:     {key:value1,_key:value2} with
     *     new_doc: {key:value3,_key:value4} updates
     *     doc:     {key:value3,_key:value2}.
     * @param  {object} doc The original document object.
     * @param  {object} new_doc The new document object
     */
    priv.documentObjectUpdate = function (doc, new_doc) {
        var k;
        for (k in doc) {
            if (k[0] !== '_') {
                delete doc[k];
            }
        }
        for (k in new_doc) {
            if (k[0] !== '_') {
                doc[k] = new_doc[k];
            }
        }
    };

    /**
     * Create a new document
     * @method setDocument
     * @param  {object} command Command object
     * @param  {string} trigger Put/Post
     */
    priv.setDocument = function (command, trigger) {
        var doc = command.getDoc(),
            document_id = doc._id,
            document_rev = doc._rev,
            document_path = 'jio/local/'+priv.username+'/'+
                    priv.applicationname+'/'+document_id+
                    '/'+document_rev;

        if (trigger === 'put'){
            priv.documentObjectUpdate(doc, command.cloneDoc());
        }

        localstorage.setItem(document_path, doc);

        if (trigger === 'post'){
            if (!priv.doesUserExist(priv.username)) {
                priv.addUser(priv.username);
            }
            priv.addFileName(document_id);
        }

        return priv.manageOptions(
            {ok:true,id:document_id,rev:document_rev}, command, doc);
    };

    /**
     * get a document or attachment
     * @method getDocument
     * @param  {object} command Command object
     */
    priv.getDocument = function (command) {
        var doc = command.getDoc();
            document_id = doc._id;
            document_rev = doc._rev;
            document_path = 'jio/local/'+priv.username+'/'+
                    priv.applicationname+'/'+document_id+
                    '/'+document_rev;

        localStorage.getItem( document_path );

        return priv.manageOptions(
            {ok:true,id:document_id,rev:document_rev}, command, doc);
    };

    /**
     * delete a document or attachment
     * @method getDocument
     * @param  {object} command Command object
     */
    priv.deleteDocument = function (command) {
        var doc = command.getDoc();
            document_id = doc._id;
            document_rev = doc._rev;
            document_path = 'jio/local/'+priv.username+'/'+
                    priv.applicationname+'/'+document_id+
                    '/'+document_rev;

        localStorage.deleteItem( document_path );

        return priv.manageOptions(
            {ok:true,id:document_id,rev:document_rev}, command, doc);
    };

    // ===================== overrides ======================
    that.serialized = function () {
        return {
            "applicationname": priv.applicationname,
            "username": priv.username
        };
    };

    that.validateState = function() {
        if (priv.username) {
            return '';
        }
        return 'Need at least one parameter: "username".';
    };

    /**
     * Create a document in local storage.
     * @method  _post
     * @param  {object} command The JIO command
     *
     * Available options:
     * - {boolean} conflicts Add a conflicts object to the response
     * - {boolean} revs Add the revisions history of the document
     * - {boolean} revs_info Add revisions informations
     *
     */
    that._post = function (command) {
        setTimeout (function () {
            that.success(priv.setDocument(command,'post'));
        });
    };

    /**
     * Create or update a document in local storage.
     * @method  _put
     * @param  {object} command The JIO command
     *
     * Available options:
     * - {boolean} conflicts Add a conflicts object to the response
     * - {boolean} revs Add the revisions history of the document
     * - {boolean} revs_info Add revisions informations
     *
     */
    that._put = function (command) {
        setTimeout(function () {
            var docid = command.getDocId(),
                path = 'jio/local/'+priv.username+'/'+
                        priv.applicationname+'/'+docid,
                doc = localstorage.getItem(path);

            if (!doc) {
                that.success(priv.setDocument(command, 'post'));
            } else {
                that.success(priv.documentUpdate(command, 'put'));
            }
        });
    };

    /**
     * Add an attachment to a document
     * @method  _putAttachment
     * @param  {object} command The JIO command
     *
     * Available options:
     * - {boolean} conflicts Add a conflicts object to the response
     * - {boolean} revs Add the revisions history of the document
     * - {boolean} revs_info Add revisions informations
     */
    that._putAttachment = function (command) {
        setTimeout(function () {
            that.success(priv.setDocument(command, 'put');
        });
    };

    /**
     * Get a document or attachment
     * @method  get
     * @param  {object} command The JIO command
     *
     * Available options:
     * - {boolean} conflicts Add a conflicts object to the response
     * - {boolean} revs Add the revisions history of the document
     * - {boolean} revs_info Add revisions informations
     */
    that._get = function (command) {
        setTimeout (function () {
            that.success( priv.getDocument(command) );
        });

    };

    /**
     * Remove a document or attachment
     * @method  remove
     * @param  {object} command The JIO command
     *
     * Available options:
     * - {boolean} conflicts Add a conflicts object to the response
     * - {boolean} revs Add the revisions history of the document
     * - {boolean} revs_info Add revisions informations
     */
    that._remove = function (command) {
        setTimeout (function () {
            that.success( priv.deleteDocument(command) );
        });
    };

    /**
     * get all filenames belonging to a user from the document index
     * @method  allDocs
     * @param  {object} command The JIO command
     *
     * Available options:
     * - {boolean} conflicts Add a conflicts object to the response
     * - {boolean} revs Add the revisions history of the document
     * - {boolean} revs_info Add revisions informations
     * - {boolean} include_docs Include documents with index
     */
    that._allDocs = function (command) {
        setTimeout(function () {
            var new_array = [],
                array = priv.getFileNameArray(),
                i,l,
                path = 'jio/local/'+priv.username+'/'+priv.applicationname,
                include_docs = command.getOption('include_docs'),
                doc, item;

            for (i = 0, l = array.length; i < l; i += 1) {
                item = array[i];

                if (include_docs === true){
                    doc = that._get(path+'/'+item.id+'/'+item.value.key );
                    new_array.push({
                        "id":item.id,
                        "key":item.key,
                        "value":item.value,
                        "doc":doc
                    });
                } else {
                    new_array.push({
                        "id":item.id,
                        "key":item.key,
                        "value":item.value
                    });
                }
            }
            that.success ({total_rows:new_array.length,rows:new_array});
        });
    };

    return that;
};
jIO.addStorageType('local', newLocalStorage);