﻿$(document).ready(initialize);

var delayInterval = 50.0;
var fadeDuration = 100;

// jQuery extensions

// Sample extension
(function($){
    $.fn.functionName = function()
    {
        var $control = this;
    };
})(jQuery);

(function($){
    $.fn.commonAncestor = function()
    {
        var lineages = [];
        var minlen = Infinity;

        $(this).each(function()
            {
                var currentLineage = $(this).parents();     
                lineages.push(currentLineage);     
                minlen = Math.min(minlen, currentLineage.length);   
            }
        );
        
        for (var i in lineages)
        {     
            lineages[i] = lineages[i].slice(lineages[i].length - minlen);
        }
        
        // Iterate until equality is found
        var firstLineage = lineages[0];
        for (var firstLineageIndex = 0; firstLineageIndex < firstLineage.length; firstLineageIndex++) 
        {
            var candidateCommonAncestor = firstLineage[firstLineageIndex];
            var foundInAllLineages = true;
            
            for (var i = 1; i < lineages.length; i++)
            {
                var lineage = lineages[i];
                var foundInThisLineage = false;
                for (var j = 0; j < lineage.length; j++)
                {
                    var element = lineage[j];
                    if (candidateCommonAncestor == element)
                    {
                        foundInThisLineage = true;
                        break;
                    }
                }
                
                if (!foundInThisLineage)
                {
                    foundInAllLineages = false;
                    break;
                }
            }
            
            if (foundInAllLineages)
            {
                return $(candidateCommonAncestor);
            }
        }   
        
        return $([]);
    }; 

})(jQuery);

(function($){
    $.fn.positionNextTo = function(targetSelector, relationship)
    {
        var $positionedControl = this;
        var $referenceControl = $(targetSelector);
        
        var referencePosition = $referenceControl.position();
        var referenceWidth = $referenceControl.outerWidth();
        var referenceHeight = $referenceControl.outerHeight();

        var x;
        var y;

        switch (relationship)
        {
            case "right":
                x = referencePosition.left + referenceWidth;
                y = referencePosition.top;
                break;

            case "bottom":
                x = referencePosition.left;
                y = referencePosition.top + referenceHeight;
                break;
        }

        $positionedControl.css("left", "" + x + "px");
        $positionedControl.css("top", "" + y + "px");
    };
})(jQuery);

// Other script methods

function initialize()
{
    var $progressiveFades = $(".progressiveFade");

    $.each(
        $progressiveFades,
        function() {
            $(this).delay(delayInterval += 10, function() { $(this).show() });
        }
    );
}

// Adds and removes a class from an element with the specified target selector
// when the specified add and remove events are triggered.
function bindAddRemoveClassEvents(target, exclusionSelector, appliedClass, addEvent, removeEvent)
{
    var $eventTargets = $(target);

    if (exclusionSelector)
    {
        $eventTargets = $eventTargets.not(exclusionSelector);
    }
    
    // Every element within the target is a trigger for the event
    var $eventTriggers = $eventTargets.find("*");
    
    $eventTriggers.bind(addEvent, function()
        {
            $(this).closest(target).addClass(appliedClass);
        }
    );
    $eventTriggers.bind(removeEvent, function()
        {
            $(this).closest(target).removeClass(appliedClass);
        }
    );
}

// A behaviour either adds a class to or removes a class from 
// the elements matched by the target selector when the event 
// occurs on one of the trigger elements. If a target selector 
// is not specified, the target is the trigger. Otherwise the 
// target is located by searching the children of the trigger, 
// then the children of the trigger's parent, then continuing 
// up the tree until at least one match is found.
function bindBehaviourClass(triggerElement, event, action, className, targetSelector)
{
    // Wrap the trigger element in a jquery object.
    var $triggerElement = $(triggerElement);
    
    // If the target selector is null, then the target and the trigger are the same.
    var $behaviourTargets;
    if (!targetSelector)
    {
        $behaviourTargets = $triggerElement;
    }
    else
    {
        var $searchContext = $triggerElement;
        while ($searchContext.length > 0)
        {
            var $targets = $searchContext.find(targetSelector);
            if ($targets.length > 0)
            {
                $behaviourTargets = $targets;
                break;
            }
            
            $searchContext = $searchContext.parent();
        }
    }
    
    // Build a collection containing the trigger element and
    // all the children of the trigger element
    var $behaviourTriggers = $(triggerElement).add($triggerElement.find("*"));
    
    if (action == "add")
    {
        $behaviourTriggers.bind(event, function()
            {
                if ($behaviourTargets)
                {
                    $behaviourTargets.addClass(className);
                }
            }
        );
    }
    else if (action == "remove")
    {
        $behaviourTriggers.bind(event, function()
            {
                if ($behaviourTargets)
                {
                    $behaviourTargets.removeClass(className);
                }
            }
        );
    }
}

function OnSendMessageResponseComplete(result)
{
}

function SendMessageResponse(instanceId, responseId)
{
    FutureSelf.MessageService.ProcessMessageResponse(instanceId, responseId);
}

$(document).ready
(
    function()
    {
        // Find all form elements that have failed validation and give them
        // a validation highlight. Any form elements that do not contain validators
        // should have validation highlight removed.
        $(".formElement").removeClass("validationHighlight focus:remove:validationHighlight");
        $(".validator").closest(".formElement").addClass("validationHighlight focus:remove:validationHighlight");

        // All form elements should highlight on focus except those that are inline.
        bindAddRemoveClassEvents(".formElement", ".inline", "highlight", "focus", "blur");
        
        bindAddRemoveClassEvents(".highlightOnFocus", null, "highlight", "focus", "blur");
        bindAddRemoveClassEvents(".highlightOnHover", null, "highlight", "mouseover", "mouseout");

        // Find behaviour classes of the form event:action:class[:targetSelector]. 
        // e.g. "blur:remove:highlight:.highlightTarget"
        $("*").filter(function()
            {
                var match = this.className.match(/\b\S+:\S+:\S+(:\S)?\b/);
                var length = match ? match.length : 0;
                return length > 0;
            }
        ).each(function()
            {
                var classNames = this.className.split(" ");
                for (var i = 0; i < classNames.length; i++)
                {
                    var className = classNames[i];
                    // Is it a behaviour class?
                    if (className.match(/\b\S+:\S+:\S+(:\S)?\b/))
                    {
                        // Yes, we have a behaviour class
                        var elements = className.split(":");
                        var event = elements[0];
                        var action = elements[1];
                        var appliedClassName = elements[2];
                        var targetSelector = elements.length > 3 ? elements[3] : null;
                        
                        bindBehaviourClass(this, event, action, appliedClassName, targetSelector);
                    }
                }
            }
        );

        // Position next to
        $("*").filter(function()
            {
                var match = this.className.match(/\bpositionNextTo:\S+:\S+\b/);
                var length = match ? match.length : 0;
                return length > 0;
            }
        ).each(function()
            {
                var classNames = this.className.split(" ");
                for (var i = 0; i < classNames.length; i++)
                {
                    var className = classNames[i];
                    // Is it a behaviour class?
                    if (className.match(/\bpositionNextTo:\S+\b/))
                    {
                        // Yes, we have a behaviour class
                        var elements = className.split(":");
                        var targetSelector = elements[1];
                        var relationship = elements[2];
                        
                        $(this).positionNextTo(targetSelector, relationship);
                    }
                }
            }
        );

        // Add focus on click behaviour
        $(".focusOnClick").bind("click", function()
            {
                $(this).focus();
            }
        );

        // Explicitly give focus to fire appropriate event handlers
        if (document.activeElement && !document.activeElement.childNodes.length > 0)
        {
            // If an element already has focus, explicitly give it focus.
            $(document.activeElement).focus();
            $(document.activeElement).select();
        }
        else
        {
            // No element already has focus. 
            // Select the first text box that has failed validation otherwise just the first text box.
            var $validationFailureTextBox = $(".validationHighlight input[type='text']");
            if ($validationFailureTextBox.length > 0)
            {
                $validationFailureTextBox.first().focus();
                $validationFailureTextBox.first().select();
            }
            else
            {
                var $firstTextBox = $(".autoFocus input[type='text']").not(".noAutoFocus");
                if ($firstTextBox.length > 0)
                {
                    $firstTextBox.first().focus();
                    $firstTextBox.first().select();
                }
            }
        }
    }
);

