﻿var AccelerationType = {
    'CONSTANT': 0,
    'SINUSOIDAL': 1,
    'EASE_OUT' : 2,
    'EASE_IN' : 3,
    'COSINE' : 4,
    'SINE': 5,
    'TANGENT' : 6
};

//*********************** Resize Animation ***************************
function ResizeAnimation(element, endWidth, endHeight, duration, interval, acceleration) {
    this.m_Element = element;

    this.m_StartWidth = null;
    this.m_StartHeight = null;
    this.m_EndWidth = endWidth;
    this.m_EndHeight = endHeight;

    this.m_ChangeWidth = null;
    this.m_ChangeHeight = null;

    this.m_AnimationEngine = new AnimationEngine(duration, interval, acceleration);
    this.m_AnimationEngine.OnAnimationRun = CreateDelegate(this, this.Animate);
    this.m_AnimationEngine.OnAnimationComplete = CreateDelegate(this, this.AnimationComplete)

    this.OnAnimationStart = null;
    this.OnAnimationComplete = null;
}

ResizeAnimation.prototype.Start = function() {
    if (this.OnAnimationStart != null) {
        this.OnAnimationStart();
    }

    this.m_StartWidth = this.m_Element.clientWidth;
    this.m_StartHeight = this.m_Element.clientHeight;

    this.m_ChangeWidth = this.m_EndWidth - this.m_StartWidth;
    this.m_ChangeHeight = this.m_EndHeight - this.m_StartHeight;

    this.m_AnimationEngine.Start();
}

ResizeAnimation.prototype.Stop = function() {
    this.m_AnimationEngine.Stop();
}

ResizeAnimation.prototype.Animate = function(percentChange) {
    this.m_Element.style.height = Math.abs(Math.round(this.m_StartHeight + (percentChange * this.m_ChangeHeight))) + 'px';
    this.m_Element.style.width = Math.abs(Math.round(this.m_StartWidth + (percentChange * this.m_ChangeWidth))) + 'px';
}

ResizeAnimation.prototype.AnimationComplete = function() {
    if (this.OnAnimationComplete != null) {
        this.OnAnimationComplete();
    }
}





//*********************** Move Animation ***************************
function MoveAnimation(element, endPosX, endPosY, duration, interval, acceleration) {
    this.m_Element = element;

    this.m_StartPosX = null;
    this.m_StartPosY = null;
    this.m_EndPosX = endPosX;
    this.m_EndPosY = endPosY;

    this.m_ChangeInPosX = null;
    this.m_ChangeInPosY = null;

    this.m_AnimationEngine = new AnimationEngine(duration, interval, acceleration);
    this.m_AnimationEngine.OnAnimationRun = CreateDelegate(this, this.Animate);
    this.m_AnimationEngine.OnAnimationComplete = CreateDelegate(this, this.AnimationComplete)

    this.OnAnimationStart = null;
    this.OnAnimationComplete = null;
}

MoveAnimation.prototype.Start = function() {
    if (this.OnAnimationStart != null) {
        this.OnAnimationStart();
    }

    this.m_StartPosX = this.m_Element.offsetLeft;
    this.m_StartPosY = this.m_Element.offsetTop;

    this.m_ChangeInPosX = this.m_EndPosX - this.m_StartPosX;
    this.m_ChangeInPosY = this.m_EndPosY - this.m_StartPosY;

    this.m_AnimationEngine.Start();
}

MoveAnimation.prototype.Stop = function() {
    this.m_AnimationEngine.Stop();
}

MoveAnimation.prototype.Animate = function(percentChange) {
    this.m_Element.style.left = Math.round(this.m_StartPosX + (percentChange * this.m_ChangeInPosX)) + 'px';
    this.m_Element.style.top = Math.round(this.m_StartPosY + (percentChange * this.m_ChangeInPosY)) + 'px';
}

MoveAnimation.prototype.AnimationComplete = function() {
    if (this.OnAnimationComplete != null) {
        this.OnAnimationComplete();
    }
}


//*********************** Horizontal Move Animation ***************************
function HorizontalMoveAnimation(element, endPosX, duration, interval, acceleration) {
    this.m_Element = element;

    this.m_StartPosX = null;
    this.m_EndPosX = endPosX;

    this.m_ChangeInPosX = null;

    this.m_AnimationEngine = new AnimationEngine(duration, interval, acceleration);
    this.m_AnimationEngine.OnAnimationRun = CreateDelegate(this, this.Animate);
    this.m_AnimationEngine.OnAnimationComplete = CreateDelegate(this, this.AnimationComplete)

    this.OnAnimationStart = null;
    this.OnAnimationComplete = null;
}

HorizontalMoveAnimation.prototype.Start = function() {
    if (this.OnAnimationStart != null) {
        this.OnAnimationStart();
    }

    this.m_StartPosX = this.m_Element.offsetLeft;
    this.m_ChangeInPosX = this.m_EndPosX - this.m_StartPosX;

    this.m_AnimationEngine.Start();
}

HorizontalMoveAnimation.prototype.Stop = function() {
    this.m_AnimationEngine.Stop();
}

HorizontalMoveAnimation.prototype.Animate = function(percentChange) {
    this.m_Element.style.left = Math.round(this.m_StartPosX + (percentChange * this.m_ChangeInPosX)) + 'px';
}

HorizontalMoveAnimation.prototype.AnimationComplete = function() {
    if (this.OnAnimationComplete != null) {
        this.OnAnimationComplete();
    }
}




//*********************** Move Animation ***************************
function VerticalMoveAnimation(element, endPosY, duration, interval, acceleration) {
    this.m_Element = element;

    this.m_StartPosY = null
    this.m_EndPosY = endPosY;

    this.m_ChangeInPosY = null;

    this.m_AnimationEngine = new AnimationEngine(duration, interval, acceleration);
    this.m_AnimationEngine.OnAnimationRun = CreateDelegate(this, this.Animate);
    this.m_AnimationEngine.OnAnimationComplete = CreateDelegate(this, this.AnimationComplete)

    this.OnAnimationStart = null;
    this.OnAnimationComplete = null;
}

VerticalMoveAnimation.prototype.Start = function() {
    if (this.OnAnimationStart != null) {
        this.OnAnimationStart();
    }

    this.m_StartPosY = this.m_Element.offsetTop;
    this.m_ChangeInPosY = this.m_EndPosY - this.m_StartPosY;

    this.m_AnimationEngine.Start();
}

VerticalMoveAnimation.prototype.Stop = function() {
    this.m_AnimationEngine.Stop();
}

VerticalMoveAnimation.prototype.Animate = function(percentChange) {
    this.m_Element.style.top = Math.round(this.m_StartPosY + (percentChange * this.m_ChangeInPosY)) + 'px';
}

VerticalMoveAnimation.prototype.AnimationComplete = function() {
    if (this.OnAnimationComplete != null) {
        this.OnAnimationComplete();
    }
}




//*********************** Opacity Animation ***************************
function OpacityAnimation(element, endOpacity, duration, interval, acceleration) {
    this.m_Element = element;

    this.m_EndOpacity = endOpacity;
    this.m_ChangeOpacity = null;

    this.m_AnimationEngine = new AnimationEngine(duration, interval, acceleration);
    this.m_AnimationEngine.OnAnimationRun = CreateDelegate(this, this.Animate);
    this.m_AnimationEngine.OnAnimationComplete = CreateDelegate(this, this.AnimationComplete)

    this.OnAnimationStart = null;
    this.OnAnimationComplete = null;
}

OpacityAnimation.prototype.Start = function() {
    if (this.OnAnimationStart != null) {
        this.OnAnimationStart();
    }

    this.m_StartOpacity = GetOpacity(this.m_Element);
    this.m_ChangeOpacity = this.m_EndOpacity - this.m_StartOpacity;

    this.m_AnimationEngine.Start();
}

OpacityAnimation.prototype.Stop = function() {
    this.m_AnimationEngine.Stop();
}

OpacityAnimation.prototype.Animate = function(percentChange) {
    var newOpacity = Math.round(this.m_StartOpacity + (percentChange * this.m_ChangeOpacity));
    this.m_Element.style.filter = 'alpha(opacity=' + newOpacity * 10 + ')';
    this.m_Element.style.opacity = newOpacity / 10;
}

OpacityAnimation.prototype.AnimationComplete = function() {
    if (this.OnAnimationComplete != null) {
        this.OnAnimationComplete();
    }
}




//*********************** Animation Engine ***************************
function AnimationEngine(duration, interval, accelerationType) {
    this.m_Duration = duration;
    this.m_Interval = interval;
    this.m_AccelerationType = accelerationType;
    this.m_StartTime = null;

    this.m_Timer = null;

    this.OnAnaimationStart = null;
    this.OnAnimationRun = null;
    this.OnAnimationComplete = null;
}

AnimationEngine.prototype.Start = function() {
    if (this.OnAnimationStart != null) {
        this.OnAnimationStart();
    }

    this.m_StartTime = new Date().getTime();
    this.m_Timer = setInterval(CreateDelegate(this, this.Animate), this.m_Interval);
}

AnimationEngine.prototype.Stop = function() {
    clearInterval(this.m_Timer);
}

AnimationEngine.prototype.Animate = function() {
    var elapsedTime = new Date().getTime() - this.m_StartTime;
    var percentChange = elapsedTime < this.m_Duration ? (this.GetPercentChange(elapsedTime)) : 1;

    if (this.OnAnimationRun != null) {
        this.OnAnimationRun(percentChange);
    }

    if (elapsedTime >= this.m_Duration) {
        this.Stop();

        if (this.OnAnimationComplete != null) {
            this.OnAnimationComplete();
        }
    }
}

AnimationEngine.prototype.GetPercentChange = function(elapsedTime) {
    var change = null;

    switch (this.m_AccelerationType) {
        case AccelerationType.CONSTANT:
            change = (elapsedTime * (1 / this.m_Duration));
            break;
        case AccelerationType.SINUSOIDAL:
            change = Math.abs(Math.sin(elapsedTime * (Math.PI / (2 * this.m_Duration))));
            break;
        case AccelerationType.EASE_OUT:
            change = Math.pow(((1 / this.m_Duration) * elapsedTime), .25);
            break;
        case AccelerationType.EASE_IN:
            change = Math.pow(((1 / this.m_Duration) * elapsedTime), 1.25);
            break;
        case AccelerationType.COSINE:
            change = Math.cos(elapsedTime * (Math.PI / (2 * 300)));
            break;
        case AccelerationType.SINE:
            change = Math.sin(elapsedTime * (Math.PI / (2 * 300)));
            break;
        case AccelerationType.TANGENT:
            change = Math.tan(elapsedTime * (Math.PI / (2 * 300)));
            break;
    }

    return change
}

function GetOpacity(element) {
    var opacity = 100;
    if (element.style.filter) {
        var opacityString = element.style.filter;
        var matches = opacityString.match(/alpha\(opacity=(\d+)\)/);
        if (matches.length > 0) {
            opacity = (matches[1] / 10);
        }
        else {
            opacity = opacity / 10;
        }
    }
    else {
       opacity = (element.style.opacity * 10);
   }

   return opacity;
}

// ***********************************************************************************************************
// Name:Collapser
// Type:User Control
// Author: Cliff Gower
//************************************************************************************************************

var TriggerType = {
    'EXPAND': 0,
    'COLLAPSE': 1,
    'BOTH': 2
};

var PanelState = {
    'EXPANDED' : 0,
    'COLLAPSED' : 1,
    'ANIMATING' : 2
};

//*********************** smoothe collapsable panel object constructor ***************************
function Collapser(panel, trigger, behavior, minWidth, minHeight, maxWidth, maxHeight, duration, interval, acceleration, expanded, allowExpansion) {
    this.m_Panel = panel;
    this.m_Trigger = trigger;
    this.m_AllowExpansion = allowExpansion;

    this.m_TriggerBehaviors = new Array();

    this.OnExpandStart = null;
    this.OnExpandComplete = null;
    this.OnCollapseStart = null;
    this.OnCollapseComplete = null;

    if (expanded) {
        this.m_PanelState = PanelState.EXPANDED;
        this.m_PreviousPanelState = PanelState.EXPANDED;
        this.SetDimensions(maxWidth, maxHeight);
    }
    else {
        this.m_PanelState = PanelState.COLLAPSED;
        this.m_PreviousPanelState = PanelState.COLLAPSED;
        this.SetDimensions(minWidth, minHeight);
    }

    this.m_ExpandAnimation = new ResizeAnimation(this.m_Panel, maxWidth, maxHeight, duration, interval, acceleration);
    this.m_ExpandAnimation.OnAnimationComplete = CreateDelegate(this, this.AnimationComplete);

    this.m_CollapseAnimation = new ResizeAnimation(this.m_Panel, minWidth, minHeight, duration, interval, acceleration);
    this.m_CollapseAnimation.OnAnimationComplete = CreateDelegate(this, this.AnimationComplete);

    if (trigger != null) {
        this.AddTrigger(trigger, behavior);
    }
}


//*********************** smoothe collapsable panel triger event handler ***************************
Collapser.prototype.OnTrigger = function(e) {
    if (this.m_PanelState == PanelState.ANIMATING) { return; }

    e = e || window.event;
    var trigger = e.srcElement || e.target;
    var triggerBehavior = this.m_TriggerBehaviors[trigger.id];
    if (triggerBehavior == undefined) {
        triggerBehavior = this.m_TriggerBehaviors[trigger.parentNode.id];
    }

    if (this.m_PanelState == PanelState.EXPANDED) {
        if (triggerBehavior != TriggerType.EXPAND) {
            this.Collapse();
        }
    }
    else {
        if (triggerBehavior != TriggerType.COLLAPSE) {
            this.Expand();
        }
    }
}


//*********************** smoothe collapsable panel methods ***************************
Collapser.prototype.AddTrigger = function(trigger, type) {
    this.m_TriggerBehaviors[trigger.id] = type;
    AddHandler(trigger, 'click', CreateDelegate(this, this.OnTrigger));
}

Collapser.prototype.Expand = function() {
    if (this.OnExpandStart != null) {
        this.OnExpandStart();
    }

    this.m_PreviousPanelState = PanelState.COLLAPSED;
    this.m_PanelState = PanelState.ANIMATING;

    this.m_ExpandAnimation.Start();
}

Collapser.prototype.Collapse = function() {
    if (this.CollapseStart != null) {
        this.OnCollapseStart();
    }

    this.m_PreviousPanelState = PanelState.EXPANDED;
    this.m_PanelState = PanelState.ANIMATING;

    this.m_Panel.style.minHeight = "";
    this.m_CollapseAnimation.Start();
}

Collapser.prototype.AnimationComplete = function() {
    var t = 0;

    if (this.m_PreviousPanelState == PanelState.COLLAPSED) {
        if (this.OnExpandComplete != null) {
            this.OnExpandComplete();
        }

        this.m_PanelState = PanelState.EXPANDED

        if (this.m_AllowExpansion) {
            this.AllowForExpansion();
        }
    }
    else {
        if (this.OnCollapseComplete != null) {
            this.OnCollapseComplete();
        }

        this.m_PanelState = PanelState.COLLAPSED
    }
}

Collapser.prototype.SetDimensions = function(width, height) {
    this.m_Panel.style.height = height + 'px';
    this.m_Panel.style.width = width + 'px';
}

Collapser.prototype.AllowForExpansion = function() {
    this.m_Panel.style.minHeight = this.m_Panel.style.height;
    this.m_Panel.style.height = "";
}

//*********************** Event Handler Creation ***************************
function AddHandler(object, eventName, handler) {
    if (object.addEventListener) { object.addEventListener(eventName, handler, false); }
    else { object.attachEvent("on" + eventName, handler); }
}

function RemoveHandler(object, eventName, handler) {
    if (object.removeEventListener) { object.removeEventListener(eventName, handler, false); }
    else { object.detachEvent("on" + eventName, handler); }
}

function AddWheelHandler(handler) {
    if (document.addEventListener) { document.addEventListener('DOMMouseScroll', handler, false); }
    else {
        document.attachEvent("onmousewheel", handler);
    }
}

function RemoveWheelHandler(handler) {
    if (document.removeEventListener) { document.removeEventListener('DOMMouseScroll', handler, false); }
    else {
        document.detachEvent("onmousewheel", handler);
    }
}

function CreateDelegate(object, method) {
    return (function() { return method.apply(object, arguments); })
}

function ForceEvent(element, eventName) {
    var isIE = navigator.userAgent.indexOf("MSIE") != -1 ? true : false;
    if (isIE) {
        element[('on' + event)];
    }
    else {
        var theEvent = document.createEvent("MouseEvent");
        theEvent.initMouseEvent(eventName, true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
        
        element.dispatchEvent(theEvent);
    }
}

// ***********************************************************************************************************
// Name:Accordian Control
// Type:User Control
// Author: Cliff Gower
//************************************************************************************************************


//*********************** accordian control object constructor ***************************
function AccordianControl() {
    this.m_Panels = new Array();
    
    this.OnItemExpandStart = null;
    this.OnItemExpandComplete = null;
    this.OnItemCollapseStart = null;
    this.OnItemCollapseComplete = null;
}

AccordianControl.prototype.AddCollapsablePanel = function(panel, siblingBehavior) {
    var t = 0;

    for (index = 0; index < this.m_Panels.length; index++) {
        var currentPanel = this.m_Panels[index];
        currentPanel.AddTrigger(panel.m_Trigger, siblingBehavior);
        panel.AddTrigger(currentPanel.m_Trigger, siblingBehavior);
    }

    panel.OnExpandStart = CreateDelegate(this, this.ItemExpandStart);
    panel.OnExpandComplete = CreateDelegate(this, this.ItemExpandComplete);

    panel.OnCollapseStart = CreateDelegate(this, this.ItemCollapseStart);
    panel.OnCollapseComplete = CreateDelegate(this, this.ItemCollapseComplete);

    this.m_Panels.push(panel);
}

AccordianControl.prototype.ItemExpandStart = function() {
    if (this.OnItemExpandStart != null) {
        this.OnItemExpandStart();
    }
}

AccordianControl.prototype.ItemExpandComplete = function() {
    if (this.OnItemExpandComplete != null) {
        this.OnItemExpandComplete();
    }
}

AccordianControl.prototype.ItemCollapseStart = function() {
    if (this.OnItemCollapseStart != null) {
        this.OnItemCollapseStart();
    }
}

AccordianControl.prototype.ItemCollapseComplete = function() {
    if (this.OnItemCollapseComplete != null) {
        this.OnItemCollapseComplete();
    }
}




