_skip_ = 0; // used on first line to allow setting breakpoints...

GalleryState =
{
    Idle:       'Idle',
    AniPending: 'AniPending',
    Animating:  'Animating',
    Slideshow:  'Slideshow',
    Invalid:    'Invalid'
}

GalleryAction =
{
    StartAniDelay: 'StartAniDelay',
    Animate:       'Animate',
    EndAnimation:  'EndAnimation',
    ShowSlideshow: 'ShowSlideshow',
    ShowThumbs:    'ShowThumbs' 
}

InitState = function(actions)
{
    var ar = [];
    ar[GalleryAction.StartAniDelay] = actions[0];
    ar[GalleryAction.Animate] =       actions[1];
    ar[GalleryAction.EndAnimation] =  actions[2];
    ar[GalleryAction.ShowSlideshow] = actions[3];
    ar[GalleryAction.ShowThumbs] =    actions[4];
    return ar;
}
                                           // StartAniDelay                        Animate                  EndAnimation           ShowSlideshow            ShowThumbs
GalleryStateMatrix = [];                   // -------------------------            -----------------------  ---------------------  -----------------------  ------------------------
GalleryStateMatrix[GalleryState.Idle] =       InitState([GalleryState.AniPending,  GalleryState.Animating,  GalleryState.Idle,     GalleryState.Slideshow,  GalleryState.Idle]);
GalleryStateMatrix[GalleryState.AniPending] = InitState([GalleryState.AniPending,  GalleryState.Animating,  GalleryState.Idle,     GalleryState.Slideshow,  GalleryState.Idle]);
GalleryStateMatrix[GalleryState.Animating]  = InitState([GalleryState.Invalid,     GalleryState.Animating,  GalleryState.Idle,     GalleryState.Slideshow,  GalleryState.Idle]);
GalleryStateMatrix[GalleryState.Slideshow]  = InitState([GalleryState.Invalid,     GalleryState.Invalid,    GalleryState.Invalid,  GalleryState.Slideshow,  GalleryState.Idle]);
GalleryStateMatrix[GalleryState.Invalid]    = InitState([GalleryState.Invalid,     GalleryState.Invalid,    GalleryState.Invalid,  GalleryState.Invalid,    GalleryState.Invalid]);

LangloWeb.ProductGalleryManager = function()
{
    this._state = GalleryState.Idle;
    this._growTimer = null;
    this._growTimerDelegate = null;
    this._growPanel = null;
    this._growPanelMouseOutDelegate = null;
    this._growImage = null;
    this._growInterval = 50;
    this._growDelta = 5;
    this._growMinHeight = 50;
    this._growMaxHeight = 90;
    this._growDelay = 300; // ms. before growstart
    this._pendingTimer = null;
    this._windowLoadDelegate = null;
    this.slideShowMgr = null;
}

LangloWeb.ProductGalleryManager.prototype = 
{
    getGrowPanel : function()
    {
        if (this._growPanel == null)
        {
            this._growPanel = $get('GrowPanel');
            if (this._growPanel != null)
            {
                this._growPanelMouseOutDelegate = Function.createDelegate(this, this.handleGrowPanelMouseOut);
                $addHandler(this._growPanel, 'mouseout', this._growPanelMouseOutDelegate);
            }
        }
        return this._growPanel;
    },
    
    getThumbsElement : function()
    {
        var myParentDiv = $get('Images');
        if (typeof myParentDiv != 'undefined')
        {
            var nodes = myParentDiv.childNodes;
            var len = nodes.length;
            var myDiv = null;
            // In Mozilla's DOM new lines are considered nodes
            for (var i = 0; i < len; i++)
            {
                if (nodes[i].nodeName == 'DIV')
                {
                    myDiv = nodes[i];
                    //We know there is only one div so we can jump out. 
                    break;
                } 
            }
            return myDiv;
        }
        else
            return null;
    },
    
    clearPendingTimer : function()
    {
        if (this._pendingTimer != null)
        {
            //Sys.Debug.trace("clearPendingTimer()");
            clearTimeout(this._pendingTimer);
            this._pendingTimer == null;
        }
    },
    
    clearGrowTimer : function()
    {
        if (this._growTimer != null)
        {
            //Sys.Debug.trace("clearGrowTimer()");
            clearTimeout(this._growTimer);
            this._growTimer == null;
        }
    },
    
    hideGrowPanel : function()
    {
        //Sys.Debug.trace("hideGrowPanel()");
        this.clearGrowTimer();
        var growPanel = this._growPanel;
        if (growPanel != null)
        {
            growPanel.onclick = null;
            growPanel.innerHTML = ''; 
            growPanel.style.height = 0;
            growPanel.style.width = 0;
        }
        this._growImage = null;
    },
    
    // Toggles visibility between the 2 major divs
    changeView : function(view) 
    {
        var thumbsDiv = $get('ThumbNails'); 
        var slideDiv = $get('SlideShow' ); 
        switch (view) 
        {
            case "Thumbs":
                thumbsDiv.style.display = ''; 
                slideDiv.style.display = 'none'; 
                break;
            case "Slideshow": 
                thumbsDiv.style.display = 'none';
                slideDiv.style.display = ''; 
                break;
        } 
    },

    // Transitions between states of the photo gallery
    transition : function(action)
    {
        //_skip_;
        var newState = GalleryStateMatrix[this._state][action];
        if (newState != this._state)
        {
            var msg = String.format('Old state = {0}, New state = {1}, Action = {2}',
                this._state, newState, action);
            //Sys.Debug.trace('Transition: ' + msg);
            if (newState == GalleryState.Invalid)
                throw Error.invalidOperation('Invalid state change. ' + msg);
            switch (this._state) // the old state
            {
                case GalleryState.Idle:
                    break;
                case GalleryState.AniPending:
                    this.clearPendingTimer();
                    break;
                case GalleryState.Animating:
                    this.hideGrowPanel();
                    break;
                case GalleryState.Slideshow:
                    this.slideShowMgr.deactivate(); 
                    this.changeView("Thumbs"); 
                    break;
                default:
                    throw Error.invalidOperation('Attempted to change state when state was already invalid');
            }
            this._state = newState;
            switch (this._state) // the new state
            {
                case GalleryState.Idle:
                    break;
                case GalleryState.AniPending:
                    break;
                case GalleryState.Animating:
                    break;
                case GalleryState.Slideshow:
                    this.changeView("Slideshow"); 
                    break;
                default:
                    throw Error.invalidOperation('Attempted to change state when state was already invalid');
            }
        }
    },
    
    // Grows the thumbImage 1 step
    growThumbImage : function()
    {         
        //Sys.Debug.trace('growThumbImage()');
        if (this._state != GalleryState.Animating)
            return; // Animation ended while we were waiting for the next step
        var img = this._growImage;
        if (img != null)
        {
            var pnl = this.getGrowPanel();
            if (pnl != null)
            {               
                var ratio = img.ratio;
                var maxHeight = this._growMaxHeight;
                if (img.height < maxHeight)
                {
                    // Resize
                    img.height += this._growDelta;
                    img.width = img.height / ratio;
                    // Reposition
                    var yDelta = this._growDelta / 2;
                    pnl.imgY -= yDelta;
                    pnl.imgX -= yDelta / ratio;
                    pnl.style.left = pnl.imgX + 'px';
                    pnl.style.top = pnl.imgY + 'px';
                }
                if (img.height < maxHeight)
                    this.scheduleNextGrow();
            }
        }
    }, 

    scheduleNextGrow : function()
    {
        if (this._growTimerDelegate == null)
            this._growTimerDelegate = Function.createDelegate(this, this.growThumbImage);
        this._growTimer = setTimeout(this._growTimerDelegate, this._growInterval);
    },
    
    insertGrowImage : function(growPanel, growImage)
    {
        //In Mozilla's DOM height is not always there. 
        if (growImage.height > 0) 
        {
            var ratio = growImage.height / growImage.width;
            growImage.ratio = ratio;    
            growImage.width = this._growMinHeight / ratio;
        }
        else 
        {
            growImage.ratio = 1; 
            growImage.width = this._growMinHeight;
        }
        growImage.height = this._growMinHeight;
        // add the image to the panel
        growPanel.innerHTML = '';    
        growPanel.appendChild(growImage);
    },
    
    setupGrowPanel : function(thumbImage)
    {
        if (thumbImage == null)
            throw Error.argumentNull('Null argument passed to setupGrowPanel method');
        var growPanel = this.getGrowPanel();
        if (growPanel == null)
            throw Error.invalidOperation('Unable to find growPanel from setupGrowPanel method');

        // Set onclick first to ensure we catch all clicks (not sure if it helps)
        growPanel.onclick = thumbImage.onclick;
        var x = photoHelper.findPosX(thumbImage);    
        var y = photoHelper.findPosY(thumbImage); 
        growPanel.style.left = x + 'px';
        growPanel.style.top = y + 'px';
        growPanel.imgX = x;
        growPanel.imgY = y;
        growPanel.style.height = thumbImage.height;
        growPanel.style.width = thumbImage.width;
        growPanel.style.position = 'absolute';
        this._growMinHeight = thumbImage.height;

        var img = document.createElement('img');
        
        img.id = 'GrowImage';
        img.imageId = thumbImage.imageId;
        // Height and width are only in IE they must be set in other browsers. 
        img.height = thumbImage.height; 
        img.width = thumbImage.width; 
        Sys.UI.DomElement.addCssClass(img, "GrowPhotoWithBorder");

        return img;
    },
    
    // Called asynchronously via thumbImage.onLoad after animation kickoff
    setupThumbAnimation : function(thumbImage)
    {           
        var growPanel = this.getGrowPanel();
        var growImage = this.setupGrowPanel(thumbImage);
        growImage.animationStarted = false; // for re-entrancy reasons
        this._growImage = growImage;
        var doOnLoaded = function(thisContext) 
            {
                //Sys.Debug.trace('growImage.onLoad()');
                if (thisContext._state == GalleryState.Animating && !growImage.animationStarted)
                {
                    growImage.animationStarted = true;
                    thisContext.insertGrowImage(growPanel, growImage);
                    thisContext.scheduleNextGrow();
                }
            };
        var doOnErrorOrAbort = function(thisContext)
            {
                //Sys.Debug.trace('growImage.onError/Abort()');
                thisContext.transition(GalleryAction.EndAnimation);
            };

        var imageId = thumbImage.imageId; 
        if (typeof imageId == 'undefined')
            imageId = thumbImage.getAttribute('imageId'); 
        var src = photoHelper.getLoaderURL(imageId, 200); 
        photoHelper.loadImage(this, growImage, src, doOnLoaded, doOnErrorOrAbort, doOnErrorOrAbort);
    },

    // Callback for timeout delay on thumbnail mouseover.
    kickOffAnimation: function(thumbImage)
    {
        //_skip_;
        this.transition(GalleryAction.Animate);
        // Ensure image is loaded
        var onLoaded = function(thisContext, isthisanimage)
            {
                Sys.Debug.trace('thumbImage.onLoad()');
                if (thisContext._state == GalleryState.Animating)
                {
                    thisContext.setupThumbAnimation(thumbImage);
                }
            };
        var onError = function(thisContext)
            {
                Sys.Debug.trace('thumbImage.onError/Abort()');
                if (thisContext._state == GalleryState.Animating)
                    thisContext.transition(GalleryAction.EndAnimation);
            };
        var onAbort = onError;
        photoHelper.handleImageLoad(this, thumbImage, onLoaded, onError, onAbort);
    },
    
    // Resets all thumbs to display again 
    showAllThumbs : function(thumbsDiv) 
    {
        var len = thumbsDiv.childNodes.length;
        for (var i = 0; i < len; i++) 
        {
            var node = thumbsDiv.childNodes[i];
            if (node.nodeName == 'IMG')
                node.style.display = '';
        }
    },

    // Show all thumbs containing all provided tags    
    showThumbsHavingTags : function(tags) 
    {
        var thumbsDiv = this.getThumbsElement();
        if (thumbsDiv != null)
        {
            this.showAllThumbs(thumbsDiv);
            var tagArray = tags.split('+'); 
            var len = tagArray.length;
            for (var i = 0; i < len; i++) 
                this.removeThumbsWithoutTag(tagArray[i], thumbsDiv); 
        }
    },

    // Hides all thumbnails which DON'T contain the provided tag. thumbsDiv is an optional argument.
    removeThumbsWithoutTag : function(tag, thumbsDiv) 
    {
        //_skip_;
        if (tag != null) 
        {
            if (typeof thumbsDiv == 'undefined')
                thumbsDiv = this.getThumbsElement();
            if (thumbsDiv != null)
            {
                var regex = new RegExp(tag); 
                var len = thumbsDiv.childNodes.length;
                for (var i = 0; i < len; i++) 
                {
                    var node = thumbsDiv.childNodes[i];
                    if (node.nodeName == 'IMG' && node.style.display != 'none')
                        node.style.display = regex.test(node.longDesc) ? '' : 'none';
                }
            }
        }
    }, 
    
    showThumbnails : function() 
    { 
        this.transition(GalleryAction.ShowThumbs);
    },

    showSlideshow : function(imageId) 
    {
        this.transition(GalleryAction.ShowSlideshow);
        this.slideShowMgr.activate(imageId);
    },
    
    // handles the mouse out event for the growpanel (incl. the embedded growimage).
    handleGrowPanelMouseOut : function(sender)
    {
        //_skip_;
        //Sys.Debug.trace('growPanel.onMouseOut() - ' + event.srcElement.id);
        this.transition(GalleryAction.EndAnimation);
    },

    // Handler for window.onload event. Used when user is specifying a big image in the query string
    handleFullImageLoad : function(sender, args)
    {
        if (this._windowLoadDelegate != null)
        {
            $removeHandler(window, 'load', this._windowLoadDelegate);
            this._windowLoadDelegate = null;
        }
        var modalPopup = $find('BigImageBehavior');        
        if (modalPopup) 
        {
            modalPopup.show();
            this.slideShowMgr.showFullPageImage(); 
        }
        else
        {
            var loadDelegate = Function.createDelegate(this, this.handleFullImageLoad);
            setTimeout(loadDelegate, 100);                
        }
    },
    
    // handles the mouse out event for the thumbnails (assigned on server).
    handleThumbMouseOut : function(sender)
    {
        //_skip_;
        //Sys.Debug.trace('thumbImage.onMouseOut() - ' + event.srcElement.id + ' - ' + event.type);
        if (this._growImage != null && this._growImage.animationStarted)
        {
            /* After the growpanel has been displayed, the thumb's mouseout event will be raised as 
             * soon as the mouse is moved (even a 1px move). The if clause above filters out this 
             * case. The growpanel's mouseout event will instead take care of transitions. */        
        }
        else
            if (this._state == GalleryState.Slideshow)
            {
                /* If the user clicks the thumb before animation has started, the slideshow should 
                 * start immediately. At this point we also get a mouseout event here (which we'll ignore). */
            }
            else
                this.transition(GalleryAction.EndAnimation);
    },

    // Assigned to thumbs on server
    handleThumbMouseOver : function(thumbImage)
    {
        //_skip_;
        //Sys.Debug.trace('thumbImage.onMouseOver() - ' + event.srcElement.id);
        this.transition(GalleryAction.StartAniDelay);
        var thisContext = this;
        var callback = function()
        {
            //Sys.Debug.trace('pendingTimer.callback()');
            // Ensure state didn't change while we were waiting.
            if (thisContext._state == GalleryState.AniPending)
                thisContext.kickOffAnimation(thumbImage);
        };
        this._pendingTimer = setTimeout(callback, this._growDelay);
    },
     
    // Assigned to thumbs on server
    handleThumbClick : function(imageId)
    {
        _skip_; 
        // Since sender is the grow panel and it is not always populated and Mozilla does not have the event variable 
        // adding the imageId to the function call seemed the simplest. 
        //Sys.Debug.trace('thumbImage.onClick() - ' + event.srcElement.id);
        this.showSlideshow(imageId);
    },
    
    // See initPhotoGallery function at the bottom of this file for info
    initialize : function(initialPhotoView, initialPhotoId, thumbnailHeight)
    {
        this.slideShowMgr = new LangloWeb.SlideShowManager(this);
        this._growMaxHeight = thumbnailHeight * 1.8; // 80% increase
        this.getGrowPanel();
        switch (initialPhotoView)
        {
            case 'Slideshow': 
                this.showSlideshow(initialPhotoId);
                break; 
            case 'BigPhoto': 
                this.showSlideshow(initialPhotoId);
                // Page needs to be loaded to ensure the modal behavior is loaded. 
                this._windowLoadDelegate = Function.createDelegate(this, this.handleFullImageLoad);
                $addHandler(window, 'load', this._windowLoadDelegate);
                break;
            case "Thumbnails":
            default:
                break;
        }
    },
    
    // See disposePhotoGallery function at the bottom of this file for info
    dispose : function()
    {
        //_skip_;
        if (this._growPanel != null)
        {
            this.transition(GalleryAction.ShowThumbs);
            $removeHandler(this._growPanel, 'mouseout', this._growPanelMouseOutDelegate);
            this._growPanelMouseOutDelegate = null;
            this._growPanel = null;
        }
        this.clearPendingTimer();
        this.clearGrowTimer();
        this._growImage = null;
        this._growTimerDelegate = null;
        if (this.slideShowMgr != null)
        {
            this.slideShowMgr.dispose();
            this.slideShowMgr = null;
        }
    }
}
LangloWeb.ProductGalleryManager.registerClass('LangloWeb.ProductGalleryManager'); 


LangloWeb.PhotoHelper = function() { }

LangloWeb.PhotoHelper.prototype = 
{
    getLoaderURL : function(aId, aHeight, aWidth, aScale)
    {
        // Fix "undefined" parameters here to avoid cpu intensive exceptions on the server. Such
        // exceptions will be handled okay on the server, but not without cost.
        var widthStr = typeof aWidth != 'undefined' ? "&w=" + aWidth : "";
        var scaleStr = typeof aScale != 'undefined' ? "&s=" + aScale : "";
        // TODO Localize ImageService (we're ok for now by using "ImageService" in Norwegian as well)
        var url =  "/ImageService?id=" + aId + "&h=" + aHeight + widthStr + scaleStr;
        url = url.replace(/&amp;/g, '&'); // Sme browsers will use the unicode character in place of the ascii.         
        return url; 
    },      

    // position finding functions
    findPosX : function(obj)
    {
        var curleft = 0;
        if (obj.offsetParent)
        {
            while (obj.offsetParent)
            {
	            curleft += obj.offsetLeft
	            obj = obj.offsetParent;			    
            }		    
        }
        else 
            if (obj.x)
                curleft += obj.x;		    
        return curleft;
    },

    findPosY : function(obj)
    {  
        var curtop = 0;	
        if (obj.offsetParent)
        {
            while (obj.offsetParent)
            {			
	            curtop += obj.offsetTop
	            obj = obj.offsetParent;
            }
        }
        else 
            if (obj.y)
                curtop += obj.y;		
        return curtop;
    },
    
    handleImageLoadPrim : function(thisContext, img, doOnLoaded, doOnError, doOnAbort)
    {
        if (typeof doOnLoaded != 'undefined' && doOnLoaded != null)
        {
            img.onload = 
                function()
                {
                    if (img.complete)
                        doOnLoaded(thisContext)
                    else
                    {
                        /* It appears (at least with IE7) that complete will not be set to true
                         * until the current execution stack has been fully popped. (TL, 08/04/17) */
                        var handleTimeout = function() 
                        { 
                            doOnLoaded(thisContext);
                        };
                        setTimeout(handleTimeout, 0);
                    }
                };
        }
        if (typeof doOnError != 'undefined' && doOnError != null)
            img.onerror = function() { doOnError(thisContext) };
        if (typeof doOnAbort != 'undefined' && doOnAbort != null)
            img.onabort = function() { doOnAbort(thisContext) };
    },
    
    // For use when img.src has already been assigned, and we need to take some
    // action when the image has loaded. This function will ensure that the doOnLoaded
    // callback will also be called if the image has already been fully loaded.
    handleImageLoad : function(thisContext, img, doOnLoaded, doOnError, doOnAbort)
    {
        if (img != null)
        {
            if (img.src != null && img.src != "" && img.complete && 
                typeof doOnLoaded != 'undefined' && doOnLoaded != null)
            {
                doOnLoaded(thisContext);
            }
            else
                this.handleImageLoadPrim(thisContext, img, doOnLoaded, doOnError, doOnAbort);
        }
    },
    
    // For use when loading a image with a new or different src.
    loadImage : function(thisContext, img, src, doOnLoaded, doOnError, doOnAbort)
    {
        if (img != null && src != null && src != "")
        {
            // Set event handlers before assigning img.src
            this.handleImageLoadPrim(thisContext, img, doOnLoaded, doOnError, doOnAbort);
            img.src = src;
            // For browsers which don't call img.onLoad under all circumstances
            if (img.complete)
                doOnLoaded(thisContext);
        }
    },
    
    incOpacity : function(obj, delta) 
    {
        return this.setOpacity(obj, obj.xOpacity += delta);
    },
    
    setOpacity : function(obj, opacity) 
    {
        opacity = opacity >= 1 ? 0.999 : (opacity < 0 ? 0 : opacity);
        obj.xOpacity = opacity;
        obj.style.opacity = opacity;
        obj.style.MozOpacity = opacity;
        obj.style.filter = "alpha(opacity=" + (opacity * 100) + ")";
        return opacity;
    }
}
LangloWeb.PhotoHelper.registerClass('LangloWeb.PhotoHelper'); 

photoHelper = new LangloWeb.PhotoHelper();
// declare and set to null, initialize in initPhotoGallery function above
prodGalleryMgr = null;

// Is called from server side generated script which is only emitted when the photo gallery is made visible.
function initPhotoGallery(initialPhotoView, initialPhotoId, thumbnailHeight)
{
    if (prodGalleryMgr == null)
        prodGalleryMgr = new LangloWeb.ProductGalleryManager();
    prodGalleryMgr.initialize(initialPhotoView, initialPhotoId, thumbnailHeight);
}
 
// Is called from server side generated script. The function is called whenever a containing
// UpdatePanel detects that the PhotoGallery user control is being disposed.
function disposePhotoGallery()
{
    if (prodGalleryMgr != null)
        prodGalleryMgr.dispose();
}

if (typeof(Sys) !== 'undefined')
    Sys.Application.notifyScriptLoaded();

