
////////////////
// MRect
////////////////
function MRect(x, y, width, height)
{
    this.x = x;
    this.y = y;
    this.width = width;
    this.height = height;
}

////////////////
// MPoint
////////////////
function MPoint(x, y)
{
    this.x = x;
    this.y = y;
}

////////////////
// MSize
////////////////
function MSize(width, height)
{
    this.width = width;
    this.height = height;
}

/********************
  Search text Field 
*********************/

function searchFocusHandler(element,initialValue)
{
    if (element.value == initialValue) {
        element.className = element.className + ' hilite';
    }
}

function searchClickHandler(element,initialValue)
{
    if (element.value == initialValue) {
        element.value = '';
    }
}

function selectTextField(textField)
{
    // See bug 329
    textField.setAttribute('autocomplete', 'off');
    
    textField.focus();
    textField.select();
}

function selectSearchField(onlyIfEdited)
{
    var searchField = document.getElementById('searchFld');
    if (searchField != null) {
        var isDefault = (searchField.value == store_defaultSearchFieldValue && store_defaultSearchFieldValue.length != 0);
        if (!onlyIfEdited || !isDefault) {
            selectTextField(searchField);
        }
    }
}

function submitFormNamed(formId)
{
    var formElement = document.getElementById(formId);
    formElement.submit();
}

function handleFreeTextSearchClicked(event)
{
    var searchField = document.getElementById('searchFld');
    var trimmedValue = searchField.value.trim();
    if (trimmedValue != store_defaultSearchFieldValue || store_defaultSearchFieldValue.length == 0) {
        var lastSearch = tx_getParameter('fts');
        if (trimmedValue == '' && (lastSearch == null || lastSearch == '')) {
            // Empty search with no existing search is a no-op.
            searchField.value = '';
        } else {
            var searchType = $('searchType').value;
            userDidSearch();
            if (searchType == 'all') {
                submitFormNamed('searchFrm');
            } else {
                var newSearch = encodeURIComponent(searchField.value).replace(/\%20/g, "+");
                // for a 'within' search, avoid repeating the same term, and allow blank to clear search
                if (searchType == 'within' && lastSearch != null && lastSearch.trim() == newSearch) {
                    window.location.reload();
                } else {
                    var linkName = 'search_' + searchType;
                    window.location.href = tx_updateParam($(linkName).href, 'fts', newSearch);
                }
            }
        }
    }
    Event.stop(event);
}

function handleSearchFrmKeyPress(event)
{
    if (event.keyCode == Event.KEY_RETURN) {
        this.handleFreeTextSearchClicked(event);
    }
}

function store_searchMenuClicked(event, type, prompt)
{
    $('searchPrompt').innerHTML = prompt;
    $('searchType').value = type;
    if (document.popupContext != null) {
        document.popupContext.closePopup();
    }
    selectSearchField(false);
    
    Event.stop(event);
}

function store_setupAutoCompleter(category)
{
    var showMatches = function(element, update) {
        if (!update.style.position || update.style.position == 'absolute') {
            update.style.position = 'absolute';
            Position.clone(element, update, {
                setHeight: false,
                setWidth: false,
                offsetTop: element.offsetHeight
            });
            if (document.popupContext != null) {
                // close any open drop-down menu when showing auto-completer
                document.popupContext.closePopup();
            }
        }
        Effect.Appear(update, {duration:0.02});
    };
    var hideMatches = function(element, update) {
        Effect.Fade(update, {duration:0.02});
    };
    var submitForm = function(element, sel) {
        submitFormNamed('searchFrm');
    };
    var popupObserver = function() {
        if (document.autoCompleter != null) {
            document.autoCompleter.hide();
        }
    };
    if (document.popupContext != null) {
        // hide the auto-completer if another menu is opened
        document.popupContext.observers.addObserver("openPopup", popupObserver);
    }
    var updateQuery = function(element, entry) {
        // update the query to add the domain parameters
        return entry + "&cat=" + category;
    };
    
    document.observe('dom:loaded', function() {
        document.autoCompleter = new Ajax.Autocompleter('searchFld', 'searchAutoComplete', '/action/autoComplete',
            { paramName: 'search', minChars: 3, onShow: showMatches, onHide: hideMatches, afterUpdateElement: submitForm, method: 'get', callback:updateQuery });
    });
}



/*****************/
/* SSO Support   */
/*****************/

function sso_checkRemoteLogin(loginUrl)
{
    var doCheck = sso_refreshCookie();
    if (doCheck) {
        setCookie('sc22', encodeURIComponent(document.referrer), 30/(24*60*60), store_cookieDomain);
        document.write('<script src="' + loginUrl + '" type="text/javascript"><\/script>');
    }
}

function sso_refreshCookie()
{
    var checkCount = getCookie('sc13');
    var checkLogin = false;
    var doTimeout = true;
    if (checkCount != null) {
        checkCount = parseInt(checkCount);
        if (isNaN(checkCount)) {
            checkCount = null;
        }
    }
    if (checkCount == null) {
        checkCount = 0;
        checkLogin = true;
    }
    
    var nCheckSeconds = 6;
    if (checkCount < (5*60)/nCheckSeconds) {
        var ckdata = checkCount+1;
        setCookie('sc13', ckdata, 15/(24*60*60), store_cookieDomain);
        var cookieCheck = getCookie('sc13');
        if (cookieCheck == null) {
            // could not set cookie?!  Chrome has this problem if we're accessed with numeric ip address
            return false;
        }
        setTimeout('sso_refreshCookie()', 1000*nCheckSeconds);
    }
    else {
        clearCookie('sc13', store_cookieDomain);
    }
    
    return checkLogin;
}

// notify, via a script request, across domains
// used in sso but is actually general functionality
function sso_notify(href)
{
    document.write('<script src="' + href + '" type="text/javascript"><\/script>');
}

/*****************/
/* internationalization  */
/*****************/

var store_strings = {};

function store_getMessage(key)
{
    var msg = store_strings[key];
    if (msg == null) {
        return '[' + key + ']';
    }
    else {
        return msg;
    }
}

/*****************/
/* Sales Alerts  */
/*****************/

function toggleSalesAlert(element)
{
    var imgs = element.parentNode.parentNode.getElementsByTagName('img');
    if (imgs[0].style.visibility == "hidden") {
        imgs[0].style.visibility = "visible";
    }
    else {
        imgs[0].style.visibility = "hidden";
    }
}

/*****************/
/* User Icons  */
/*****************/

function showDeleteButton(iconDiv)
{
    var buttons = Element.select(iconDiv, '.userIconDeleteButton');
    if (buttons.length > 0) {
        buttons[0].style.visibility = "visible";
    }
}

function hideDeleteButton(iconDiv)
{
    var buttons = Element.select(iconDiv, '.userIconDeleteButton');
    if (buttons.length > 0) {
        buttons[0].style.visibility = "hidden";
    }
}

function hiliteIconLabels(iconDiv)
{
    var labels = Element.select(iconDiv, '.clickable');
    for (var i = 0; i < labels.length; i++) {
        labels[i].style.color = "black";
    }
}

function unhiliteIconLabels(iconDiv)
{
    var labels = Element.select(iconDiv, '.clickable');
    for (var i = 0; i < labels.length; i++) {
        labels[i].style.color = "";
    }
}


function scrollToVisible(elementId)
{
    var selectedLook = document.getElementById(elementId);
    var selectedLookTop = absoluteTop(selectedLook);
    window.scrollTo(0, selectedLookTop - 20);
}

function store_elementHeight(element)
{
    var height = isIE() ? element.offsetHeight : element.clientHeight;
    return height;
}

/**
   textAreaId is the name (id) of the textarea element.  This trims it down to maxLength chars
   to fit the limit we have set in the DB (typically 4096 chars).
*/
function trimTextArea(textAreaId, maxLength)
{
    var textAreas = document.getElementsByTagName('textarea');
    for (var i = 0; i != textAreas.length; i++) {
        if (textAreas[i].id == textAreaId) {
            var textAreaValue = textAreas[i].value.trim();
            if (textAreaValue.length >= maxLength) {
                textAreaValue = textAreaValue.substring(0, maxLength - 1);
            }
            textAreas[i].value = textAreaValue;
        }
    }
}


function MHintContext(hintName, alwaysDoHint, viewerContext)
{
    this.viewerContext = viewerContext;
    var cookieValue = getCookie('sc4');
    var hintVersion = cookieValue ? parseInt(cookieValue) : 0;
    if (alwaysDoHint || hintVersion < 1) {
        this.hintVersion = hintVersion;
        
        this.isHintVisible = false;
        this.hasScrolled = false;
    
        this.hintBubble = document.getElementById(hintName);
        if (this.hintBubble && viewerContext != null) {
            window.setTimeout(this.beginShowingAnimation.bind(this), 4000);
        }
    }
}

MHintContext.prototype.beginShowingAnimation = function()
{
    if (!this.hasScrolled && this.viewerContext.canScroll()) {
        new Effect.Opacity(this.hintBubble, {from:0.0, to:1.0, duration:1.2, fps:16, transition:Effect.Transitions.linear,
                                             afterFinish:this.finishShowingAnimation.bind(this) });
    }
}

MHintContext.prototype.finishShowingAnimation = function()
{
    this.isHintVisible = true;
    if (this.hasScrolled) {
        // they scrolled while the hint was animating into view
        this.beginHidingAnimation(this);
    }
}

MHintContext.prototype.didScroll = function()
{
    if (!this.hasScrolled) {
        setCookie('sc4', 1, 365*100, store_cookieDomain);
        this.hasScrolled = true;
        if (this.isHintVisible) {
            this.beginHidingAnimation(this);
        }
    }
}

MHintContext.prototype.beginHidingAnimation = function()
{
    this.isHintVisible = false;
    new Effect.Opacity(this.hintBubble, { from:1.0, to:0.0, duration:0.4, fps:12, transition:Effect.Transitions.linear,
                                          afterFinish:this.finishHidingAnimation.bind(this) });
}

MHintContext.prototype.finishHidingAnimation = function()
{
    // Safari doesn't completely erase the hint unless you give it time to redraw after
    // the animation, but before the hint is hidden with display:none.
    window.setTimeout(this.andReallyFinishHidingAnimation.bind(this), 500);
}

MHintContext.prototype.andReallyFinishHidingAnimation = function()
{
    this.hintBubble.style.visibility = "hidden";
    // important to display:none, see CellBrowser.html
    this.hintBubble.style.display = "none";
}


/**
  Used to record explicit user searches in Omniture, which got
  harder once we cleaned up our urls and made them canonical
*/
function userDidSearch()
{
    setCookie('sc2', 'search:', null, store_cookieDomain);
}

/**
  Used to record diff nav types in Omniture without mucking up our urls.
*/
function userDidNavType(type)
{
    setCookie('sc2', 'navt:' + type, null, store_cookieDomain);
}

function store_isUserSignedIn()
{
    var isUserSignedIn = false;
    var handleAjaxResponse = function(xmlhttp) {
        var responseText = xmlhttp.responseText;
        isUserSignedIn = responseText == "true";
    };
    var optionsDict = {
            asynchronous: false,
            method: 'get',
            onSuccess: handleAjaxResponse
    };
    new Ajax.Request('/action/isUserSignedIn', optionsDict);
    return isUserSignedIn;
}

function store_openSignInDialog(anchorElement, signInUrl, pendingUrl, isPendingUrlForDialog)
{
    var isUserSignedIn = store_isUserSignedIn();
    if (isUserSignedIn == true) {
        if (isPendingUrlForDialog) {
            openDialog(anchorElement, pendingUrl);
        }
        else {
            window.location.href = pendingUrl;
        }
    }
    else {
        var baseElement = null;
        openDialog(anchorElement, signInUrl, pendingUrl, baseElement, isPendingUrlForDialog)
    }
    return false;
}

function store_setShippingCountry(country)
{
    var handleAjaxResponse = function(xmlhttp) {
        // refresh the page, but strip any dialog invoking parameters (so we don't cycle)
        var url = window.location.href;
        url = tx_removeParam(url, "dialog");
        if (url.charAt(url.length-1) == '#') {
            url = url.substr(0, length-1);
        }
        window.location = url;
    };
    
    // remember that we've set the shipping country, for analytics
    setCookie('sc2', 'shipC:'+country, null, store_cookieDomain);

    var optionsDict = {
            method: 'get',
            onSuccess: handleAjaxResponse
    };
    var url = '/action/changeShippingCountry?country='+country;
    new Ajax.Request(url, optionsDict);
    
    return false;
}

///////////////////
// CellBrowser
///////////////////

/* all sizes copied in store.css too, and dependent on bo.Image's sizes too */
document.smallProductCellSize = new MSize(70, 84);
document.mediumProductCellSize = new MSize(138, 188);
document.largeProductCellSize = new MSize(184, 255);

function store_computeProductCellSize()
{
    var isSmallWindow = tx_windowSizeForCookie() < store_cellSizeThreshold;
    return isSmallWindow ? document.mediumProductCellSize : document.largeProductCellSize;
}

function store_smallProductCellSize()
{
    return document.smallProductCellSize;
}

function store_mediumProductCellSize()
{
    return document.mediumProductCellSize;
}

function store_largeProductCellSize()
{
    return document.largeProductCellSize;
}

document.departmentCellSize = new MSize(315, 440);
function store_departmentCellSize()
{
    return document.departmentCellSize;
}

document.departmentSmallCellSize = new MSize(163, 194);
function store_departmentSmallCellSize()
{
    return document.departmentSmallCellSize;
}

document.mediumLookCellSize = new MSize(351, 230);
document.largeLookCellSize = new MSize(351, 301);

function store_computeLookCellSize()
{
    // magic constant also exists in the server
    var isSmallWindow = tx_windowSizeForCookie() < store_lookCellSizeThreshold;
    return isSmallWindow ? document.mediumLookCellSize : document.largeLookCellSize;
}

document.smallLookWidgetCellSize = new MSize(266, 240);
function store_smallLookWidgetSmallCellSize()
{
    return document.smallLookWidgetCellSize;
}

document.largeLookWidgetCellSize = new MSize(480, 400);
function store_largeLookWidgetSmallCellSize()
{
    return document.largeLookWidgetCellSize;
}

document.homeLookCellSize = new MSize(330, 265);
function store_homeLookCellSize()
{
    return document.homeLookCellSize;
}

document.promotionCellSize = new MSize(341, 162);

function store_promotionCellSize()
{
    return document.promotionCellSize;
}

document.userCellSize = new MSize(240, 130);

function store_computeUserCellSize()
{
    return document.userCellSize;
}

////////////////////////
// Analytics / Omniture
////////////////////////

var store_ajaxTrackingEnabled = false;

function store_setAjaxTrackingEnabled(flag)
{
    store_ajaxTrackingEnabled = flag;
}

function store_isAjaxTrackingEnabled()
{
    return store_ajaxTrackingEnabled;
}

var store_reportSuiteName = null;
var store_omniHostName = null;

function store_setReportSuiteName(name)
{
    store_reportSuiteName = name;
}

function store_setOmniHostName(name)
{
    store_omniHostName = name;
}

// linkElement should be the widget clicked on (not sure how it's used, but null doesn't
// work).  gestureName is a constant that will show up as a value under the Omniture AJAX prop.
function store_emitOmnitureAjaxPacket(linkElement, gestureName)
{
    store_emitOmnitureMicroPacket(11, gestureName);
}

// A "micro" omni packet is one that just holds a few property values, but doesn't imply
// a full-on page view and visit.  This is useful for AJAX ops that happen within a page.
// The arguments are pairs of prop number then property value.
function store_emitOmnitureMicroPacket(/* ... */)
{
    if (store_reportSuiteName) {
        // need to make the url different every time to defeat browser caching
        // pe_lnk stuff needed or else the packet will cause a page view
        var random = new Date().getTime();
        var im = new Image();
        var url = 'http://' + store_omniHostName + '/b/ss/' + store_reportSuiteName + '/1/H.7-pdv-2/' + random + '?ns=shopstyle';
        for (var i = 0; i < arguments.length-1; i += 2) {
            url += '&c' + arguments[i] + '=' + escape(arguments[i+1]);
        }
        url += '&pe=lnk_o&pev2=AJAX%20Link';
        im.src = url;
    }
/*
    // standard method, but it was too slow
    if (store_reportSuiteName) {
        var s2=makeOmnitureObject(store_reportSuiteName, "shopstyle");
        // linkTrackVars determines what values are sent to Omniture, and we only want to send the one prop
        // we set, since this isn't a full page view.
        s2.linkTrackVars="prop11";
        s2.prop11 = gestureName;
        s2.tl(linkElement, 'o', 'AJAX Link');
    }
*/
}

function store_emitComScorePacket(currentUrl)
{
    window.setTimeout(function() {
        if (currentUrl == undefined || currentUrl == null) {
            currentUrl = window.location.hostname + window.location.pathname;
        }
        var im = new Image();
        im.src = "http://beacon.scorecardresearch.com/scripts/beacon.dll?c1=2&c2=6035900"
            + "&c3=&c4=" + currentUrl
            + "&c5=&c6=&c7=" + escape(document.location.href)
            + "&c8=" + escape(document.title)
            + "&c9=" + escape(document.referrer)
            + "&c10=" + escape(screen.width+'x'+screen.height)
            + "&c15=&rn=" + (new Date()).getTime();
    }, 1);
}

function store_emitComScoreScrollPacket(isBigScroll)
{
    if (isBigScroll) {
        store_emitComScorePacket(null);
    }
}

function store_emitQuantcastScrollPacket(isBigScroll)
{
    if (isBigScroll && typeof quantserve != 'undefined') {
        _qoptions = {
            qacct:"p-36POJYHTosuxU",
            media:"webpage",
            event:"refresh"
        };
        quantserve();
    }
}

var previousExplanationParentDiv;

// debug hack for showing/hiding an explanation div
function store_showExplanation(parentDiv)
{
    store_hideCurrentExplanation();
    previousExplanationParentDiv = parentDiv;
    var explanation = findChildWithId(parentDiv, 'explanation');
    document.body.appendChild(explanation);
    explanation.id = "currentExplanation";
    explanation.style.display = "block";
}

function store_hideCurrentExplanation()
{
    store_hideExplanation(previousExplanationParentDiv);
}

function store_hideExplanation(parentDiv)
{
    var explanation = findChildWithId(document.body, 'currentExplanation');
    if (explanation && parentDiv) {
        explanation.style.display = "none";
        parentDiv.appendChild(explanation);
        explanation.id = "explanation";
    }
}

//
// Ad rotation
//
var lastRotateTime = (new Date()).getTime();
var rotateTimeoutId = null;
var adFrames = null;
function store_rotateAds(isBigScroll)
{
    // cache the list of ad iframes needing rotation.  This will allow us
    // to short out of this work in the case where nothing needs rotating.
    if (adFrames == null) {
        adFrames = new Array();
        var iframes = document.getElementsByTagName('iframe');
        for (var frameIndex = 0; frameIndex < iframes.length; frameIndex++) {
            var frame = iframes[frameIndex];
            if (frame.id && frame.id.startsWith('rotatingAd')) {
                adFrames.push(frame);
            }
        }
    }
    
    if (adFrames.length > 0) {
        // no matter what kind of scroll is going on, if a rotate was scheduled,
        // we want to defer it (meaning cancel and reschedule).  Also, if its a big
        // scroll and the current ad has been up long enough, then schedule it);
        if (rotateTimeoutId || (isBigScroll && ((new Date()).getTime() - lastRotateTime > 4500))) {
            if (rotateTimeoutId) {
                window.clearTimeout(rotateTimeoutId);
            }
            rotateTimeoutId = window.setTimeout(store_doRotateAds, 500);
        }
    }
}

function store_doRotateAds()
{
    for (var frameIndex = 0; frameIndex < adFrames.length; frameIndex++) {
        var frame = adFrames[frameIndex];
        var adSrc = tx_replaceParam(frame.src, 'showNow', 't');
        if (frame.contentWindow) {
            frame.contentWindow.location.replace(adSrc); 
        }
        else {
            frame.src = adSrc;
        }
        // track the ad, position is based on the id
        /*
        var i = frame.id.indexOf("rotatingAd-");
        if (i > -1) {
            store_emitOmnitureMicroPacket(26, frame.id.substring(i+11));
        }
        */
    }
    lastRotateTime = (new Date()).getTime();
    rotateTimeoutId = null;
}

function store_manualAdRotation()
{
    store_rotateAds(null, false);
    store_doRotateAds();
}

//
// Locale flag selection feedback
//
function store_selectLocale(hoverId, hoverColor, selectedColor)
{
    //trace('SET');
    // first locale in the list is always the selected locale
    var selectedLocale = document.getElementById('locale0');
    selectedLocale.style.color = selectedColor;
    
    var hoverLocale = document.getElementById(hoverId);
    
    if (hoverLocale == selectedLocale && hoverColor == 'black') {
        // moving out of selected element, dont set the bullet invisible
    } else {
        hoverLocale.style.color = hoverColor;
    }
}

function store_ajaxUpdateDiv(url, parentDiv, hideFirst)
{
    var handleAjaxResponse = function(xmlhttp) {
        var dialogContents = getResponseText(xmlhttp);
        if (!handleAjaxExceptionPage(dialogContents)) {
            Element.update(parentDiv, dialogContents);
            findAndEvalJavascript(dialogContents);
            var showParent = function() {
                // Hide until element can paint itself to avoid flicker
                Element.show(parentDiv);
            }
            if (hideFirst) {
                window.setTimeout(showParent, 10);
            }
        }
    };
    if (hideFirst) {
        Element.hide(parentDiv);
    }
    new Ajax.Request(url, { method: 'get', onSuccess: handleAjaxResponse });
    return false;
}

// check for cookie support
var supports_cookies = false;
setCookie('sc16', '1');
if (getCookie('sc16')) {
    supports_cookies=true;
}

function gatherCheckboxIds(container)
{
    var ids = new Array();
    var inputs = container.getElementsByTagName('input');
    for (var i = 0; i != inputs.length; i++) {
        var input = inputs[i];
        if (input.type == "checkbox" && input.checked) {
            ids.push(input.id);
        }
    }

    return ids;
}

function store_disableButton(button)
{
    // our buttons have outer <a> with onclick and inner div with class
    if ($(button) != null) {
        $(button).onclick = null;
        var innerDiv = Element.select(button, ".buttonCell");
        if (innerDiv != null && innerDiv.length > 0) {
            Element.addClassName(innerDiv[0], "buttonCellDisabled");
        }
    }
}
