if(!window.infoaxe) window.infoaxe = {};

window.infoaxe.Util = function(jQueryAlias) {
    this._jQ = jQueryAlias || $ || $j;

    var subDomain = window.location.host.split('.')[0];
    this.logFile = this.LOG_FILES[subDomain];
};

window.infoaxe.Util.prototype = {
    LOG_FILES : {
        'feedshare': 'flip_log.jsp',
        'login': 'log.jsp'
    },

    setJQueryAlias: function(alias) {
        this._jQ = alias;
    },

    isEmpty: function(s) {
        return ((s == null) || (s.length == 0));
    },

    trim: function(s) {
        return s.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
    },

    ellipsify: function(s, maxLen) {
        if(s.length <= maxLen) return s;
        return s.substring(0, maxLen - 4) + "...";
    },

    getHash: function() {
        //@TODO: is document.location.hash not standard?
        var ind = document.location.href.indexOf('#');
        if (ind != -1) {
            return document.location.href.substring(ind + 1);
        }
        return null;
    },

    enablePopup: function() {
        this._popupDisabled = false;
    },

    disablePopup: function() {
        this._popupDisabled = true;
    },

    isPopupDisabled: function() {
        return this._popupDisabled;
    },

    redirect: function(loc, force) {
        if(!force && !this.isPopupDisabled()) return;

        this.disablePopup();
        window.location.href = loc;
    },

    log: function(msg) {
        if(window.console && window.console.log !== undefined) {
            window.console.log(msg);
        }
    },

    logError: function(msg) {
        if(window.console && window.console.log !== undefined) {
            window.console.error(msg);
        }
    },

    logEvent: function(data, redirectURL) {
        if(typeof data != "object") {
            data = {event: data}
        }

        var self = this;
        var cb = function() {
            if (redirectURL) {
                self.disablePopup();
                window.location.href = redirectURL;
            }
        }

        this._jQ.ajax({
            url: this.logFile,
            data: data,
            error: cb,
            success: cb
        });

    },

    isChrome: function() {
        try {
            return navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
        }
        catch (e) {
            return false;
        }
    },

    getURLParameter: function(paramName, url) {
        if(url === undefined) {
            url =  window.location.href;
        }

        paramName = paramName.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
        var regexS = "[\\?&]"+paramName+"=([^&#]*)";
        var regex = new RegExp( regexS );
        var results = regex.exec(url);

        var rv = null;
        if(results != null)
            rv = results[1];

        return window.infoaxe.Util.prototype.decodeURLParam(rv);
    },

    decodeURLParam: function(paramVal) {
        if(paramVal === null) return null;
        return unescape(paramVal.replace(/\+/g, " "));
    },

    getParamFragment: function(url) {
        if(url === undefined) {
            url = window.location.href;
        }

        var ind = url.indexOf("?");
        var urlParams = "";
        if (ind != -1 && ind != url.length - 1) {
            urlParams = url.substring(ind + 1);
        }

        return urlParams;
    },

    unparam: function(value) {
        //inverse of jQuery.param
        //source:http://stackoverflow.com/questions/1131630/javascript-jquery-param-inverse-function
        var
        // Object that holds names => values.
        params = {},
        // Get query string pieces (separated by &)
        pieces = value.split('&'),
        // Temporary variables used in loop.
        pair, i, l;

        // Loop through query string pieces and assign params.
        for (i = 0, l = pieces.length; i < l; i++) {
            pair = pieces[i].split('=', 2);
            // Repeated parameters with the same name are overwritten. Parameters
            // with no value get set to boolean true.
            params[decodeURIComponent(pair[0])] = (pair.length == 2 ?
                decodeURIComponent(pair[1].replace(/\+/g, ' ')) : true);
        }

        return params;
    },

    isEmptyObject: function(o) {
        for(var prop in o) {
            if(o.hasOwnProperty(prop)) return false;
        }
        return true;
    },

    isEmpty: function(str) {
        return (!str || /^\s*$/.test(str));
    },

    isValidEmail: function(email) {
        /*http://stackoverflow.com/questions/46155/validate-email-address-in-javascript*/
        var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
        return email.match(re) != null;
    },

    formToData: function(form) {
        form = this._jQ(form);
        var fields = form.find('input[name], select');
        var data = {};

        var self = this;
        this._jQ.each(fields, function(i, field){
            field = self._jQ(field);
            var name = field.attr("name");
            if(name) {
                data[name] = field.val();
            }
        });
        return data;
    },

    submitForm: function(form, onSuccess, onError, timeout) {
        var data = this.formToData(form);

        return this._jQ.ajax({
            type: form.attr("method") || "POST",
            url: form.attr("action"),
            data: data,
            dataType: 'json',
            timeout: timeout,
            error: function(xhr, textStatus, error) {
                if(onError) {
                    onError(xhr, textStatus, error);
                }
            },
            success: function(data, textStatus, xhr) {
                if(window.console) {
                    window.console.log(data);
                }
                if(onSuccess) {
                    onSuccess(data, textStatus, xhr);
                }
            }
        });
    },

    printf: function(tmpl, args) {
        for (var key in args) {
            var pattern = "\\{" + key + "\\}";
            var re = new RegExp(pattern, "g");
            tmpl = tmpl.replace(re, args[key]);
        }
        return tmpl;
    },

    utcToLocalTime: function(utcMilli) {
        var offset = new Date().getTimezoneOffset() * 60 * 1000;
        utcMilli -= offset;
        return new Date(utcMilli).getTime();
    },

    chunkifyArray: function chunkifyArray(array, maxChunkLen) {
        if(!maxChunkLen) throw "maxChunkLen must be a positive integer";

        var rv = [];
        while(array.length) {
            rv.push(array.splice(0, maxChunkLen));
        }
        return rv;
    },

    preloadImages: function(imgSrcArray) {
        var self = this;
        this._jQ(document).ready(function(){
            self._jQ(imgSrcArray).each(function(){
                self._jQ('<img/>')[0].src = this;

            });
        });
    },

    setOuterWidth: function(elem, width) {
        var extra = elem.outerWidth(true) - elem.width();
        elem.css('width', width - extra);
    },

    jsonStringify: function(obj) {
        http://stackoverflow.com/questions/3593046/jquery-json-to-string
        if(typeof JSON !== 'undefined' && typeof JSON.stringify !== 'undefined') return JSON.stringify(obj);

        var t = typeof (obj);
        if (t != "object" || obj === null) {
            // simple data type
            if (t == "string") obj = '"'+obj+'"';
            return String(obj);
        }
        else {
            // recurse array or object
            var n, v, json = [], arr = (obj && obj.constructor == Array);
            for (n in obj) {
                v = obj[n];
                t = typeof(v);
                if (t == "string") v = '"'+v+'"';
                else if (t == "object" && v !== null) v = this.jsonStringify(v);
                json.push((arr ? "" : '"' + n + '":') + String(v));
            }
            return (arr ? "[" : "{") + String(json) + (arr ? "]" : "}");
        }
    },

    addParametersToURL: function(url, paramsObj) {
        //make sure that the query is added before # and after ?

        var params = this._jQ.param(paramsObj);

        var hashIndex = url.lastIndexOf('#');
        var questionIndex = url.indexOf('?');

        var hash = "";
        if(hashIndex > 0) {
            hash = url.substring(hashIndex);
            url = url.substring(0, hashIndex)
        }

        if(questionIndex < 0) {
            url += '?' + params;
        }
        else {
            if(questionIndex == url.length - 1) {
                //url ends with a ?
                url += params;
            }
            else {
                url += '&' + params;
            }
        }

        return url + hash;

    },

    cookie: function (key, value, options) {
        /**
         * jQuery Cookie plugin
         *
         * Copyright (c) 2010 Klaus Hartl (stilbuero.de)
         * Dual licensed under the MIT and GPL licenses:
         * http://www.opensource.org/licenses/mit-license.php
         * http://www.gnu.org/licenses/gpl.html
         *
         */

        // key and at least value given, set cookie...
        if (arguments.length > 1 && String(value) !== "[object Object]") {
            options = jQuery.extend({}, options);

            if (value === null || value === undefined) {
                options.expires = -1;
            }

            if (typeof options.expires === 'number') {
                var days = options.expires, t = options.expires = new Date();
                t.setDate(t.getDate() + days);
            }

            value = String(value);

            return (document.cookie = [
                encodeURIComponent(key), '=',
                options.raw ? value : encodeURIComponent(value),
                options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
                options.path ? '; path=' + options.path : '',
                options.domain ? '; domain=' + options.domain : '',
                options.secure ? '; secure' : ''
            ].join(''));
        }

        // key and possibly options given, get cookie...
        options = value || {};
        var result, decode = options.raw ? function (s) {
            return s;
        } : decodeURIComponent;
        return (result = new RegExp('(?:^|; )' + encodeURIComponent(key) + '=([^;]*)').exec(document.cookie)) ? decode(result[1]) : null;
    },

    wasModalPopupOpen: function(callback) {
        var DELTA = 100;
        var ERROR_WINDOW = 100;

        var self = this;

        var beforeTime = new Date().getTime();
        setTimeout(function(){
            var afterTime = new Date().getTime();
            var delta = afterTime - beforeTime;

            //self.log(delta + " " + DELTA + " " + ERROR_WINDOW);

            var firedTooLate = delta - DELTA >= ERROR_WINDOW;

            //if(firedTooLate) self.log("fired too late");

            callback(firedTooLate);
        }, DELTA);
    },

    waitForModalPopup: function(callback) {
        var POLL_INTERVAL = 25;

        var self = this;
        self.wasModalPopupOpen(function(wasOpen){
            if(wasOpen) {
                callback();
            }
            else {
                setTimeout(function(){
                    self.waitForModalPopup(callback);
                }, POLL_INTERVAL);
            }
        });

    }
};


/**
 * Usage example:
 * var signinFormValidator = {
 *   'signin_email': {
 *       'is_email': {
 *           'value': true,
 *           'message': 'please enter a valid email'
 *       }
 *   },
 *
 *   'signin_password': {
 *       'min_length': {
 *           'value': 6,
 *           'message': function(length){
 *               if(length == 0) {
 *                   return "please enter a password";
 *               }
 *               if(length < 6) {
 *                   return "password should be longer than 6";
 *               }
 *
 *               return null;
 *           }
 *       }
 *    }
 * }
 *
 * signinForm = new window.infoaxe.Form($j, 'signin_form_form', {
 *   invalidInputParentClass: 'invalid_input_background',
 *   invalidInputClass: 'invalid_input',
 *   labelledClass: 'hint_label',
 *   validators: signinFormValidator
 * });
 *
 * working example: login.infoaxe.com/login.jsp
 *
 */

window.infoaxe.Form = function(jQueryAlias, formId, options) {
    this._jQ = jQueryAlias || $ || $j;
    this.options = options;

    this._fields = null;

    var self = this;
    this._jQ(document).ready(function(){
        self._form = self._jQ('#' + formId);
        self._fields = self._form.find('input[type="text"], input[type="password"]');
        self.__init__();

        if(self.options.onInit) {
            self.options.onInit();
        }
    });

};

window.infoaxe.Form.prototype = {
    __init__: function() {

        var self = this;
        this._fields.each(function() {
            // need to strip newlines because the browser strips them
            // if you set textbox.value to a string containing them
            self._jQ(this).data("label", (self._jQ(this).attr('title') || "").replace(/\n/g,''));
            self._jQ(this).data("isInvalid", false);

            self._jQ(this).focus(function(){
                self._onFocus(self._jQ(this));
            }).blur(function(){
                self._onBlur(self._jQ(this));
            });

            /*if (this.value !== this.defaultValue) {
                // user already started typing; don't overwrite their work!
                return;
            }*/

            // actually set the value
            this.value = self._jQ(this).data("label");

            self._jQ(this).addClass(self.options.labelledClass);

            if(self._jQ(this).attr('type') === "password") {
                var real = self._jQ(this);
                var id = real.attr('id');
                var placeholder = self._jQ('#' + id + '_placeholder');

                setInterval(function(){
                    if(real.val().length > 0 && !real.is(":visible")) {
                        placeholder.hide();
                        real.show();
                    }
                },  self.options.hiddenPasswordPollInterval || 500);
            }
        });

        /*this._fields.keypress(function(e) {
            if(e.which == 13) {
                self._jQ(this).blur();
                self._form.find('input[type="button"], input[type="submit"]').focus().click();
                e.preventDefault();
            }
        });*/

        self._form.submit(self.removeValuesOnExit);
        self._jQ(window).unload(function(){
            self.removeValuesOnExit();
        });
        self._jQ(window).unload(function(){
            self._form[0].reset();
        });//self.removeValuesOnExit
    },

    _onFocus: function(evtSrc) {
        var self = this;

        if(evtSrc.attr('type') === "password") return;

        var id = evtSrc.attr('id');

        var isPlaceholder =  id.match(/(.+)_placeholder$/);
        if(isPlaceholder) {
            var real = this._form.find('#' + isPlaceholder[1]);
            var val = real.val();

            evtSrc.data('font-size', evtSrc.css('font-size')).animate({'font-size': 1}, 100, function() {
                evtSrc.val('').hide();
                real.val('').show().animate({'font-size': evtSrc.data('font-size')}, 100, function(){
                    real.focus();
                });
            });

            real.data('isInvalid', false);

        }
        else {
            var val = evtSrc.val();
            if (val === evtSrc.data("label") || evtSrc.data('isInvalid') === true) {

                evtSrc.data('font-size', evtSrc.css('font-size')).animate({'font-size': 1}, 100, function(){

                    evtSrc.css('filter', undefined);

                    if(evtSrc.data('isInvalid') === true) {
                        evtSrc.val(evtSrc.data('invalidValue'));
                    }
                    else {
                        evtSrc.val(this.defaultValue);
                    }

                    evtSrc.animate({'font-size': evtSrc.data('font-size')}, 100, function(){
                        evtSrc.css('filter', undefined);

                        if(self.options.invalidInputParentClass) {
                            evtSrc.parent().removeClass(self.options.invalidInputParentClass);
                        }
                        if(self.options.invalidInputClass) {
                            evtSrc.removeClass(self.options.invalidInputClass);
                        }
                        if(self.options.labelledClass) {
                            evtSrc.removeClass(self.options.labelledClass);
                        }

                        //XXX: this is a hack, we want the font-size to increase
                        //and not get restored to the error state font size
                        evtSrc.css('font-size', '');
                        //evtSrc.focus();
                    });

                    evtSrc.data('isInvalid', false);
                });
            }
        }
    },

    _onBlur: function(evtSrc){
        var id = evtSrc.attr('id');
        var val = evtSrc.val();

        //ignore hide/blur of placeholder text

        if(id.match(/_placeholder$/)) return;

        var valid = this._validateField(evtSrc);

        /*var hasDefaultVal = evtSrc[0].value === evtSrc[0].defaultValue;

        var textField = evtSrc;

        if(validationError || hasDefaultVal) {
            if(evtSrc.attr('type') === "password") {
                evtSrc.val('').hide();
                textField = this._form.find('#' + id + '_placeholder');
            }

            textField.fadeOut(0);
            textField.show();
            textField.val(validationError || textField.data("label"));
            textField.fadeIn(400);
        }

        if(validationError) {
            textField.data('isInvalid', true);
            //val is the old value, text field has already been filled with a new
            //value
            textField.data('invalidValue', val);
            textField.parent().addClass(this.options.invalidInputParentClass);
            textField.addClass(this.options.invalidInputClass);
        }
        else if (hasDefaultVal) {
            textField.addClass(this.options.labelledClass);
        }*/

    },

    removeValuesOnExit : function() {
        var self = this;

        this._fields.each(function(){
            if (this.value === self._jQ(this).data("label") || self._jQ(this).data('isInvalid') === true) {
                this.value = this.defaultValue;
                if(self.options.labelledClass) {
                    self._jQ(this).removeClass(self.options.labelledClass);
                }
            }
        })
    },

    _setFieldError: function(field, value) {
        var self = this;

        var isPassword = field.attr("type") === "password";

        var textField = field;
        if(isPassword) {
            var id = field.attr('id');
            textField = this._form.find('#' + id + '_placeholder');

            //for actual password input field, save it's current font size,
            //reduce font-size to 0, hide it and show the placeholder
            field.data('font-size', field.css('font-size')).animate({'font-size': 1}, 100, function(){
                field.val('').hide();
                textField.show();
            });
        }

        textField.data('font-size', textField.css('font-size')).animate({
            'font-size': 1
        }, 100, function(){
            textField.val(value);
            textField.animate({'font-size': textField.data('font-size')}, 100, function(){
                if(self.options.invalidInputParentClass) {
                    textField.parent().addClass(self.options.invalidInputParentClass);
                }
                if(self.options.invalidInputClass) {
                    textField.addClass(self.options.invalidInputClass);
                }
            });
        });

    },

    _validateField: function(field){
        var self = this;
        if(field.data("isInvalid")) return false;

        var id = field.attr('id');
        var validators = this.options.validators && this.options.validators[id];
        if(!validators) {
            if(!field.val()) {
                field.data('font-size', field.css('font-size')).animate({
                    'font-size': 1
                }, 100, function(){
                    field.addClass(self.options.labelledClass);
                    field.val(field.data("label"));
                    field.animate({
                        'font-size': field.data('font-size')
                    }, 100);
                });
            }

            return true;
        }

        if(field.val() === field.data("label")) {
            field.val("");
        }
        var val = window.infoaxe.Util.prototype.trim(field.val());

        var errorMessage = null;


        for(var condition in validators) {
            var validator = validators[condition];
            if(condition === "min_length") {
                var minLength = validator.value;

                if(val.length < minLength) {
                    errorMessage = validator.message;
                    if(typeof validator.message == "function") {
                        errorMessage = validator.message(val.length);
                    }
                }
            }
            else if(condition === "is_email") {
                if(validator.value) {
                    if(!window.infoaxe.util.isValidEmail(val)) {
                        errorMessage = validator.message;
                        if(typeof validator.message == "function") {
                            errorMessage = validator.message(val.length);
                        }
                    }
                }
            }

            if(errorMessage) break;
        }

        if(errorMessage) {
            field.data("isInvalid", true);
            field.data("invalidValue", field.val());

            this._setFieldError(field, errorMessage);

        }
        else {
            field.data("isInvalid", false);
            field.data("invalidValue", undefined);

            if(this.options.invalidInputParentClass) {
                field.parent().removeClass(this.options.invalidInputParentClass);
            }
            if(this.options.invalidInputClass) {
                field.removeClass(this.options.invalidInputClass);
            }
        }

        return !errorMessage;
    },

    validateForm: function() {
        var self = this;

        var validated = true;
        this._fields.each(function(){
            var field = self._jQ(this);
            /*if(field.data("isInvalid")) {
                validated = false;
                return;
            }*/
            validated = validated && self._validateField(field);
        });

        return validated;
    },
    
    setFieldValue: function(fieldId, newValue) {
    	if (newValue) {
    		var field = this._jQ("#"+fieldId);
            field.val(newValue);
            if (this.options.labelledClass) {
                field.removeClass(this.options.labelledClass);
            }
        }
    },

    setOptions: function(options) {
        this.options = options;
    },

    _hideShowField: function(field, whileCallback, afterCallback) {
        field.data('font-size', field.css('font-size')).animate({
            'font-size': 1
        }, 100, function(){

            if(whileCallback) whileCallback(field);

            field.animate({
                'font-size': field.css('font-size')
            }, 100, function(){

                if(afterCallback) afterCallback(field);

            });
        });
    }
};



//init a singleton Util instance on load of this js
if(!window.infoaxe.util) {
    window.infoaxe.util = new window.infoaxe.Util();
}

