/**
 * app.utilB.js
 * JavaScript browser utilities
 *
 */

/*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 $, app, getComputedStyle */

app.utilB = (function () {
    'use strict';
    //---------------- BEGIN MODULE SCOPE VARIABLES --------------
    var
        configMap = {
            regex_encode_html: /[&"'><]/g,
            regex_encode_noamp: /["'><]/g,
            html_encode_map: {
                '&': '&#38;',
                '"': '&#34;',
                "'": '&#39;',
                '>': '&#62;',
                '<': '&#60;'
            }
        },

        decodeHtml, encodeHtml, getEmSize, getApiUrl, getUrlParams, formData, objectifyFormDataArray,
        getMediaSize, prepareObjectForClient, fixDatesToStrings,
        epochToShortDate, epochToLocalShortDate, epochToLocalShortDateTime, getCurrentDateTimeAsEpoch,
        genListColumn,
        genListColumnNoLink, autoComplete, prepareObjectDatesForServer,
        fixStringToServerDate;

    configMap.encode_noamp_map = $.extend({}, configMap.html_encode_map);
    delete configMap.encode_noamp_map['&'];
    //----------------- END MODULE SCOPE VARIABLES ---------------

    //------------------- BEGIN UTILITY METHODS ------------------


    // Begin decodeHtml
    // Decodes HTML entities in a browser-friendly way
    // See http://stackoverflow.com/questions/1912501/\
    //   unescape-html-entities-in-javascript
    //
    decodeHtml = function (str) {
        return $('<div/>').html(str || '').text();
    };
    // End decodeHtml


    // Begin encodeHtml
    // This is single pass encoder for html entities and handles
    // an arbitrary number of characters
    //
    encodeHtml = function (input_arg_str, exclude_amp) {
        var
            input_str = String(input_arg_str),
            regex, lookup_map;

        if (exclude_amp) {
            lookup_map = configMap.encode_noamp_map;
            regex = configMap.regex_encode_noamp;
        } else {
            lookup_map = configMap.html_encode_map;
            regex = configMap.regex_encode_html;
        }
        return input_str.replace(regex,
            function (match, name) {
                return lookup_map[match] || '';
            }
        );
    };
    // End encodeHtml

    // Begin getEmSize
    // returns size of ems in pixels
    //
    getEmSize = function (elem) {
        return Number(
            getComputedStyle(elem, '').fontSize.match(/\d*\.?\d*/)[0]
        );
    };
    // End getEmSize


    //Begin getApiUrl
    //returns url for api methods by parsing current window location url
    //
    getApiUrl = function () {
        var u = window.location.href.replace(window.location.hash, "").replace('default.htm', '') + "api/";
        //is it a dev local url?
        if (u.indexOf("localhost:8080") != -1) {
            u = u.replace("8080", "8081");
        }
        // End getApiUrl

        //fix for random recurrence of extraneous ? on iPhone when using api
        //(Cannot post to http://gl-gztw.rhcloud.com/?api/list (404))
        u = u.replace("?", "");

        return u;
    }





    // Begin formData
    // Get or set all form fields
    //
    formData = function (data) {

        //fix dates into strings
        prepareObjectForClient(data);


        var inps = $(":input").get();

        if (typeof data != "object") {
            // return all data
            data = {};

            $.each(inps, function () {
                if (this.name && (this.checked || /select|textarea/i.test(this.nodeName) || /text|hidden|password/i.test(this.type))) {
                    data[this.name] = $(this).val();
                }
            });
            return data;
        } else {
            $.each(inps, function () {
                if (this.name && data[this.name]) {
                    if (this.type == "checkbox" || this.type == "radio") {
                        $(this).prop("checked", (data[this.name]));
                    } else {
                        $(this).val(data[this.name]);
                    }
                } else if (this.type == "checkbox") {
                    $(this).prop("checked", false);
                }
            });
            return $(this);
        }
    };
    // End formdata

    // Begin getMediaSize
    // Retrieves results of css media query in hidden pseudo element
    // :after body element
    //objectifyFormDataArray
    getMediaSize = function () {
        return window.getComputedStyle(document.querySelector('body'), ':after').getPropertyValue('content').replace(/\"/g, '');
    };
    // End getMediaSize





    //Begin objectifyFormDataArray
    //takes name value form input pairs in array and turns into a keyed object
    //suitable for sending as json object
    //
    objectifyFormDataArray = function (arr) {
        var rv = {};
        for (var i = 0; i < arr.length; ++i)
            if (arr[i] !== undefined) {
                rv[arr[i].name] = arr[i].value.trim();//case 3205 added trim 
            }
        return prepareObjectDatesForServer(rv);
    }





    //Prepare an object for server needed format before submission
    //called by objectifyFormDataArray
    prepareObjectDatesForServer = function (obj) {
        if (Array.isArray(obj)) {
            for (var i = 0; i < obj.length; i++) {
                fixStringToServerDate(obj[i]);
            }
        } else {
            fixStringToServerDate(obj);
        }
        return obj;
    }
    //

    //Turn string date fields from client into server compatible format (Unix epoch like this: 1498262400 1499904000)
    fixStringToServerDate = function (obj) {
        var keys = Object.keys(obj);
        keys.forEach(function (key) {
            if (key.endsWith('Date') || key.startsWith('dt')) {
                var value = obj[key];
                if (value == null) {
                    obj[key] = '';
                } else {
                    //this is the sample format we will see: 2017-07-13    
                    //TODO: is this assuming UTC?               
                    obj[key] = moment.utc(value, "YYYY-MM-DD").unix();
                }
            }
        });
    }



    //This function exists to change the properties of the passed in object
    //to values compatible with jquery form filling functions (mostly dates to strings for now)
    //
    prepareObjectForClient = function (obj) {
        if (Array.isArray(obj)) {
            for (var i = 0; i < obj.length; i++) {
                fixDatesToStrings(obj[i]);
            }
        } else {
            fixDatesToStrings(obj);
        }
        return obj;
    }
    //

    //Turn date fields of object coming from db into stringified values for consumption by client
    //turn null dates into empty strings and iso date values into strings in iso format
    fixDatesToStrings = function (obj) {
        var keys = Object.keys(obj);
        keys.forEach(function (key) {
            if (key.endsWith('Date') || key.startsWith('dt')) {
                var value = obj[key];
                if (value == null) {
                    obj[key] = '';
                } else {
                    //Now with sqlite they come and go as unix epoch seconds
                    //needs to be yyyy-MM-dd
                    obj[key] = moment.utc(new Date(value * 1000)).format("YYYY-MM-DD");
                }
            }
        });
    }
    //

    //Turn date values coming in from server into displayable short date format
    //used to display dates in various lists (where the source epoch is already localized)
    epochToShortDate = function (epoch) {
        if (epoch == null || epoch == 0) return '';
        return moment.utc(new Date(epoch * 1000)).format("YYYY-MM-DD");
    }
    //

    //LOCAL VERSION: Turn date values coming in from server into displayable short date format
    //used to display dates in various lists where the source epoch is in UTC
    epochToLocalShortDate = function (epoch) {
        if (epoch == null || epoch == 0) return '';
        var utdate = moment.utc(new Date(epoch * 1000));
        var localdate = moment(utdate).local();
        return localdate.format("YYYY-MM-DD");
    }

    //LOCAL VERSION: Turn date values coming in from server into displayable short date AND TIME format
    //used to display dates in various lists where the source epoch is in UTC
    epochToLocalShortDateTime = function (epoch) {
        if (epoch == null || epoch == 0) return '';
        var utdate = moment.utc(new Date(epoch * 1000));
        var localdate = moment(utdate).local();
        return localdate.format("YYYY-MM-DD LT");
    }

    //////////////////////////
    //Get current date and time as a utc unix epoch
    getCurrentDateTimeAsEpoch = function () {
        return moment().utc().unix();
    }

    // Begin genListColumn
    // This function is used to demarcate 'columns' of fields in basic list forms by wrapping each column field in html
    //
    genListColumn = function (val) {
        return '<span class="rf-list-column">' + val + '</span>'
    };
    // End genListColumn

    // Begin genListColumnNoLink
    // This function is used to demarcate and style 'columns' of fields in basic list forms by wrapping each column field in html
    // that are not link columns
    genListColumnNoLink = function (val) {
        return '<span class="rf-list-column-nolink">' + val + '</span>'
    };
    // End genListColumn


    // Begin autoComplete
    // This function is used to attach an autocomplete method to an input
    //
    autoComplete = function (controlId, acGetToken) {
        $('#' + controlId).autocomplete({
            serviceUrl: app.shell.stateMap.apiUrl + 'autocomplete',
            params: {
                acget: acGetToken
            },
            ajaxSettings: {
                headers: app.api.getAuthHeaderObject()
            }
        });
    };
    // End autoComplete



    // export methods
    return {
        decodeHtml: decodeHtml,
        encodeHtml: encodeHtml,
        getEmSize: getEmSize,
        getApiUrl: getApiUrl,
        getUrlParams: getUrlParams,
        formData: formData,
        getMediaSize: getMediaSize,
        objectifyFormDataArray: objectifyFormDataArray,
        epochToShortDate: epochToShortDate,
        epochToLocalShortDate: epochToLocalShortDate,
        epochToLocalShortDateTime: epochToLocalShortDateTime,
        getCurrentDateTimeAsEpoch: getCurrentDateTimeAsEpoch,
        genListColumn: genListColumn,
        genListColumnNoLink: genListColumnNoLink,
        autoComplete: autoComplete
    };
    //------------------- END PUBLIC METHODS ---------------------
}());