
Type.registerNamespace('BlueBridge.SharePointExtensions.MasterPages.Ajax');

BlueBridge.SharePointExtensions.MasterPages.Ajax.HierarchicalMenuBehavior = function(element) 
{
    BlueBridge.SharePointExtensions.MasterPages.Ajax.HierarchicalMenuBehavior.initializeBase(this, [element]);
    
    // Property values
    this._DynamicControlSrc = null;
    this._hoverCssClass = null;
    this._fadeInAnimate = true;
    this._framesPerSecond = 250;
    this._animationDuration = 2000;
    
    // Handler delegates
    this._mouseOverHandler = null;
    this._mouseOutHandler = null; 
    this._tickHandler = null;   
    
    // State variables
    this._oldLayer = null;
    this._hoveredItem = null;
    this._oldClass = null;
    this._animation = null;
    this._timer = null;
    this._callID = 0;
    this._currentCallID = -1;
    this._cache = null;
    this._callInProc = null;
    this._batchCallInProc=false;
}

BlueBridge.SharePointExtensions.MasterPages.Ajax.HierarchicalMenuBehavior.prototype = 
{
    //------------------------------------------------------------------------- 
    initialize : function() 
    //------------------------------------------------------------------------- 
    {
        BlueBridge.SharePointExtensions.MasterPages.Ajax.HierarchicalMenuBehavior.callBaseMethod(this, 'initialize');

        var element = this.get_element();
        var list    = element.getElementsByTagName('UL');
        
        if(list != null) 
        {
            // Create delegates
            this._mouseOutHandler = Function.createDelegate(this, this._onMouseOut);
            this._mouseOverHandler = Function.createDelegate(this, this._onMouseOver);
            this._tickHandler = Function.createDelegate(this, this._onTimerTick);
            
            // Initialize list menu
            this.initializeList(list);
            
            // Initialize timer
            this._timer = new Sys.Timer();
            this.initializeTimer(this._timer);
            
            //Create a new parent for dynamic element
            var dynamicElement = $get(this._DynamicControlID);            
            this._cache = {};
            this._cache[0] = this._DynamicControlID;
            this._oldLayer = dynamicElement;            
            
            jslog.info ("Preloading rollover content");
            //debugger;
            
            // pre-populate elements
            this.initializeContent(list);
        }
    },
    //------------------------------------------------------------------------- 
    dispose : function()
    //------------------------------------------------------------------------- 
    {
        /// <summary>
        /// Disposes the hover/unhover behaviors
        /// </summary>
        /// <returns />
        var populateTrigger = this.get_element();

        this._mouseOverHandler = null;
        this._mouseOutHandler = null;
        
        if(this._animation)
            this._animation.dispose();
            
        if (this._timer) 
        {        
            this._timer.dispose();
            this._timer = null;
        }

        BlueBridge.SharePointExtensions.MasterPages.Ajax.HierarchicalMenuBehavior.callBaseMethod(this, 'dispose');
    },
    get_DynamicControlSrc : function() 
    {
        return this._DynamicControlSrc;
    },
    set_DynamicControlSrc : function(value) 
    {
        if (this._DynamicControlSrc != value) 
        {
            this._DynamicControlSrc = value;
            this.raisePropertyChanged('DynamicControlSrc');
        }
    },
    get_hoverCssClass : function() 
    {
        return this._hoverCssClass;
    },
    set_hoverCssClass : function(value) 
    {
        if (this._hoverCssClass != value) 
        {
            this._hoverCssClass = value;
            this.raisePropertyChanged('HoverCssClass');
        }
    },
    
    get_fadeInAnimate: function() 
    {
        return this._fadeInAnimate;
    },
    set_fadeInAnimate: function(value) 
    {
        this._fadeInAnimate = value;
        this.raisePropertyChanged('FadeInAnimate');
    },
    
    get_animationDuration: function() 
    {
        return this._animationDuration;
    },

    set_animationDuration: function(value) 
    {
        this._animationDuration = value;
        this.raisePropertyChanged('AnimationDuration');
    },
    get_framesPerSecond: function() 
    {
        return this._framesPerSecond;
    },

    set_framesPerSecond: function(value) 
    {
        this._framesPerSecond = value;
        this.raisePropertyChanged('FramesPerSecond');
    },
    
    //-------------------------------------------------------------------------
    // Pre-loads all elements for the list
    //-------------------------------------------------------------------------
    initializeContent : function (ulElements)
    //-------------------------------------------------------------------------
    {
        var urlList = "###";   // Batch parameter starts with ###
        for(var indexU = 0; indexU < ulElements.length; indexU++)
        {
            var ulElement  = ulElements[indexU];
            var liElements = ulElement.getElementsByTagName("li");
            
            /*
            for(var index = 0; index < liElements.length; index++)
            {
                var liElm = liElements[index].getElementsByTagName("A")[0];
                var num = liElm.ord;
                this._hoveredItem = liElm;
                this._populate(liElm.href,num);
            }
            */
            
            for(var index = 0; index < liElements.length; index++)
            {
                var liElm = liElements[index].getElementsByTagName("A")[0];
                urlList += liElm.ord;
                urlList += "###";
                urlList += liElm.href;
                urlList += "###";
            }
        }
        
        urlList = urlList.substring (0, urlList.length-3);
        jslog.debug ("(initializeContent) Sending batch request, length="+urlList.length);
        this._populateBatch(urlList);
    },
    //-------------------------------------------------------------------------
    // Initializes the list element.
    //-------------------------------------------------------------------------
    initializeList : function(ulElms)
    //------------------------------------------------------------------------- 
    {
        var mouseOutHandler = this._mouseOutHandler;
        var mouseOverHandler = this._mouseOverHandler;

        jslog.info ("Initializing list.");

        for(var indexU = 0; indexU < ulElms.length; indexU++)
        {
            var ulElm  = ulElms[indexU];
            var liElms = ulElm.getElementsByTagName("li");
            
            for(var index = 0; index < liElms.length; index++)
            {
                var liElm = liElms[index].getElementsByTagName("A")[0];
                liElm.ord = indexU + "." + (index + 1);

//                $addHandler(liElm, "mouseover", mouseOverHandler);

                liElm.onmouseover = function (ev)
                {
                    mouseOverHandler(this, ev);
                    return false;
                };
                
                jslog.debug ("Added mouseover handler to element: "+liElm.outerHTML);
            }
            
//            $addHandler(ulElm, "mouseout", mouseOutHandler);
            ulElm.parentNode.onmouseout = function (ev)
            {
                mouseOutHandler(this, ev);
                return false;
            };
        }

    },
    // Initializes the timer
    //------------------------------------------------------------------------- 
    initializeTimer: function(timer) 
    //------------------------------------------------------------------------- 
    {
        timer.set_interval(300);
        timer.add_tick(this._tickHandler);
    },
    // Handler invoked when a timer tick occurs
    //-------------------------------------------------------------------------
    _onTimerTick : function(sender, eventArgs) 
    //-------------------------------------------------------------------------
    {
         if(this._hoveredItem != null)
            this._fireHover(this._hoveredItem); 
    },
    //------------------------------------------------------------------------- 
    _onMouseOver : function(sender, args) 
    //------------------------------------------------------------------------- 
    {
        if(sender != null)
        {
            var hoveredItem =  sender;
            if((hoveredItem.tagName != 'A') || !(hoveredItem.ord)) 
		        return;
		        
		    var oldNum = this._hoveredItem == null ? 0 : this._hoveredItem.ord;
		    var newNum = hoveredItem.ord;   
		    
		    if(newNum == oldNum)
		        return;

		    this._hoveredItem = hoveredItem;
		    
            var e = this.get_element();
            if (this._hoverCssClass && e.className != this._hoverCssClass) 
            {
                this._oldClass = e.className;
                e.className = this._hoverCssClass;
            }
            
            if(this._cache[newNum] != null)
                this._fireHover(hoveredItem);
            else
            
		        this._timer.set_enabled(true);
        }  
    },
    //------------------------------------------------------------------------- 
    // Makes the current marketing zone div visible and the last one invisible
    //------------------------------------------------------------------------- 
    _fireHover : function(hoveredItem) 
    //------------------------------------------------------------------------- 
    {
	    var newLayer = null;
	    var newNum = hoveredItem.ord;  
	    var newLayerId = this._cache[newNum];
	    
	    // check if swap content is already loaded
	    if ((this._callInProc!==null) && (this._callInProc[newNum]))
	    {
		    jslog.debug ("Unable to switch to element #"+num+", loading in progress...");
		    return;
	    }
	    if ((this.batchCallInProc!==null) && (this.batchCallInProc))
	    {
		    jslog.debug ("Batch call in progress, _populate aborted.");
		    return;
	    }
	    
	    
        if(newLayerId)
	        newLayer = $get(newLayerId);

	    if(newLayer != null)
	    {
	        this._switchLayer(newLayer, true);    
	    }
	    else
	    {
            var linkItem = hoveredItem/*.getElementsByTagName('A')[0]*/;
            var href = linkItem.href;
            var num = this._hoveredItem.ord;
            if(href)
                this._populate(href,num);
	    }
    },
    //--------------------------------------------------------------------------- 
    // Exchanges the currently shown layer in the header zone with the given one
    //--------------------------------------------------------------------------- 
    _switchLayer : function(newLayer, animate) 
    //------------------------------------------------------------------------- 
    {
        this._timer.set_enabled(false);
        
        // Initialize animation
        if(this._animation && this._animation.get_isPlaying())
            this._animation.stop();
            
        if(this._oldLayer)
            $common.setVisible(this._oldLayer, false); 
        this._oldLayer = newLayer;

        $common.setVisible(newLayer, true);

        if(newLayer && animate) 
        {
            if(this._fadeInAnimate && this._animationDuration)
            {
                    var image = newLayer.getElementsByTagName('IMG')[0];
                    if(image != null)
                    {
                        if(this._animation == null)
                        {
                            this._animation = new $AA.FadeAnimation(
                            image, // target 
                            this._animationDuration/1000, // duration in seconds
                            this._framesPerSecond, // number of frames per second
                            $AA.FadeEffect.FadeIn, // fade effect
                            0, // minimum opacity
                            1, // maximum opacity
                            Sys.Browser.InternetExplorer == Sys.Browser.agent // force layout: should be true in IE!
                            );
                        }
                        else
                        {
                            this._animation.set_target(image);       
                        }
                        
                        this._animation.play();
                    }
            
            }
                
        
        }


    },
    //---------------------------------------------------------------------------
    // Triggers a backend call for loading the marketing zone content for all
    // list entries (batch mode).
    //
    // Params
    // * contextKey = Url of the hovered link (makes no sense here)
    // 
    // Remarks
    // * Result is processed in OnCallbackComplete (calls --> _onMethodComplete)
    //---------------------------------------------------------------------------
    _populateBatch : function(contextKey)
    //---------------------------------------------------------------------------
    {
        // TODO: CallInProc processing
        this._currentCallID = ++this._callID;
        if (this._DynamicServicePath && this._DynamicServiceMethod) 
        {
            jslog.error ("Unsupported operation in _populateBatch: Dynamic Service");
        }
        else if (this._DynamicControlSrc)
        {
            var context = {};
            context.id = this._id;
            context.currentCallID = this._currentCallID;
            context.hoveredItem = this._hoveredItem;  // TODO: Makes no sense here
            jslog.debug ("Backend request #"+this._currentCallID+": Batch request all items");
            jslog.debug ("... contextKey length="+contextKey.length);
            this._batchCallInProc = true;
            HierarchicalMenuExtender_DoCallback(context, contextKey);  
        }
        else
        {
            jslog.error ("Unable to populate (batch), you need the dynamic service or dynamic control.");
        }
    },
    //---------------------------------------------------------------------------
    // Triggers a backend call for loading the marketing zone content for a list
    // entry.
    //
    // Params
    // * contextKey = Url of the hovered link
    // * num = Number of the hovered item
    // 
    // Remarks
    // * Result is processed in OnCallbackComplete (calls --> _onMethodComplete)
    //---------------------------------------------------------------------------
    _populate : function(contextKey,num)
    //------------------------------------------------------------------------- 
    {
        if(this._callInProc == null)
            this._callInProc = {};
            
        if(this._callInProc[num])
        {
            jslog.debug ("Call for element #"+num+" in progress, _populate aborted.");
            return;
        }
        
        if(this.batchCallInProc)
        {
            jslog.debug ("Batch call in progress, _populate aborted.");
            return;
        }

        this._currentCallID = ++this._callID;
        if (this._DynamicServicePath && this._DynamicServiceMethod) 
        {
            Sys.Net.WebServiceProxy.invoke(this._DynamicServicePath, this._DynamicServiceMethod, false,
            { contextKey:(contextKey ? contextKey : this._contextKey) },
            Function.createDelegate(this, this._onMethodComplete), Function.createDelegate(this, this._onMethodError),
            this._currentCallID);
        }
        else if(this._DynamicControlSrc)
        {            
            var context = {};
            context.id = this._id;
            context.currentCallID = this._currentCallID;
            context.hoveredItem = this._hoveredItem;
            jslog.debug ("Backend request #"+this._currentCallID+": List item no: "+num);
            jslog.debug ("... contextKey="+contextKey);
            HierarchicalMenuExtender_DoCallback(context, contextKey);          
        }
        else
        {
            jslog.error ("Unable to populate, you need the dynamic service or dynamic control.");
        }
    
        this._callInProc[num] = true;
        
        $common.updateFormToRefreshATDeviceBuffer();
    },
    //------------------------------------------------------------------------- 
    // Calls "FireUnhover" if the list is left completely
    //------------------------------------------------------------------------- 
    _onMouseOut: function(sender, args) 
    //------------------------------------------------------------------------- 
    {
//		if(sender.tagName != 'UL') 
//		    return;
        
        // Rectangle check: Is the mouse moved inside the list or out of the list?
        //var rect = sender.getBoundingClientRect();

        var bounds = Sys.UI.DomElement.getBounds(sender);

        var mouseX = typeof args!=="undefined" ? args.clientX : window.event.clientX;
        var mouseY = typeof args!=="undefined" ? args.clientY : window.event.clientY;
        
        //if ((rect.left<=mouseX) && (rect.right>=mouseX) && (rect.top<=mouseY) && (rect.bottom>=mouseY))
        var bLeft = bounds.x + 2;
        var bRight = bLeft + bounds.width;
        var bTop = bounds.y + 2;
        var bBottom = bTop + bounds.height;
        
        if ((bLeft <= mouseX) && (bRight >= mouseX) &&
           (bTop <= mouseY) && (bBottom >= mouseY))
        {
            // inside
            return;
        }
        
		this._hoveredItem = null;  
        window.setTimeout(Function.createDelegate(this, this._fireUnhover), 1000);  // todo: 1000 milliseconds may  be too much
    },   
    //------------------------------------------------------------------------- 
    // Unhover:
    // * resets the CSS class of the link
    // * sets cached content #0 for the marketing zone
    //------------------------------------------------------------------------- 
    _fireUnhover : function() 
    //------------------------------------------------------------------------- 
    {    
        if(this._hoveredItem != null)
		    return;
        
        var e = this.get_element();
        if (this._hoverCssClass && e.className == this._hoverCssClass) 
            e.className = this._oldClass;
            
	    var newLayer = $get(this._cache[0]);        

        this._switchLayer(newLayer, false) ;
    },
    //------------------------------------------------------------------------- 
    // Finds the order number for a navigation element
    //------------------------------------------------------------------------- 
    _findNavigationElement : function (navigationUrl)
    //------------------------------------------------------------------------- 
    {
        // TODO: Can be removed
        if (!navigationUrl)
        {
            return -1;
        }
        
        var element = this.get_element();
        var ulElms  = element.getElementsByTagName('UL');
        
        if(ulElms != null) 
        {
            for(var indexU = 0; indexU < ulElms.length; indexU++)
            {
                var ulElm  = ulElms[indexU];
                var liElms = ulElm.getElementsByTagName("li");
                
                for(var index = 0; index < liElms.length; index++)
                {
                    var liElm = liElms[index].getElementsByTagName("A")[0];
                    if (liElm.href == navigationUrl)
                    {
                        return liElm.ord;
                    }
                }
            }
        }
        
        // nothing found
        return -1;
    },
    //------------------------------------------------------------------------- 
    // Used to add the sections that have been dynamically loaded
    //
    // Params:
    // * num = generated section number from the list's link element (used for div name)
    // * content = generated content (from backend) to add
    //------------------------------------------------------------------------- 
    _addLoadedSection : function (num,content)
    //------------------------------------------------------------------------- 
    {
        try
        {
            var parentElement = $get(this._DynamicControlID).parentNode;
            var childElement = document.createElement('DIV');
            var childElementId = this._DynamicControlID + "layer" + num;
            parentElement.appendChild(childElement);            
            childElement.innerHTML = content;
            childElement.setAttribute('id', childElementId);
            var className = $get(this._DynamicControlID).className;
            if(className)
                childElement.className = className;
            
            // TODO:  What does this do? 
            this.raisePopulated(this, Sys.EventArgs.Empty);
            
            $common.setVisible($get(childElementId), false); // will be made visible later
            
            if (num>=0)
            {
              this._cache[num] = childElementId;
            }
        }
        catch (ex)
        {
            jslog.error ("Exception thrown in _addLoadedSection: "+ex);
        }
    },
    //------------------------------------------------------------------------- 
    // Processes the result of a backend callback:
    // * Creates a div for the returned html content and adds it to the
    //   div or element with id "DynamicControlId"
    // * Triggers "raisePopulated"
    // * Hides the new element
    //
    // Params
    // * result:       Contains rendered HTML content for the marketing zone
    //                 Format: URL###RenderedHtml
    // * userContext:  Canonical ajax context argument
    // * methodName:   Always NULL!?
    //
    //------------------------------------------------------------------------- 
    _onMethodComplete : function (result, userContext, methodName) 
    //------------------------------------------------------------------------- 
    {
        var num = -1;
        var splitterIndex = 0;
        var resultUrl;
        
        //debugger;
        
        if ((result.length>=3) && (result.substring(0,3)=="###"))
        {
            // split
            var resultElements = result.split ("###");  // array contains [number,htmlcontent] pairs
            
            // need to start at index 1 because of the leading ###, split returns an empty first section
            jslog.debug ("Batch call returned "+(resultElements.length-1)/2+" sections");
            
            // fill
            for (var i=1; i<resultElements.length; i++)
            {
                /*
                if (resultElements[i].length<15)
                {
                    jslog.debug ("Result processing: Element #"+i+" = '"+resultElements[i]+"'");
                }
                else
                {
                    jslog.debug ("Result processing: Element #"+i+" = '"+resultElements[i].substring(0,15)+"'");
                }
                */
                if ((resultElements[i].length>0) && (resultElements[i]!="###"))
                {
                    if (i%2)
                    {
                      // number
                      num = resultElements[i];
                    }
                    else
                    {
                      // html content
                      jslog.debug ("Putting section #"+num+" into cache");
                      this._addLoadedSection (num, resultElements[i]);
                      
                    }
                }
            }
            
            
            
            jslog.info ("Finished batch. Calling SIFR.");
            
            // reset semaphore
            this._batchCallInProc = false;
        }
        else
        {
            // result is single item        
            
            // TODO: Move into addLoadedSection
            
            try
            {
                num = userContext.hoveredItem.ord;
            }
            catch (exc)
            {
                // only happens if no menu items. Set number to zero as fallback
                num=0;
            }
            jslog.info ("Backend sent content for list item #"+num);

            // TODO: Check
            if(this._cache[num]!= null)
                return;  // Do not update already cached items
     
            var parentElement = $get(this._DynamicControlID).parentNode;
            var childElement = document.createElement('DIV');
            var childElementId = this._DynamicControlID + "layer" + num;
            parentElement.appendChild(childElement);            
            childElement.innerHTML = result.substring(splitterIndex+3);
            childElement.setAttribute('id', childElementId);
            var className = $get(this._DynamicControlID).className;
            if(className)
                childElement.className = className;
            this._callInProc[num] = null;
            
            
            // TODO:  What does this do? 
            this.raisePopulated(this, Sys.EventArgs.Empty);
            
            $common.setVisible($get(childElementId), false); // will be made visible later
            
            if (num>=0)
            {
              this._cache[num] = childElementId;
            }
        }
    },
    //-------------------------------------------------------------------------
    _onMethodError : function(webServiceError, userContext, methodName) 
    //-------------------------------------------------------------------------
    {
        if (userContext.currentCallID != this._currentCallID) return;

        var e = this.get_element();
        if (e && webServiceError != null) 
        {
            e.innerHTML = "<div class=\"error\">" + webServiceError + "<\/div>";
        }
    }
}

BlueBridge.SharePointExtensions.MasterPages.Ajax.HierarchicalMenuBehavior.registerClass('BlueBridge.SharePointExtensions.MasterPages.Ajax.HierarchicalMenuBehavior', AjaxControlToolkit.DynamicPopulateBehaviorBase);

//-------------------------------------------------------------------------
// Callback method. Backend returned a result that needs to be processed.
//-------------------------------------------------------------------------
function HierarchicalMenuExtender_OnCallbackComplete(result, context)
{
    if(context != null)
    {
        var behavior = $find(context.id);
        if(behavior != null)
            behavior._onMethodComplete(result, context, null);
    }
} 

//-------------------------------------------------------------------------
// Callback method. Backend returned with an error
//-------------------------------------------------------------------------
function HierarchicalMenuExtender_OnCallbackError(result, context)
{
    if(context != null)
    {
        var behavior = $find(context.id);
        if(behavior != null)
            behavior._onMethodError(result, context, null);
    }
} 
if(typeof(Sys)!=='undefined')Sys.Application.notifyScriptLoaded();