// Copyright 2007-2008 Gilt Groupe, Inc.
var fl;
if (!fl) {
    fl = {};
}
var Gilt;
if (!Gilt) {
  Gilt = {};
}

fl.Init = {};
fl.Init.is_initialized = false;
fl.Init.scms_version_id = null;
fl.Init.question_mark_regexp = null;
fl.Init.ImageUri = function(uri) { // why?
    return uri;
};

// cdnUri: The full path to the domain hosting our images (e.g. http://cdn.gilt.com)
// versionKey: Appended to every cdn image query via javascript. This should be the
//    most recent mtime of ALL assets we may serve from the CDN
fl.Init.WindowLoad = function(cdnUri, versionKey, scmsVersionId) {
    log.setup("startup", "fl")("Loading...");
    fl.Init.scms_version_id = scmsVersionId;

    if (!fl.Init.question_mark_regexp) {
        fl.Init.question_mark_regexp = new RegExp(/\?j_/);
    }

    if (cdnUri) {
        fl.Init.ImageUri = function(uri) {
            if ( fl.Init.question_mark_regexp.test(cdnUri) )  {
                return cdnUri;
            }
            return cdnUri + uri + '?j_' + versionKey;
        };
    } else if (versionKey) {
        fl.Init.ImageUri = function(uri) {
            if ( fl.Init.question_mark_regexp.test(cdnUri) )  {
                return uri;
            }
            return uri + '?j_' + versionKey;
        };
    }
    fl.Init.Initialize();
    fl.Init.is_initialized = true;
    log.stopAll();
};
// Can be called multiple times per page if the page uses ajax. For
// example, a form brought in via ajax will need to make sure this
// function is called to setup all of our validation on the form.
// This function should not have any parameters.
fl.Init.Initialize = function() {
    log.setup("startup", "fl")("Initializing Gilt Groupe");
    gg.Usermeta.init();
    gg.throttleFormSubmit();
    fl.ImageSubmit.init();
    fl.ImageRollover.init();
    fl.ToolTip.init();
    fl.Form.init();
    fl.Form.autoFocusForms();
    if (!gg.Admin.isAdminPage()) {
        // On admin, let rails validate forms.
        fl.Validate.AutoInit();
    }
    gg.Sprite.init();
    gg.processLoginKey();
    gg.FlashMessage.init();
    Gilt.SingleSignOnLinks.init();
    log("Initialization Complete").stop();
};
fl.Init.isInitialized = function() {
    return fl.Init.is_initialized;
};

fl.ImageSubmit = {};
// Looks for input type=image and downloads the images. We do this to
// get these particular images to download as quickly as possible
fl.ImageSubmit.init = function() {
    log.setup("startup", "fl")("Initializing Image Submit");
    var inputs = $('input[type=image]');
    var i = inputs.length;
    var el;
    while (el = inputs[--i]) {
        if (fl.Util.isInitialized('ImageSubmitInit', el)) {
            continue;
        }
        log.setup("startup", "fl")("Preloading %s", el.attr("src"));
        (new Image()).src = el.attr("src");
    }
    log("Image Submit Initialization Complete");
};
fl.ImageRollover = {};
fl.ImageRollover.useZoomEffect = false;
fl.ImageRollover.init = function() {
    log.setup("startup")("Initializing Image Rollovers");

    $("img[rollover]").rollover({
        rollover_source: "rollover",
        otherrollover_sources: "rollover_associated_ids",
        otherrollover_targets: "rollover_associated_urls"
    });

    var imgs = $(".zoom img");
    var i = imgs.length;
    while (i--) {
        imgs.eq(i).attr("fullsrc", imgs.eq(i).attr("src").replace(/\/sm\./,"/lg."));
    }
    if (fl.ImageRollover.useZoomEffect) {
      imgs.zoom({
        container: $("#photoZoom"),
        triggerEvent: "zoomstart", // custom event, so we can do some other stuff first
        useZoomInEffect: false,
        useZoomOutEffect: false,
        panSpeed: 0,
        easing: "linear"
        // All options, for demo:
        /*easing: (-1 != document.location.search.search(/[&\?]paneasing=(\w*)/)) ? document.location.search.match(/[&\?]paneasing=(\w*)/)[1] : "swing",
        panSpeed: (-1 != document.location.search.search(/[&\?]panspeed=(\d*|\w*)/)) ? parseInt(document.location.search.match(/[&\?]panspeed=(\d*)/)[1])||document.location.search.match(/[&\?]panspeed=(\w*)/)[1] : "fast",
        zoomSpeed: (-1 != document.location.search.search(/[&\?]zoominspeed=(\d*|\w*)/)) ? parseInt(document.location.search.match(/[&\?]zoominspeed=(\d*)/)[1])||document.location.search.match(/[&\?]zoominspeed=(\w*)/)[1] : "slow",
        resetSpeed: (-1 != document.location.search.search(/[&\?]zoomoutspeed=(\d*|\w*)/)) ? parseInt(document.location.search.match(/[&\?]zoomoutspeed=(\d*)/)[1])||document.location.search.match(/[&\?]zoomoutspeed=(\w*)/)[1] : "fast",
        useZoomInEffect: -1 == document.location.search.search(/[&\?]zoomin=(false)/),
        useZoomOutEffect: -1 == document.location.search.search(/[&\?]zoomout=(false)/)*/
      });
    }

    log("Image Rollover Initialization Complete");
};

fl.Form = {};
// Places focus on first non empty input field
// $(function() { fl.Form.focusFirstEmptyField('loginform'); });
fl.Form.focusFirstEmptyField = function(formId) {
    var input = $("#" + formId + " input:not(:hidden):blank:first");
    if (input.length) {
        input.focus();
    } else {
        $("#" + formId + " input:not(:hidden):first").focus();
    }
};
fl.Form.initChangeButtonOnSubmit = function() {
    log.setup("startup", "form")("Initializing Change Button On Submit Event");

    var forms = $(".autoChange:input:image").closest("form");

    if (forms.length) {
        $("<img/>").attr("src", '/images/default/buttons/please_wait.gif'); // TODO: this should be a constant
        var f = function() {
            log.setup("interaction", "form")("Changing Button on Submit");
            var img = $(this).find(".autoChange:image"); // I'm assuming there's only 1
            img.data("oldSrc", img.attr("src"))
               .attr("src", '/images/default/buttons/please_wait.gif');
            this.disable();
        };
        forms.unbind("submit", f).submit(f);
    }
};
fl.Form.enable = function() {
    var inputs = $('.autoChange:image');
    var i = inputs.length;
    if (i) {
        while (--i) {
            var el = inputs.eq(i);
            if (el.data("oldSrc")) {
                el.attr("src", el.data("oldSrc"))
                  .removeData("oldSrc")
                  .closest("form")
                    .get().enable();
            }
        }
    }
};
// To focus first input element of a form:
// <% form_tag url_for(:action =>  'update'), :class => 'autoFocus' do -%>
// To focus first empty input element of a form:
// <% form_tag url_for(:action =>  'update'), :class => 'autoFocusEmpty' do -%>
fl.Form.autoFocusForms = function() {
    log.setup("startup", "fl", "form")("Autofocusing on Form");
    var forms = $('form');
    var i = -1;
    var max = forms.length;
    while (++i < max) {
        var el = forms.eq(i);
        if (el.hasClass('autoFocus')) {
            log("Focusing on first field");
            el.find("input[type!=hidden]:first").focus();
            return;
        } else if (el.hasClass('autoFocusEmpty')) {
            log("Focusing on first empty field");
            fl.Util.MaybeAssignID(el);
            fl.Form.focusFirstEmptyField(el.id());
            return;
        }
    }
};
// Auto disable the submit button until all inputs have data.
// If you do not pass in the ID of the submit tag, we'll disable the
// first one we find in the form (first image or submit input tag)
// $(function() { fl.Form.autoDisableSubmit('loginform', 'submit'); });
fl.Form.autoDisableSubmit = function(formId, submitId) {
    log.setup("startup", "fl", "form")("Disabling form submit for form #%s", formId);
    if (!submitId) {
        var form = $("#" + formId);
        if (!form) {
            return;
        }
        var el = form.find(":image, :submit").eq(0);
        if (!el.id()){
            el.id('_fl_autoDisableSubmit');
        }
        submitId = el.id();
    }

    fl.Form.autoDisableSubmitCheck(formId, submitId);
    var inputs = $("#" + formId + " :input");
    var i = inputs.length;
    var f = function() {
        fl.Form.autoDisableSubmitCheck(formId, submitId);
    };
    while (i--) {
        inputs.eq(i).blur(f);
    }

    // Also observe the form so you don't have to tab out of a final text box
    log("Attaching a Form Observer");
    /*new Form.Observer(formId, 0.5, function(_, value) { // TODO: jquery equivalent, probably a plugin
        var map = value.toQueryParams();
        var filled_out = true;
        for (var key in map) {
            if (map.hasOwnProperty(key) && !map[key]) {
                filled_out = false;
                return;
            }
        }
        if (filled_out) {
            fl.Form.autoDisableSubmitCheck(formId, submitId);
        }
    });*/
};
fl.Form.autoDisableSubmitCheck = function(formId, submitId) {
    log.setup("interaction", "fl", "form")("Checking for missing data");
    var inputs = $("#" + formId + " :input");
    var i = inputs.length;
    while (i--) {
        if (!inputs.eq(i).val()) {
            log("Missing data found, disabling submit");
            $("#" + submitId).attr("disabled","disabled");
            return;
        }
    }
    log("No missing data found, enabling submit");
    $("#" + submitId).attr("disabled","");
};
fl.Form.init = function() {	
    log.setup("startup", "fl", "form")("Initializing Forms");
    fl.Form.initPreviewText();
    fl.Form.initChangeButtonOnSubmit();
    fl.Form.initOnKeyPress();
    fl.Form.initPhoneNumberFields();
    fl.Form.usermetaPrefillEmail();
    log("Forms Initialization Complete");
};

fl.Form.initPhoneNumberFields = function() {
    log.setup("startup", "fl", "form")("Adding Phone Number Formatters");
    var inputs = $('input[type=text]');
    var i = inputs.length;
    var el;
    var f = function(el) {
        return function() {
            fl.Formatter.phone(el);
        };
    };
    while (--i > -1) {
        el = inputs.eq(i);
        if (el.hasClass('phone_number')) {
            fl.Formatter.phone(el);
            el.blur(f(el));
        }
    }
};

// looks for test field inputs with class user_prefill_email, and
// prefills the box with the contents from a cookie named email, if set
fl.Form.usermetaPrefillEmail = function() {
    if (-1 != window.location.toString().indexOf('noemail=')) {
        return;
    }

    var cookie_value = fl.Util.readCookie('email');
    if (!cookie_value) {
        return;
    }
    log.setup("startup", "fl", "form")("Adding detected email address %s to all email fields", cookie_value);
    if (!$("input.usermeta_prefill_email[type=text]").val()) {
        $("input.usermeta_prefill_email[type=text]").val(cookie_value);
    }
};

// Submits the form that contains the specified link. Handles ajax and
// traditional submits
fl.Form.submit_link = function(linkElement) {
    fl.Form.submit_form($(linkElement).closest("form"));
};
fl.Form.submit_form = function(form) {
    form = $(form);
    if (form[0] && form[0].onsubmit) {
        // this triggers if the html has an onsubmit="", eg form comes from rails' form_remote_tag().
        form[0].onsubmit();
    } else {
        // this triggers if the onsubmit handlers are set in jquery.
        form.submit();
    }
};
// Now that we're using links for submit buttons, we need to manually trap the enter key
// to submit forms that do not otherwise have submit buttons
// Key code 40 is the down arrow. 38 is the up arrow. If the previous
// key code is one of these, do not submit the form - the user is
// selecting from a list (e.g. an autocompleted list)
fl.Form.lastKeyCode = null;
fl.Form.initOnKeyPress = function() {
    log.setup("startup", "form")("Initializing Form KeyPress Handlers");
    $("form:not(:has(:submit))").keypress(function(event){
        if (13 == event.keyCode && 38 != fl.Form.lastKeyCode && 40 != fl.Form.lastKeyCode){
            log.setup("interaction", "form")("Detected Enter key without immediately prior up or down key, submitting form");
            fl.Form.submit_form($(this).closest("form"));
        }
        fl.Form.lastKeyCode = event.keyCode;
    });
    $(":input:not(textarea,select,:hidden)").keypress(function(event){
        if (13 == event.keyCode && 38 != fl.Form.lastKeyCode && 40 != fl.Form.lastKeyCode){
            log.setup("interaction", "form")("Detected Enter key without immediately prior up or down key, submitting form");
            fl.Form.submit_form($(this).closest("form"));
        }
        fl.Form.lastKeyCode = event.keyCode;
    });
};
// Allows you to set defaults in text fields for any form elements on the page
// text_field_tag this_field, nil, { :preview_text => 'friend@email.com' }
fl.Form.initPreviewText = function() {
    $(":input[preview_text]").coolinput({ source: 'preview_text', blurClass: 'form_preview_text' });
};

// Creates a simple, lightweight tooltip that displays immediately
// below the text the mouse is pointing to. Unobtrusive:
// <dl class="static_tooltip">
//  <dt>Text 2</dt>
//  <dd>Tip 2</dd>
// </dl>
fl.ToolTip = {};
fl.ToolTip.init = function() {
    log.setup("startup", "tooltip")("Initializing Tooltips");

    $("dl.static_tooltip").each(function() {
        if ($(this).data('qtip')) return; // Skip lists which already have an initialized qtip object

        var el = $(this);
        var corner = { target: 'leftMiddle', tooltip: 'rightTop' };
        var tipCorner = "rightTop";
        if (el.closest("#sql_trace").length) {
            corner = { target: 'rightMiddle', tooltip: 'leftTop' };
            tipCorner = "leftTop";
        }
        var style = {
            name: "red",
            color: 'black',
            border: { width: 1 },
            fontSize: '11px',
            lineHeight: '130%',
            tip: {
                corner: tipCorner,
                size: { x: 12, y: 12 }
            }
        };
        if (!el.parent(".field_info")) {
            style.width = { max: 800 };
        }
        el.qtip({
            content: el.find("dd").html(),
            position: {
                target: el.find("dt"),
                corner: corner
            },
            show: {
                effect: {
                    type: 'slide',
                    length: 400
                }
            },
            hide: {
                fixed: true,
                effect: {
                    type: 'slide',
                    length: 200
                }
            },
            style: style
        });
    });
    log("Tooltip Initialization Complete");
};

fl.Validate = {}; // (mostly) DEPRECATED, replaced by validation plugin

// Returns true if the specified string is an integer
fl.Validate.IsInteger = function (str) { // Used by Credit Card Formatter -- Do not delete (yet)
    var i = -1;
    var max = str.length;
    while (++i < max) {
        var c = str.charCodeAt(i);
        if (57 < c || 48 > c){
            return false;
        }
    }
    return true;
};
fl.Validate.AutoInit = function() {
    log.setup("startup", "fl", "validate")("Initializing Form Validation");

    $("form").each(function() {
        $(this).validate({
            //debug: true, // enable to disable form submission, + some debug statements in validate plugin
            errorPlacement: function(error, element) { // TODO: test this placement thoroughly
                //error.css({ display: 'inline', 'float': 'none', margin: 0, width: 'auto' }); // reset some styles.  label.error styles isn't working, it's being applied before some other styles, and being overwritten
                var insertion_point = element.endOfLine(); // place error message after end of current line.
                insertion_point.after(error);
                if (error.offset().top < element.offset().top + element.height()) { // if the line had some space at the end, the error might not go onto a new line.
                    insertion_point.after("<br/>");
                }
            },
          highlight: function(element, errorClass, validClass ) {
            $(element).addClass(errorClass).removeClass(validClass);
            var selectmenu = $(element).data("selectmenu");
            if (selectmenu) {
              selectmenu.newelement.addClass("ui-state-error").removeClass(validClass);
            }
          },
          unhighlight: function( element, errorClass, validClass ) {
            $(element).removeClass(errorClass).addClass(validClass);
            var selectmenu = $(element).data("selectmenu");
            if (selectmenu) {
              selectmenu.newelement.removeClass("ui-state-error").addClass(validClass);
            }
          }
        });
    });
};
// In RJS: page << "fl.Validate.addFormError('addform', '#{error_messages_for(:brand)}');"
// Automatically adds a div tag to contain the error messages for this form if needed.
fl.Validate.addFormError = function(divId, errorMessages) {
    var el = $("#" + divId);
    var errorId = divId + "-E";
    var items = $('#' + errorId);
    var fullMessage = '<div id="' + errorId + '">' + errorMessages + '</div>';
    if (!items.length) {
        el.prepend(fullMessage);
    } else {
        items.html(fullMessage);
    }
};

fl.Validate.hideAllErrors = function() {
    $('.errorExplanation, label.error').hide();
};

fl.Refresh = {};
fl.Refresh.count = null;
fl.Refresh.set_message = function(statusId, message) {
    var el = $("#" + statusId);
    if (el.html() != message) {
        el.html(message);
    }
};
fl.Refresh.auto_refresh = function(statusId, interval, url) {
    fl.Refresh.countdown(statusId, interval, function() { // TODO: not the best way to do this
        window.location = url;
    });
};

// Used to update a div automatically with a countdown timer (e.g. 10
// seconds, 9 seconds, etc.). Callback, if provided, is invoked when 0
// is reached.
fl.Refresh.countdown = function(statusId, interval, callback) {
    if (!fl.Refresh.count) {
        fl.Refresh.count = {};
    }
    var count = (fl.Refresh.count[statusId] || 0) + 1;
    fl.Refresh.count[statusId] = count;

    var elapsed = (count / 4);
    var number_seconds = interval - elapsed;

    var minutes = parseInt(number_seconds / 60);
    var seconds = parseInt(number_seconds % 60).toString();
    if (1 == seconds.length){
        seconds = "0" + seconds;
    }

    fl.Refresh.set_message(statusId, minutes + ":" + seconds + "" + Locale.minutes);
    if (elapsed >= interval) {
        fl.Refresh.count[statusId] = null;
        if (callback) {
            callback();
        }
        return;
    }
    setTimeout(function() {
        fl.Refresh.countdown(statusId, interval, callback);
    }, 250);
};

fl.Omniture = {
    enabled: true,
    abTestGroup: '',
    channel: '',
    pageName: '',
    attributes: {},
    initialize: function(c,pn) {
        log.setup("startup", "fl", "omniture")("Initializing Omniture");
        fl.Omniture.channel = c;
        fl.Omniture.pageName = pn;
        fl.Omniture.attributes = {};
        fl.Omniture.trackingServer = "stat.gilt.com";
        fl.Omniture.trackingServerSecure = "sstat.gilt.com";
       //fl.Omniture.trackingServer = "stat." + gg.Site.currentSubsite.domain;
       //fl.Omniture.trackingServerSecure = "sstat." + gg.Site.currentSubsite.domain;
    },
    disable: function() {
        fl.Omniture.enabled = false;
    },
    addAttribute: function(k,v) {
        log.setup("fl", "omniture")("Adding attribute %s = %o to Omniture", k, v);
        if (!fl.Omniture.attributes[k]) {
            fl.Omniture.attributes[k] = [];
        }
        fl.Omniture.attributes[k][fl.Omniture.attributes[k].length] = v;
    },
    doTracking: function() {
        if (fl.Omniture.enabled) {
            log.setup("startup", "fl", "omniture")("Doing Tracking");
            var omniture_data = {
                channel: fl.Omniture.channel,
                pageName: fl.Omniture.pageName
            };
            if (fl.Omniture.abTestGroup) {
                log("AB Test Group");
                omniture_data.eVar11 = fl.Omniture.abTestGroup;
                omniture_data.prop5 = fl.Omniture.abTestGroup;
            }
            log("Joining attributes");
            var attrs = fl.Omniture.attributes;
            for (var k in attrs) {
                if (attrs.hasOwnProperty(k)) {
                    omniture_data[k] = fl.Omniture.attributes[k].join(',');
                }
            }
            log("Tracking...");
            $(function(){try{ 
                // Note: Passing tracking servers in the omniture_data doesn't seem to work.
                tmp = s.trackingServer;
                stmp = s.trackingServerSecure;
                s.trackingServer = fl.Omniture.trackingServer;
                s.trackingServerSecure = fl.Omniture.trackingServerSecure;
                s.t(omniture_data);
                s.trackingServer = tmp;
                s.trackingServerSecure = stmp;
                }catch(_){}});
        }
    },
    track: function(c,pn,attr) {
        log.setup("fl", "omniture")("Omniture Tracking");
        fl.Omniture.initialize(c, pn);
        for (var k in attr) {
            if (attr.hasOwnProperty(k)) {
                fl.Omniture.attributes[k] = attr[k];
            }
        }
        fl.Omniture.doTracking();
    }
};


// Set of functions to use a cookie as a key-value hash, with LRU space management to keep size under 4kb.
// Might get slow with lots of entries, but with 4kb ceiling, don't expect lots of entries.
fl.LruCookie = {
    persist: {},
    maxSize: {},
    // Internal low-level cookie read, does deserialization
    readCookie: function(cookie) {
        var rslt_string = fl.Util.readCookie(cookie);
        if (!rslt_string) {
            return [];
        }
        return (gg.parse_json(rslt_string) || []);
    },
    // Internal low-level cookie write, does serialization and space management
    writeCookie: function(cookie,state) {
        var state_string = JSON.stringify(state);
        var max = fl.LruCookie.maxSize[cookie] || 256;
        while (state_string.length > max && state.length) {
            state.pop();
            state_string = JSON.stringify(state);
        }
        if (state.length) {
            if (fl.LruCookie.persist[cookie]) {
                fl.Util.setPersistentCookie(cookie, state_string);
            } else {
                fl.Util.setSessionCookie(cookie, state_string);
            }
        } else {
            fl.Util.expireCookie(cookie);
        }
    },
    setPersist: function(cookie,persist) {
        fl.LruCookie.persist[cookie] = persist;
    },
    setMaxSize: function(cookie,maxSize) {
        fl.LruCookie.maxSize[cookie] = maxSize;
    },
    store: function(cookie, key, state) {
        /*var old_state = fl.LruCookie.readCookie(cookie), new_state = [];
        if (state) {
            new_state.push({ k: key, v: state });
        }
        var i = -1, max = old_state.length;
        while (++i < max) {
            var entry = old_state[i];
            if (entry && entry.k != key) {
                new_state.push(entry);
            }
        }
        fl.LruCookie.writeCookie(cookie, new_state);*/
        //if (state) { // are we storing anything
        var data = fl.LruCookie.readCookie(cookie); // load cookie
        if (data) { // does cookie exist
            //var i = -1, max = data.length;
            //while (++i < max) { // look from front
            var i = data.length;
            while (i--) { // look from back
                if (data[i].k == key) { // look for data with same key
                    data.splice(i, 1);  // if found, remove it
                    break;
                }
            }
            if (state) {
                data.unshift({ k: key, v: state }); // put new data on top of stack
            }
        } else if (state) {
            data = [{ k: key, v: state }]; // create cookie
        }
        fl.LruCookie.writeCookie(cookie, data); // write cookie
        //}
    },
    fetch: function(cookie, key) {
        var all_state = fl.LruCookie.readCookie(cookie);
        if (!all_state) {
            return null;
        }
        var i = -1;
        var max = all_state.length;
        while (++i < max) {
            var state = all_state[i];
            if (key == state.k) {
                // Move found state record to front of state array to maintain LRU order
                all_state.splice(i, 1);
                all_state.unshift(state);
                fl.LruCookie.writeCookie(cookie, all_state);
                return state.v;
            }
        }
        return null;
    }
};