/*
 * app.api.js
 * Ajax api helper module
 */

/*jslint         browser : true, continue : true,
  devel  : true, indent  : 2,    maxerr   : 50,
  newcap : true, nomen   : true, plusplus : true,
  regexp : true, sloppy  : true, vars     : false,
  white  : true
*/
/*global $, io, app */

app.api = (function () {
    'use strict';
    var
        initModule, getAuthHeaderObject,
        GZAppVersion, 
        get, remove, create, update, uploadFile,
        doSync, getListFromStore, putListInStore,
        goToNextList, getActiveList, replaceActiveList, renameActiveList, toggleDeleteActiveList,
        getActiveListIndex, replaceRecordInStore, insertRecordInStore, getRecordFromStore,
        getListItemCoordinates, setActiveListId, getActiveListId, newList
        ;


    GZAppVersion = "1.4";
   



    //////////////////////////////////////////////////////////////////////////////////////
    //         NOT AUTHORIZED ERROR HANDLER


    $(document).ajaxError(function (event, jqxhr, settings, thrownError) {
        //unauthorized?  Trigger logout which will trigger login after clearing creds
        if (jqxhr.status == 401) {
            window.location.replace('#!/logout');
        }
    });

    //////////////////////////////////////////////////////////////////////////////////////
    //         UTILITY

    ///////////////////////////////////////////////////////////
    // Return the auth token header 
    //
    //
    getAuthHeaderObject = function () {
        return {
            "Authorization": "Bearer " + app.shell.stateMap.user.token
        };
    }


    ///////////////////////////////////////////////////////////
    // Fetch the list from local storage
    //
    //
    getListFromStore = function () {
        return store.get('pecklist.list');
    }

    ///////////////////////////////////////////////////////////
    // Replace the list in local store
    //
    //
    putListInStore = function (theList) {
        store.set('pecklist.list', theList);
    }

    ///////////////////////////////////////////////////////////
    // Get the active list id or first if active not found
    //
    getActiveListId = function (theId) {
        var ret = store.get('pecklist.activeListId');

        //validate it's ok
        var l = app.api.getListFromStore();
        var firstListId = l[0].id;//get a default in case it's not found

        var len = l.length, i = 0;
        for (i; i < len; i++) {
            if (l[i].id == ret) {
                return ret;
            }
        }

        //if we're here then it's not a valid id so use the first one instead and set it
        store.set('pecklist.activeListId', firstListId);
        return firstListId;

    }

    ///////////////////////////////////////////////////////////
    // Set the active list id
    // 
    //
    setActiveListId = function (theId) {
        if (theId) {
            store.set('pecklist.activeListId', theId);
        }
    }


    ///////////////////////////////////////////////////////////
    // ADVANCE ACTIVE LIST ID TO NEXT LIST
    // 
    //
    goToNextList = function () {
        var l = getListFromStore();
        var allLength = l.length;
        //is there more than one list?
        if (allLength < 2) {
            //Nope
            return;
        }

        //figure out what the next list id should be
        var currentIndex = getActiveListIndex();
        var highestPossibleIndex = allLength - 1;

        //are we already at the last list?
        if (currentIndex == highestPossibleIndex) {
            //go to first list (wrap)
            setActiveListId(l[0].id);
            return;
        }

        //advance to the next list
        setActiveListId(l[currentIndex + 1].id);
        return;
    }



    //////////////////////////////
    // GET LIST INDEX
    //
    getActiveListIndex = function () {
        var activeListId = getActiveListId();
        var l = app.api.getListFromStore();
        var len = l.length, i = 0;
        for (i; i < len; i++) {
            if (l[i].id == activeListId) {
                return i;
            }
        }
        //This should never happen, if it does something is very wrong:
        throw new Error("Error: app.main.js::getActiveListIndex - active list ID not found in list store");
    }

    ///////////////////////////
    // GET ACTIVE LIST
    //
    getActiveList = function () {
        var activeListId = getActiveListId();
        var l = app.api.getListFromStore();
        var len = l.length, i = 0;
        for (i; i < len; i++) {
            if (l[i].id == activeListId) {
                return l[i];
            }
        }
        //This should never happen, if it does something is very wrong:
        throw new Error("Error: app.main.js::getActiveList - activeListId not found in list store");
    }


    ///////////////////////////
    // CREATE NEW LIST
    //
    newList = function () {
       
        var l = app.api.getListFromStore();
        var newListRecord={
            id:"NEW_"+ _.now(),
            name: "New list "+Date(),
            v:1,
            name_v:1,
            items:[]
        }

        l.push(newListRecord);
        app.api.putListInStore(l);
        setActiveListId(newListRecord.id);        
    }




    ///////////////////////////
    // RENAME ACTIVE LIST
    //
    renameActiveList = function (newName) {
        var activeListId = getActiveListId();
        var l = app.api.getListFromStore();
        var len = l.length, i = 0;
        for (i; i < len; i++) {
            if (l[i].id == activeListId) {
                l[i].name = newName;
                putListInStore(l);
                return;
            }
        }
        //This should never happen, if it does something is very wrong:
        throw new Error("Error: app.main.js::renameActiveList - activeListId not found in list store");
    }


    ///////////////////////////
    // DELETE ACTIVE LIST
    //
    toggleDeleteActiveList = function () {
        var activeListId = getActiveListId();
        var l = app.api.getListFromStore();
        var len = l.length, i = 0;
        for (i; i < len; i++) {
            if (l[i].id == activeListId) {
                if (l[i].deleted) {
                    delete l[i].deleted;
                } else {
                    l[i].deleted = true;//tag it as deleted
                }
                putListInStore(l);
                return;
            }
        }
        //This should never happen, if it does something is very wrong:
        throw new Error("Error: app.main.js::toggleDeleteActiveList - activeListId not found in list store");
    }


    ///////////////////////////
    // REPLACE ACTIVE LIST
    //
    replaceActiveList = function (replacementList) {
        var activeListId = getActiveListId();
        var l = app.api.getListFromStore();
        var len = l.length, i = 0;
        for (i; i < len; i++) {
            if (l[i].id == activeListId) {
                l[i] = replacementList;
                putListInStore(l);
                return;
            }
        }
        //This should never happen, if it does something is very wrong:
        throw new Error("Error: app.main.js::replaceActiveList - activeListId not found in list store");
    }


    //////////////////////////////
    // GET LIST ITEM CO-ORDINATES
    //
    getListItemCoordinates = function (itemId) {
        var allLists = app.api.getListFromStore();
        var allLength = allLists.length, j = 0;
        for (j; j < allLength; j++) {
            //iterate the list and find it
            var len = allLists[j].items.length, i = 0;
            for (i; i < len; i++) {
                if (allLists[j].items[i].id == itemId) {
                    return { listIndex: j, itemIndex: i };
                }
            }
        }
        //This should never happen, if it does something is very wrong:
        throw new Error("Error: app.main.js::getListItemCoordinates - List item ID not found in list store");
    }



    ///////////////////////////
    // GET RECORD FROM STORE
    //
    getRecordFromStore = function (itemId) {
        var co = getListItemCoordinates(itemId);
        var allLists = app.api.getListFromStore();
        return allLists[co.listIndex].items[co.itemIndex];
    }





    ///////////////////////////
    // REPLACE RECORD IN STORE
    //
    replaceRecordInStore = function (itemId, replacementRecord) {
        var co = getListItemCoordinates(itemId);
        var l = app.api.getListFromStore();
        //Todo: is this the proper way to do it?
        l[co.listIndex].items[co.itemIndex] = replacementRecord;
        app.api.putListInStore(l);
    }


    ///////////////////////////
    // INSERT RECORD IN STORE
    //
    insertRecordInStore = function (newRecord) {
        var activeListIndex = getActiveListIndex();
        var l = app.api.getListFromStore();
        l[activeListIndex].items.push(newRecord);
        app.api.putListInStore(l);
    }




    //////////////////////////////////////////////////////////////////////////////////////
    //        PECKLIST SPECIFIC ROUTES
    //////////////////////////////////////////////////////////////////////////////////////


    ///////////////////////////////////////////////////////////
    // 
    //     DOSYNC - Synchronize the stored data
    //
    doSync = function (callback) {
        //get the list from the store
        var theList = getListFromStore();

        $.ajax({
            method: "post",
            dataType: "json",
            url: app.shell.stateMap.apiUrl + 'sync',
            headers: getAuthHeaderObject(),
            contentType: 'application/json; charset=utf-8',
            data: JSON.stringify(theList),
            success: function (ret, textStatus) {
                //Put the new list in the store
                putListInStore(JSON.parse(ret));
                callback({ ok: 1 });
            },
            error: function (jqXHR, textStatus, errorThrown) {
                callback({
                    error: 1,
                    msg: textStatus + '\n' + errorThrown,
                    error_detail: {}
                });
            }
        });
    }




    ////////////////////////////////////////////////////////////////////////////////////////////////////////
    //      STANDARD API CORE ROUTES
    //
    ////////////////////////////////////////////////////////////////////////////////////////////////////////


    ///////////////////////////////////////////////////////////
    //Create
    //Route app.post('/api/:obj_type/create', function (req, res) {
    //
    create = function (apiRoute, objData, callback) {
        $.ajax({
            method: "post",
            dataType: "json",
            url: app.shell.stateMap.apiUrl + apiRoute,
            headers: getAuthHeaderObject(),
            contentType: 'application/json; charset=utf-8',
            data: JSON.stringify(objData),
            success: function (data, textStatus) {
                callback(data);
            },
            error: function (jqXHR, textStatus, errorThrown) {
                callback({
                    error: 1,
                    msg: textStatus + '\n' + errorThrown,
                    error_detail: {}
                });
            }
        });
    }

    /////////////////
    //Get - get anything, the caller provides the route, this should replace most legacy get
    //
    get = function (apiRoute, callback) {
        $.ajax({
            method: "GET",
            dataType: "json",
            url: app.shell.stateMap.apiUrl + apiRoute,
            headers: getAuthHeaderObject(),

            success: function (data, textStatus) {
                callback(data);
            },
            error: function (jqXHR, textStatus, errorThrown) {
                callback({
                    error: 1,
                    msg: textStatus + '\n' + errorThrown,
                    error_detail: {}
                });
            }
        });
    }
    ////////////////////

    ///////////////////////////////////////////////////////////
    //Update
    //route: app.post('/api/:obj_type/update/:id', function (req, res) {
    //
    update = function (objType, objData, callback) {
        var theId;
        if (!objData.id) {
            return callback({
                error: 1,
                msg: 'app.api.js::update->Error: missing id field in update document',
                error_detail: objData
            });
        }
        theId = objData.id;
        $.ajax({
            method: "put",
            dataType: "json",
            url: app.shell.stateMap.apiUrl + objType + '/' + theId,
            headers: getAuthHeaderObject(),
            contentType: 'application/json; charset=utf-8',
            data: JSON.stringify(objData),
            success: function (data, textStatus) {
                if (data == null) {
                    data = { ok: 1 };
                }

                callback(data);
            },
            error: function (jqXHR, textStatus, errorThrown) {
                callback({
                    error: 1,
                    msg: textStatus + '\n' + errorThrown,
                    error_detail: {}
                });
            }
        });
    }



    ///////////////////////////////////////////////////////////
    //remove Item    
    remove = function (apiRoute, callback) {
        $.ajax({
            method: "DELETE",
            dataType: "json",
            url: app.shell.stateMap.apiUrl + apiRoute,
            headers: getAuthHeaderObject(),
            success: function (data, textStatus) {
                callback(data);
            },
            error: function (jqXHR, textStatus, errorThrown) {
                callback({
                    error: 1,
                    msg: textStatus + '\n' + errorThrown,
                    error_detail: {}
                });
            }
        });
    }



    ///////////////////////////////////////////////////////////
    // uploadFile
    // (ajax route to upload a file)
    //
    uploadFile = function (apiRoute, objData, callback) {
        $.ajax({
            method: "post",
            dataType: "json",
            url: app.shell.stateMap.apiUrl + apiRoute,
            headers: getAuthHeaderObject(),
            contentType: false,
            processData: false,
            data: objData,
            success: function (data, textStatus) {
                callback(data);
            },
            error: function (jqXHR, textStatus, errorThrown) {
                callback({
                    error: 1,
                    msg: textStatus + '\n' + errorThrown,
                    error_detail: {}
                });
            }
        });
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////





    initModule = function () { };

    return {
        initModule: initModule,
        getAuthHeaderObject: getAuthHeaderObject,
        GZAppVersion: GZAppVersion,
        get: get,
        remove: remove,
        create: create,
        update: update,
        uploadFile: uploadFile,
        doSync: doSync,
        getListFromStore: getListFromStore,
        putListInStore: putListInStore,
        goToNextList: goToNextList,
        getActiveList: getActiveList,
        replaceActiveList: replaceActiveList,
        getActiveListIndex: getActiveListIndex,
        replaceRecordInStore: replaceRecordInStore,
        insertRecordInStore: insertRecordInStore,
        getRecordFromStore: getRecordFromStore,
        getListItemCoordinates: getListItemCoordinates,
        renameActiveList: renameActiveList,
        toggleDeleteActiveList: toggleDeleteActiveList,
        newList: newList


    };
}());