/*jslint devel: false, browser: true, undef: true, unparam: true, sloppy: true, vars: true, white: true, nomen: true, plusplus: true, maxerr: 50, indent: 4, continue: true */
/*global $, Event, Tx, TxEventObserver, SSDialog, Store, SSFav, SSPDetails */

////////////////////////////
// Context for all product details popups on this page.
// NOTE: there is only one of these per page, not one per popup
////////////////////////////

function MProductDetailsContext()
{
    // (Kevin 7/28/11) JSLint complains about the periods in the regexp, but we really want those
    /*jslint regexp: true */
    // note that the state is per page, not per details popup
    this._selectedColorDiv = null;
    this._imageExp = /.*\/.im\/..\/..\/([a-f0-9]*)/;
    this._productImgUrl = null;
    this._hasClickedColor = false;
    this._hasSwizzledColor = false;
    this._restoreProductColor = true;
    // for observing changeColor events
    this.observers = new TxEventObserver();
}

MProductDetailsContext.prototype.updateSizesForColor = function(detailsDiv, availableSizes)
{
    var spans = detailsDiv.getElementsByTagName("span");
    var spansLength = spans.length;
    var sizeIndex = 0;
    var index;
    for (index = 0; index < spansLength; index++) {
        var span = spans[index];
        if (span.id === "detailsSize") {
            if (span.origColor === null || span.origColor === undefined) {
                span.origColor = span.style.color;
            }
            if (!availableSizes || availableSizes[sizeIndex] === 1) {
                span.style.color = span.origColor;
            }
            else {
                span.style.color = '#cccccc';
            }
            sizeIndex++;
        }
    }
};

MProductDetailsContext.prototype.swizzleProductImage = function(imageParentDiv, altProductImageUrl)
{
   var productImg = imageParentDiv.productImg;
   if (!productImg) {
       // If the productImg is not found, nothing to swizzle.
       return;
   }
   if (!altProductImageUrl || altProductImageUrl === '') {
       var productImgSrc = imageParentDiv.productImgSrc;
       if (productImgSrc && productImgSrc !== productImg.src) {
           productImg.src = productImgSrc;
       }
   }
   else {
       productImg.src = altProductImageUrl;
   }
   this._hasSwizzledColor = true;
};

// save the product image information into the fetcher div for later reference
MProductDetailsContext.prototype.initializeProductImg = function(imageParentDiv)
{
    var productImg = imageParentDiv.productImg;
    if (productImg === undefined) {
        // cache the productImg and its src for later restoration
        productImg = $(imageParentDiv).down(".cellImg");
        // If the cellImg is not found, nothing to initialize.
        if (productImg) {
            imageParentDiv.productImg = productImg;
            imageParentDiv.productOriginalImgSrc = productImg.src;
            imageParentDiv.productImgSrc = productImg.src;
        }
    }

    return productImg;
};

// change the default image for the product
// the default image is what is shown when the mouse is not over a color swatch
MProductDetailsContext.prototype.setDefaultSource = function(imageParentDiv, defaultSource)
{
    if (defaultSource) {
        imageParentDiv.productImgSrc = defaultSource;
    }
    else {
        imageParentDiv.productImgSrc = imageParentDiv.productOriginalImgSrc;
    }
};

/* handleColorMouseOver, handleColorMouseOut, handleColorClick, handleSizeMouseOver, handleSizeMouseOut, handleSizeClick share an interface with registry.js - see ColorTable.java */

MProductDetailsContext.prototype.handleColorMouseOver = function(detailsColorDiv, event, availableSizes, colorIndex)
{
    $(detailsColorDiv).addClassName('detailsColorHilite');
    var detailsDiv = this.getDetailsDiv();
    this.updateSizesForColor(detailsDiv, availableSizes);
    var detailsFetcherDiv = document.detailsContext._currentDetailsFetcherDiv;
    if (detailsFetcherDiv && detailsFetcherDiv._colorInfo) {
        var colorInfo = detailsFetcherDiv._colorInfo[colorIndex];
        this.swizzleProductImage(detailsFetcherDiv, colorInfo.image);
        if (colorInfo.mimage !== undefined) {
            this.swizzleProductImage(detailsDiv, colorInfo.mimage);
        }
    }
    Event.stop(event);
};

MProductDetailsContext.prototype.handleColorMouseOut = function(detailsColorDiv, event)
{
    $(detailsColorDiv).removeClassName('detailsColorHilite');
    var detailsDiv = this.getDetailsDiv();
    this.updateSizesForColor(detailsDiv, null);
    var detailsFetcherDiv = document.detailsContext._currentDetailsFetcherDiv;
    if (detailsFetcherDiv) {
        this.swizzleProductImage(detailsFetcherDiv, null);
        this.swizzleProductImage(detailsDiv, null);
    }
    Event.stop(event);
};

MProductDetailsContext.prototype.handleColorClick = function(detailsColorDiv, event, colorIndex)
{
    // change selection
    if (this._selectedColorDiv !== null) {
        $(this._selectedColorDiv).removeClassName('chosenHilite');
    }
    $(detailsColorDiv).addClassName('chosenHilite');
    this._selectedColorDiv = detailsColorDiv;

    // change default image to what is chosen
    var detailsDiv = this.getDetailsDiv();
    var detailsFetcherDiv = document.detailsContext._currentDetailsFetcherDiv;
    this.setDefaultSource(detailsFetcherDiv, detailsFetcherDiv.productImg.src);
    if (detailsDiv.productImg !== undefined) {
        this.setDefaultSource(detailsDiv, detailsDiv.productImg.src);
    }

    this._hasClickedColor = true;
    this._productImgUrl = detailsFetcherDiv.productImgSrc;
    Event.stop(event);
};

MProductDetailsContext.prototype.extractImageUrl = function(fullUrl)
{
    if (!fullUrl) {
        return null;
    }
    var result = fullUrl.match(this._imageExp);
    if (result !== null) {
        return result[1];
    }
    else {
        return null;
    }
};

MProductDetailsContext.prototype.setColors = function(colors, productId)
{
    // save the color tokens on the fetcher div for future reference
    var detailsFetcherDiv = document.detailsContext._currentDetailsFetcherDiv;
    if (!detailsFetcherDiv) {
        // this may be a preloaded details popup, so _currentDetailsFetcherDiv isn't set yet
        // find the fetcher div based on the productId
        detailsFetcherDiv = $('detailsFetcher' + productId);
    }
    if (detailsFetcherDiv) {
        detailsFetcherDiv._colorInfo = colors;
        this.setColorSelection(detailsFetcherDiv);
    }
};

// set the color selection style on the color swatch that corresponds to the product image
MProductDetailsContext.prototype.setColorSelection = function(detailsFetcherDiv)
{
    var colorInfo = detailsFetcherDiv._colorInfo;
    if (!colorInfo || colorInfo.length < 2) {
        // don't show selection if nothing to choose
        return;
    }

    var productImgChild = detailsFetcherDiv.productImg;
    if (!productImgChild) {
        // product cell on spread look image has no productImg, since product cell does not display cellImg img
        return;
    }

    var productImgToken = this.extractImageUrl(productImgChild.src);

    var detailsDiv = this.getDetailsDiv();
    var divs = detailsDiv.getElementsByTagName("div");
    var divsLength = divs.length;
    this._selectedColorDiv = null;
    var colorIndex = 0;
    var haveSelected = false;
    var divIndex;
    for (divIndex = 0; divIndex < divsLength; divIndex++) {
        var div = divs[divIndex];
        if ($(div).hasClassName('detailsColorHilitable') || $(div).hasClassName('detailsColorText')) {
            if (!colorInfo[colorIndex] || colorInfo[colorIndex].token === "") {
                continue;
            }
            if (productImgToken === colorInfo[colorIndex].token && !haveSelected) {
                this._selectedColorDiv = div;
                $(div).addClassName('chosenHilite');
                haveSelected = true;
            }
            else {
                $(div).removeClassName('chosenHilite');
            }
            colorIndex++;
        }
    }
};

// hook called by details.js when the details dialog appears
MProductDetailsContext.prototype.handleShowDetails = function()
{
    SSPDetails.colorSizeContext = this;

    var detailsDiv = this.getDetailsDiv();
    var detailsFetcherDiv = document.detailsContext._currentDetailsFetcherDiv;
    this.initializeProductImg(detailsDiv);
    this.initializeProductImg(detailsFetcherDiv);
    this._productImgUrl = detailsFetcherDiv.productImgSrc;

    this.setColorSelection(detailsFetcherDiv);
};

//hook called by details.js when the details dialog is hidden (which may happen before it is shown!)
MProductDetailsContext.prototype.handleHideDetails = function()
{
    //trace("productDetails.handleHideDetails");
    var detailsDiv = this.getDetailsDiv();
    var detailsFetcherDiv = document.detailsContext._currentDetailsFetcherDiv;
    var img = null;
    var changeColorLink = null;
    if (detailsFetcherDiv) {
        img = detailsFetcherDiv.productImg;
        // if we have a changeColor link then we want to set the color
        changeColorLink = Tx.findChildWithClass(detailsFetcherDiv, 'changeColorLink');
    }

    // save the color change, if we know a look and favorite
    if (this._selectedColorDiv !== null && img && changeColorLink !== null && this._hasClickedColor) {
        //trace("handleHideDetails saving color");
        var colorToken = this.extractImageUrl(img.src);
        if (changeColorLink !== null && changeColorLink.href) {
            //trace("sending color change to server");
            var handleAjaxResponse = function(xmlhttp) {
                var responseText = Tx.getResponseText(xmlhttp);
                Tx.handleUpdatesFromDirectAction(responseText);
            };
            var optionsDict = {
                    asynchronous: true,
                    method: 'get',
                    onSuccess: handleAjaxResponse
            };
            var url = changeColorLink.href;
            url = Tx.replaceParam(url, 'colorToken', colorToken);
            Tx.ajax(url, optionsDict);
        }

        // tell any observers that the color has been changed
        this.observers.notify("changeColor", detailsFetcherDiv);
    }
    else if (this._hasSwizzledColor) {
        this.observers.notify("cancelColor", detailsFetcherDiv);
    }

    // set image sources back to the originals (if we aren't editing)
    if (this._restoreProductColor && detailsFetcherDiv && detailsFetcherDiv.productOriginalImgSrc &&
            changeColorLink === null) {
        this.setDefaultSource(detailsFetcherDiv, null);
        this.setDefaultSource(detailsDiv, null);
        this.swizzleProductImage(detailsFetcherDiv, null);
        this.swizzleProductImage(detailsDiv, null);
    }

    this._hasClickedColor = false;
    this._hasSwizzledColor = false;
};

MProductDetailsContext.prototype.getDetailsDiv = function()
{
    var detailsFetcherDiv = document.detailsContext._currentDetailsFetcherDiv;
    var detailsDiv = document.detailsContext.getDetailsDiv(detailsFetcherDiv);
    return detailsDiv;
};

////////////////////////////
// Sizes Handling
////////////////////////////

MProductDetailsContext.prototype.applyDivMask = function(targetDiv)
{
    var divMask = targetDiv.getAttribute("divMask");
    if (!divMask) {
        divMask = document.createElement('div');
        targetDiv.setAttribute("divMask", divMask);
        divMask.style.position = 'absolute';
        divMask.style.width = targetDiv.offsetWidth;
        divMask.style.height = targetDiv.offsetHeight;
        divMask.style.top = "0px";
        divMask.style.left = "0px";
        divMask.style.backgroundColor = "white";
        divMask.style.filter = "progid:DXImageTransform.Microsoft.Alpha(opacity=90)";
        divMask.style.zIndex = 100;
        divMask.style.visibility = 'hidden';
        targetDiv.appendChild(divMask);
    }
    divMask.style.visibility = 'visible';
};

MProductDetailsContext.prototype.removeDivMask = function(targetDiv)
{
    var divMask = targetDiv.getAttribute("divMask");
    if (divMask) {
        divMask.style.visibility = 'hidden';
    }
};

MProductDetailsContext.prototype.updateColorsForSize = function(detailsDiv, availableColors)
{
    var divs = detailsDiv.getElementsByTagName("div");
    var divsLength = divs.length;
    var colorIndex = 0;
    var divIndex;
    for (divIndex = 0; divIndex < divsLength; divIndex++) {
        var div = divs[divIndex];
        if (div.id === "detailsColor") {
            if (!availableColors || availableColors[colorIndex] === 1) {
                if (Tx.isIE7()) {
                    this.removeDivMask(div);
                }
                else {
                    $(div).removeClassName('detailsColorUnavailable');
                }
            }
            else {
                if (Tx.isIE7()) {
                    this.applyDivMask(div);
                }
                else {
                    $(div).addClassName('detailsColorUnavailable');
                }
            }
            colorIndex++;
        }
    }
};

MProductDetailsContext.prototype.handleSizeMouseOver = function(detailsSizeSpan, event, availableColors)
{
    if (availableColors) {
        $(detailsSizeSpan).addClassName('detailsSizeHilite');
    }
    var detailsDiv = this.getDetailsDiv();
    this.updateColorsForSize(detailsDiv, availableColors);
    Event.stop(event);
};

MProductDetailsContext.prototype.handleSizeMouseOut = function(detailsSizeSpan, event)
{
    $(detailsSizeSpan).removeClassName('detailsSizeHilite');
    var detailsDiv = this.getDetailsDiv();
    this.updateColorsForSize(detailsDiv, null);
    Event.stop(event);
};

MProductDetailsContext.prototype.handleSizeClick = function(detailsSizeSpan, event, sizeName)
{
    Event.stop(event);
};

// handle a mouse click that happens outside the color and size area
MProductDetailsContext.prototype.handleClickOutside = function(event)
{
    if (this._selectedColorDiv !== null) {
        $(this._selectedColorDiv).removeClassName('chosenHilite');
        this._selectedColorDiv = null;
    }

    var detailsDiv = this.getDetailsDiv();
    var detailsFetcherDiv = document.detailsContext._currentDetailsFetcherDiv;
    this.setDefaultSource(detailsFetcherDiv, null);
    this.setDefaultSource(detailsDiv, null);
    this.swizzleProductImage(detailsFetcherDiv, null);
    this.swizzleProductImage(detailsDiv, null);

    this.setColorSelection(detailsFetcherDiv);

    Event.stop(event);
};

function SSDeals()
{
    // the example search prompt (filled out correctly in PageWrapper)
    this.popupWindows = [];
    this.cnt = 0;
    this.closeWindowTimer = null;
    this.moveResizeTimer = null;
    this.lastCTWindow = null;
    this.lastDealWindow = null;
    
    // Chrome needs to be a bit wider and taller as it never hide the URL address bar
    var ua = navigator.userAgent;
    this.isChrome = ua.indexOf("Chrome") >= 0;
    if (this.isChrome) {
        this.popupWindowWidth = 295;
        this.popupWindowHeight = 380;
    }
    else if (Tx.isSafari()) {
        this.popupWindowWidth = 295;
        this.popupWindowHeight = 350;
    }
    else {
        this.popupWindowWidth = 295;
        this.popupWindowHeight = 320;
    }
}

// Create our global Designer Apparel object
document.ssdeals = new SSDeals();

SSDeals.prototype.addPairedWindow = function(w1, w2)
{
    var pairPopupWindow = [];
    this.popupWindows[this.cnt] = pairPopupWindow;
    pairPopupWindow[0] = w1;
    pairPopupWindow[1] = w2;
    pairPopupWindow[2] = 'false';
    this.cnt++;
    
        // Create a just only one timer
    if (this.closeWindowTimer === null) {
        this.closeWindowTimer = setInterval(this.closePairedWindow, 500);  
    }
}

SSDeals.prototype.closePairedWindow = function()
{
    var allclosed = true;
    var length = document.ssdeals.popupWindows.length;
    for (i = 0; i < length; i++) {
        var pairPopupWindow = document.ssdeals.popupWindows[i];
        if (pairPopupWindow !== undefined && pairPopupWindow[0] !== null && pairPopupWindow[1] !== null) {
                // Close the popup window if retailer window is closed
            if(pairPopupWindow[0].closed) {  
                pairPopupWindow[1].close();
                
                pairPopupWindow[0] = null;
                pairPopupWindow[1] = null;
                pairPopupWindow[2] = true;
            }
            else {
                allclosed = false;
            }
        }
    }
    
    if (allclosed) {
        clearInterval(document.ssdeals.closeWindowTimer);
        document.ssdeals.closeWindowTimer = null;
        document.ssdeals.popupWindows = [];
    }
}

SSDeals.prototype.moveAndResizeWindow = function()
{
    try {
        var length = document.ssdeals.popupWindows.length;
        for (i = length -1; i >= 0; i--) {
            var pairPopupWindow = document.ssdeals.popupWindows[i];
            if (pairPopupWindow[0] !== null && pairPopupWindow[1] !== null && 
                pairPopupWindow[0] !== undefined && pairPopupWindow[1] !== undefined &&
                pairPopupWindow[2] === 'false') {
            
                var ct_window =   pairPopupWindow[0];
                var deal_window = pairPopupWindow[1];
                
                var screenX = Tx.isIE()?ct_window.screenLeft:ct_window.screenX;
                var screenY = Tx.isIE()?ct_window.screenTop:ct_window.screenY;
                if (screenX !== undefined && screenY !== undefined) {
                    // Determine if we have enough space to put side by side
                    var screenWidth = screen.availWidth;
                    
                    var width = Tx.clientWidth(ct_window);
                    var sideBySideWidth = document.ssdeals.popupWindowWidth + width;
                    
                    if (screenWidth > sideBySideWidth) {
                        var x_pos = screenX - document.ssdeals.popupWindowWidth;
                        var y_pos = screenY + (ct_window.outerHeight - ct_window.innerHeight) - (deal_window.outerHeight - deal_window.innerHeight);
                        
                        // Put to the window to the left and top corner of CT window.
                        // However, if it off the screen, then move the CT window to the right
                        if (x_pos < 0) {
                            ct_window.moveTo(295, screenY);
                        }
            
                        deal_window.moveTo(x_pos, y_pos);
                        
                        // Resize the chrome as it does not do so properly
                        if (document.ssdeals.isChrome || Tx.isSafari()) {
                            deal_window.resizeTo(document.ssdeals.popupWindowWidth, document.ssdeals.popupWindowHeight);
                        }
                        
                        // Focus to the CT window
                        ctWindow.focus();
                    }
                    else {
                        var y_pos = screenY + (ct_window.outerHeight - ct_window.innerHeight) - (deal_window.outerHeight - deal_window.innerHeight);

                        deal_window.moveTo(0, y_pos);
                        // Resize the chrome as it does not do so properly
                        if (document.ssdeals.isChrome || Tx.isSafari()) {
                            deal_window.resizeTo(document.ssdeals.popupWindowWidth, document.ssdeals.popupWindowHeight);
                        }
                        
                        // Popup the Holiday Saving window on top
                        var cookieValue = Tx.getCookie('sc38');
                        if (cookieValue !== '1') {
                            deal_window.focus();
                        }
                        else {
                            ct_window.focus();
                        }
                        Tx.setCookie("sc38", '1', null);
                    }
                    
                    pairPopupWindow[2] = 'true';
                }
            }
        }
    }
    catch(err) {
    }
    
}

SSDeals.prototype.openDealWindow = function(ctWindow, url)
{
    // Make the window name unique by uber id so each product opens in a new window.
    var id = Tx.getParameterFromUrl('id', url);
    var dealWindowName = 'ssdeals' + (id === null ? '' : id);
    
    var dealWindow = null;
    if (this.isChrome) {
        dealWindow = window.open(url, dealWindowName, 'width='+this.popupWindowWidth+',height=420,menubar=no,toolbar=no,location=no,directories=no,status=no,resizable=no,scrollbars=no');
    }
    else {
        dealWindow = window.open(url, dealWindowName, 'width='+this.popupWindowWidth+',height='+this.popupWindowHeight+',menubar=no,toolbar=no,location=no,directories=no,status=no,resizable=no,scrollbars=no');
    }
    
    // Save the window pairs so that we can close them
    this.addPairedWindow(ctWindow, dealWindow);
    
    // Move and resize right away if it not chrome or IE as the window's sizes are there
    if (!this.isChrome && !Tx.isIE()) {
        this.moveAndResizeWindow();
    }
    else {
        // Then setup the timer
        setTimeout(this.moveAndResizeWindow, 400);
    }
    return dealWindow;
}

function productdetails_openRetailerWindow(url, dealUrl, extraParams)
{
    try {
        if (extraParams) {
            url += (url.indexOf('?') > -1 ? '&' : '?') + extraParams;
        }
        // Make the window name unique by uber id so each product opens in a new window.
        var id = Tx.getParameterFromUrl('id', url);
        
        var ctWindowName = 'ssretailer' + (id === null ? '' : id);
        // Note: we require these window options toforce FireFox2.0 to open in a new window.
        // see: http://www.websitedesignerslist.com/articles/The+Consequences+of+Firefox+2.0+Features+and+Default+Tabs+Settings/
        var ctWindow = window.open(url, ctWindowName, "menubar=yes,toolbar=yes,location=yes,directories=yes,resizable=yes,scrollbars=yes");
        
        if (dealUrl !== null) {
            // Popup deal window
            document.ssdeals.openDealWindow(ctWindow, dealUrl);
        }
    }
    catch (err) {
    }
    
    return false;
}

MProductDetailsContext.prototype.handleOpenDialog = function(linkElement)
{
    document.detailsContext.clearPendingTimeout();
    document.detailsContext.hideCurrentDetails();
    // if a color has been chosen, fiddle the product image parameter
    var colorToken = this.extractImageUrl(this._productImgUrl);
    var dest = linkElement.href;
    if (colorToken !== null) {
        dest = Tx.replaceParam(dest, 'objectParams', colorToken);
    }
    // Empty string for pendingOperationUrl means 'do not refresh page -- simply close the dialog'
    return SSDialog.openDialog(linkElement, dest, "");
};

// if a color has been chosen, fiddle the product image parameter.
// caller optionally can pass a detailsFetcher, for use by 'details' hover button
MProductDetailsContext.prototype.handleAddFavorite = function(linkElement, detailsFetcherDiv)
{
    var productImgUrl = (!detailsFetcherDiv ? this._productImgUrl : detailsFetcherDiv.productImgSrc);
    var colorToken = this.extractImageUrl(productImgUrl);
    if (colorToken !== null) {
        var dest = Tx.replaceParam(linkElement.href, 'image', colorToken);
        linkElement.href = dest;
    }

    SSFav.flashLink(linkElement);
};

///////////////////////
// Admin Integration
///////////////////////

var SSPDetails = {};

SSPDetails.handleMouseDown = function(event, productId, adminHost)
{
    if (event.shiftKey) {
        var newWindow = window.open(adminHost + '/Admin/app?service=page&page=QueryProductsPage&uberId=' + productId, 'ShopStyleAdmin');
        newWindow.focus();
    }
};

//////////////////////////////////////////////////////////////////////////////////////
// Below this point code executes upon parsing.  Above are all functions definitions.
//////////////////////////////////////////////////////////////////////////////////////

// For now, there's a single, global (per page) MProductDetailsContext

SSPDetails.singleton = new MProductDetailsContext();
SSPDetails.colorSizeContext = SSPDetails.singleton;

// productDetails needs to watch details context for show/hide
// (if productDetails was a kind of details, rather than independent, this would use methods-calling-super approach)
SSPDetails.showObserver = function() {
    SSPDetails.singleton.handleShowDetails();
};
SSPDetails.hideObserver = function() {
    SSPDetails.singleton.handleHideDetails();
};
document.detailsContext.observers.addObserver("show", SSPDetails.showObserver);
document.detailsContext.observers.addObserver("hide", SSPDetails.hideObserver);


