﻿Type.registerNamespace("Infragistics.Web.UI");
var $IG = Infragistics.Web.UI; 

$IG.DropDownPopupPosition = function () { 

    ///<summary>
    /// Enumeration for different dropdown container positions relative to the source element
    ///</summary>

}

$IG.DropDownPopupPosition.prototype = 
{
   Default:0, // Bottom Left. This is also the AUTO mode, which means that the container will be automatically positioned wherever there is visible space 
   Center:1, // (dropdown bottom center) - the source element will be centered above the dropdown container 
   Left:2, // the dropdown container will be positioned on the left of the source (not directly below it). They will be aligned in the same way on the y axis
   Right:3, // the dropdown container will be positioned on the right of the source (not directly below it). They will be aligned in the same way on the y axis
   TopLeft:4, // the dropdown container will be on top of the source, aligned on the left
   TopRight:5, // the dropdown container will be on top of the source, aligned on the right
   BottomLeft:6, // the dropdown container will be on the bottom of the source, aligned on the left
   BottomRight:7 // same as above, but alighed on the right
};

$IG.DropDownPopupPosition.registerEnum("Infragistics.Web.UI.DropDownPopupPosition");


$IG.DropDownBehavior = function(sourceElement, dropDownIsChild, outerContainer) {

    ///<summary>
    /// An object that allows the developer to specify elements and/or UIObjects that 
    /// should be source elements and/or target elements.  the Target element wll be the 
    /// drop down target (popup) while the source will be the element that receives 
    /// drop down events and which will cause the popup to show/hide
    ///</summary>

    // initializations
    if (!sourceElement) {
        throw Error.argumentNull('sourceElement');
    }

    this._sourceElement = sourceElement; // the source of the dropdown (it will receive the events and cause the dropdown to appear / dissappear)
    this._targetContainer = null; // dropdown container
    this._targetContent = null; //reference to the content in the target container - currently it is not used anywhere
    this._position = $IG.DropDownPopupPosition.Default; // $IG.DropDownPopupPosition (default is Bottom + Left + AUTO)

    this._outerContainer = outerContainer;
    
    this._offsetX = 0; // number of pixels by which the dropdown container will be offset from the source on the X axis
    this._offsetY = 0; // number of pixels by which the dropdown container will be offset from the source on the Y axis
    this._containerHeight = 0; // used to store the height of the dropdown container.
    this._offScreen = false; // if true, it means that IF and WHEN the dropdown is shown, it will be off the screen, therefore IF the positioning is AUTO, the position will be automatically adjusted

    // by default this is true, and in that case we will adjust the dropdown position if it is off screen (controllable by the user)
    this._enableAutomaticPositioning = true;
    this._enableMovingTargetWithSource = true;

    this._enableAnimations = true; // by default animations are enabled
    this._animationType = $IG.AnimationEquationType.EaseInOut; // see $IG.AnimationEquationType in igAnimation.js

    this._visible = false; // whether the popup container is currently visible or not ; by default the popup container is initially closed

    this._visibleOnFocus = false; // if true, the dropdown will appear when the source gains focus
    this._visibleOnBlur = false; // if true, the dropdown will disappear when the source loses focus
    this._visibleOnMouseOver = false; // if true, the dropdown will appear once the mouse is over the source
    this._visibleOnClick = false; // if true, the dropdown will appear once the source is clicked - it's probably better to be mouseDOWN instead !
    this._visibleOnKeyDown = false; // if true, the dropdown will appear once the keyDown event is invoked on the source

    this._dropDownAnimation = null; // a reference to the drop down animation object, which extends $IG.AnimationBase
    this._animationDurationMs = 300; // default 300 ms - number of milliseconds  during which the animation will be performed

    this._zIndex = 10000;
    /*
    * There are various ways to perform the animations. Normally it is not reliable to animate the actual drop down container
    * especially in cases when it has borders/paddings, and so on. Therefore we create a separate animation container that wraps around the
    * dropdown container (i.e. the actual dropdown container will be a child - the only one-  of the animationsContainer).
    * And we perform the animations on this animations container. It will have overflow: hidden. 
    */
    this._animationsContainer = null;
    // we need to store the targetcontainer bounds and initially set its height to zero , when animations are enabled
    // otherwise there will be a flickering because its height will be originally set to the default (max) one
    this._targetBounds = null;

    // whether the drop down panel is a child of the target or not (by default it is not, and can be anywhere
    // on the page, we use absolute positioning in order to position it exactly where it should be. If it is set to be a child
    // then we set the targetContainer to be the first child of the source (see the init() function)
    this._dropDownIsChild = dropDownIsChild;

    // a reference to the object that manages drop down events: see $IG.DropDownEvents
    this._events = new $IG.DropDownEvents(this);

    this._animationEndListener = null;

    // hook delegates
    // mouse up on the source
    this._mouseUpDelegate = Function.createDelegate(this, this._mouseUpHandler);
    // mouse click on the source
    this._mouseClickDelegate = Function.createDelegate(this, this._mouseClickHandler);
    // mouse over on the source
    this._mouseOverDelegate = Function.createDelegate(this, this._mouseOverHandler);
    // mouse down on the source
    this._mouseDownDelegate = Function.createDelegate(this, this._mouseDownHandler);
    // key down on the source               
    this._keyDownDelegate = Function.createDelegate(this, this._keyDownHandler);
    // key up on the source
    this._keyUpDelegate = Function.createDelegate(this, this._keyUpHandler);
    // focus on the source
    this._focusDelegate = Function.createDelegate(this, this._focusHandler);
    // focus on the source
    this._blurDelegate = Function.createDelegate(this, this._blurHandler);

    // this is a special delegate which controls the iframe for the IE6.0 SELECT bug - so that it's always properly aligned behind the dropdown container
    this._moveDelegate = Function.createDelegate(this, this._onMove);

    // set interval to check periodically if the source's position is changed
    // if it is changed, we close the dropdown
    if (this._enableMovingTargetWithSource) {
    
        this._checkDelegate = Function.createDelegate(this, this._onCheckPosition);
        this._sourceLocation = Sys.UI.DomElement.getLocation(this._sourceElement);
        this._sourceBounds = Sys.UI.DomElement.getBounds(this._sourceElement);
        this._closeCheckID = setInterval(this._checkDelegate, 500);
    }

}

$IG.DropDownBehavior.prototype =
{

	/***************************** PUBLIC Properties *********************************/
	get_sourceElement: function()
	{
		///<summary>
		/// Returns the dropdown source elemenet (DOM Element)
		///</summary>
		///<remarks>
		///
		///</remarks>
		return this._sourceElement;
	},

	get_targetContainer: function()
	{
		///<summary>
		/// returns the dropdown container (DOM Element)
		///</summary>
		///<remarks>
		///
		///</remarks>
		return this._targetContainer;
	},

	get_animationsContainer: function()
	{
		///<summary>
		/// returns the animations container (DOM Element)
		///</summary>
		///<remarks>
		///
		///</remarks>
		return this._animationsContainer;
	},

	set_targetContainer: function(container)
	{
		///<summary>
		/// 
		///</summary>
		///<param name="container" type="Sys.UI.DomElement" domElement="true">
		///<remarks>
		///
		///</remarks>
		if (!container)
		{
			throw Error.argumentNull('container');
		}
		this._targetContainer = container;
	},

	set_targetContainerHeight: function(height)
	{
		this._targetBounds.height = height; // was this._targetBounds = height; ????? 
		this._containerHeight = height;

		if (this.get_enableAnimations())
			$util.setAbsoluteHeight(this._animationsContainer, height);
	},

	get_targetContent: function()
	{
		///<summary>
		/// 
		///</summary>
		///<remarks>
		/// the target content is the first child of the targetContainer 
		///</remarks>
		return this._targetContent;
	},

	set_targetContent: function(content)
	{
		///<summary>
		/// 
		///</summary>
		///<param name="content" type="Sys.UI.DomElement" domElement="true">
		///<remarks>
		///
		///</remarks>
		this._targetContent = content;
	},

	get_zIndex: function()
	{

		return this._zIndex;

	},

	set_zIndex: function(zindex)
	{

		this._zIndex = zindex;

	},

	get_position: function()
	{
		///<summary>
		/// returns the $IG.DropDownPopupPosition that is currently used for the dropdown behavior
		///</summary>
		///<remarks>
		///
		///</remarks>
		return this._position;
	},

	set_position: function(position)
	{
		///<summary>
		/// position is of type $IG.DropDownPopupPosition
		///</summary>
		///<param name="position" type="$IG.DropDownPopupPosition" domElement="false">
		///<remarks>
		///
		///</remarks>
		this._position = position;
	},

	get_enableAutomaticPositioning: function()
	{

		return this._enableAutomaticPositioning;
	},

	set_enableAutomaticPositioning: function(enabled)
	{

		this._enableAutomaticPositioning = enabled;
	},

	get_enableMovingTargetWithSource: function()
	{

		return this._enableMovingTargetWithSource;

	},

	set_enableMovingTargetWithSource: function(enabled)
	{

		this._enableMovingTargetWithSource = enabled;

		if (this._enableMovingTargetWithSource)
		{

			clearInterval(this._closeCheckID);
			this._checkDelegate = Function.createDelegate(this, this._onCheckPosition);
			this._sourceLocation = Sys.UI.DomElement.getLocation(this._sourceElement);
			this._sourceBounds = Sys.UI.DomElement.getBounds(this._sourceElement);
			this._closeCheckID = setInterval(this._checkDelegate, 200);

		} else
		{
			clearInterval(this._closeCheckID);
		}

	},

	get_enableAnimations: function()
	{
		///<summary>
		/// returns true/false depending on whether the dropdown's showing and hiding is animated or not
		///</summary>
		///<remarks>
		///
		///</remarks>
		return this._enableAnimations;
	},

	set_enableAnimations: function(enableAnimations)
	{
		///<summary>
		/// enables disables animations of the dropdown container - enableAnimations must be true or false
		///</summary>
		///<param name="enableAnimations" type="boolean" domElement="false">
		///<remarks>
		///
		///</remarks>
		this._enableAnimations = enableAnimations;
	},

	get_animationType: function()
	{
		///<summary>
		/// returns $IG.AnimationEquationType
		///</summary>
		///<remarks>
		///
		///</remarks>
		return this._animationType;
	},

	set_animationType: function(animationType)
	{
		///<summary>
		/// sets the type of animation for the drop down container
		///</summary>
		///<param name="animationType" type="$IG.AnimationEquationType" domElement="false">
		///<remarks>
		///
		///</remarks>
		this._animationType = animationType;
	},

	get_animationDurationMs: function()
	{
		///<summary>
		/// returns the number of milliseconds during which the animation will play
		///</summary>
		///<remarks>
		///
		///</remarks>
		return this._animationDurationMs;
	},

	set_animationDurationMs: function(duration)
	{
		///<summary>
		/// sets the number of milliseconds during which the animation will play
		///</summary>
		///<param name="duration" type="integer" domElement="false">
		///<remarks>
		///
		///</remarks>
		this._animationDurationMs = duration;
	},

	get_offsetX: function()
	{
		///<summary>
		/// returns the number of pixels by which the dropdown container will be offset on the x axis
		///</summary>
		///<remarks>
		///
		///</remarks>
		return this._offsetX;
	},

	set_offsetX: function(offsetX)
	{
		///<summary>
		/// sets the number of pixels by which the dropdown container will be offset on the x axis
		///</summary>
		///<param name="offsetX" type="integer" domElement="false">
		///<remarks>
		///
		///</remarks>
		this._offsetX = offsetX;
	},

	get_offsetY: function()
	{
		///<summary>
		/// returns the number of pixels by which the dropdown container will be offset on the y axis
		///</summary>
		///<remarks>
		///
		///</remarks>
		return this._offsetY;
	},

	set_offsetY: function(offsetY)
	{
		///<summary>
		/// returns the number of pixels by which the dropdown container will be offset on the y axis
		///</summary>
		///<param name="offsetY" type="integer" domElement="false">
		///<remarks>
		///
		///</remarks>
		this._offsetY = offsetY;
	},

	get_offScreen: function()
	{
		///<summary>
		/// returns whether the dropdown container will be off the screen on its next appearance. If this is true, and the positioning is set to Default
		/// i.e. AUTO, then the position of the dropdown will be readjusted so that it is visible on the screen 
		///</summary>
		///<remarks>
		///
		///</remarks>
		return this._offScreen;
	},

	set_offScreen: function(offScreen)
	{
		///<summary>
		/// sets whether the drop down container is off the screen or not
		///</summary>
		///<param name="offScreen" type="boolean" domElement="false">
		///<remarks>
		///
		///</remarks>
		this._offScreen = offScreen;
	},

	get_visibleOnFocus: function()
	{
		///<summary>
		/// returns whether the dropdown container should show if the source gains focus
		///</summary>
		///<remarks>
		///
		///</remarks>
		return this._visibleOnFocus;
	},

	set_visibleOnFocus: function(visibleOnFocus)
	{
		///<summary>
		///  sets whether the dropdown container should show if the source gains focus
		///</summary>
		///<param name="visibleOnFocus" type="boolean" domElement="false">
		///<remarks>
		///
		///</remarks>
		this._visibleOnFocus = visibleOnFocus;
	},

	get_visibleOnBlur: function()
	{
		///<summary>
		/// returns whether the dropdown container should hide if the source loses focus
		///</summary>
		///<remarks>
		///
		///</remarks>
		return this._visibleOnBlur;
	},

	set_visibleOnBlur: function(visibleOnBlur)
	{
		///<summary>
		/// sets whether the dropdown container should hide if the source loses focus
		///</summary>
		///<param name="visibleOnBlur" type="boolean" domElement="false">
		///<remarks>
		///
		///</remarks>
		this._visibleOnBlur = visibleOnBlur;
	},

	get_isAnimating: function()
	{
		if (this._dropDownAnimation)
			return this._dropDownAnimation.get_isAnimating();
		else
			return false;
	},

	get_visibleOnMouseOver: function()
	{
		///<summary>
		/// returns whether the dropdown container should show if mouse over is executed on the source
		///</summary>
		///<remarks>
		///
		///</remarks>
		return this._visibleOnMouseOver;
	},

	set_visibleOnClick: function(visibleOnClick)
	{
		///<summary>
		/// sets whether the dropdown container should show if click is executed on the source
		///</summary>
		///<param name="visibleOnClick" type="boolean" domElement="false">
		///<remarks>
		///
		///</remarks>
		this._visibleOnClick = visibleOnClick;
	},

	get_visibleOnClick: function()
	{
		///<summary>
		/// returns whether the dropdown container should show if click is executed on the source
		///</summary>
		///<remarks>
		///
		///</remarks>
		return this._visibleOnClick;
	},

	set_visibleOnMouseOver: function(visibleOnMouseOver)
	{
		///<summary>
		/// sets whether the dropdown container should show if mouse over is executed on the source
		///</summary>
		///<param name="visibleOnMouseOver" type="boolean" domElement="false">
		///<remarks>
		///
		///</remarks>
		this._visibleOnMouseOver = visibleOnMouseOver;
	},

	get_visibleOnKeyDown: function()
	{
		///<summary>
		/// returns whether the dropdown container should show if key down is executed on the source
		///</summary>
		///<remarks>
		///
		///</remarks>
		return this._visibleOnKeyDown;
	},

	set_visibleOnKeyDown: function(visibleOnKeyDown)
	{
		///<summary>
		/// sets whether the dropdown container should show if key down is executed on the source
		///</summary>
		///<param name="visibleOnKeyDown" type="boolean" domElement="false">
		///<remarks>
		///
		///</remarks>
		this._visibleOnKeyDown = visibleOnKeyDown;
	},

	get_dropDownIsChild: function()
	{
		///<summary>
		/// returns whether or not the dropdown container is the first child of the source element, or whether it is absolutely positioned
		/// anywhere on the page (normally the appended to the form as a sibling)
		///</summary>
		///<remarks>
		///
		///</remarks>
		return this._dropDownIsChild;
	},

	get_visible: function()
	{
		///<summary>
		/// whether the dropdown container is currently visible (shown) or not
		///</summary>
		///<remarks>
		///
		///</remarks>
		return this._visible;
	},

	set_visible: function(visible)
	{
		///<summary>
		/// causes the dropdown container to show and hide
		/// NOTE: calling this function actually *CAUSES* the dropdown to show and hide
		/// it does not only modify the contents of the "_visible" variable
		///</summary>
		///<remarks>
		/// Do we fire these events if the dropdown is already visible / hidden ? 
		///</remarks>
		// denotes whether the "ing" event will be canceled or not

		var cancelEvent = false;

		this._sourceLocation = Sys.UI.DomElement.getLocation(this._sourceElement);

		// return immediately if there is an ongoing animation
		if (this._dropDownAnimation && this._dropDownAnimation.get_isAnimating())
		{
			return;
		}

		if (visible)
		{
			// fire setting visible event
			cancelEvent = this.get_Events()._fireEvent("SettingVisible", this);

		} else
		{
			// fire setting hidden event
			cancelEvent = this.get_Events()._fireEvent("SettingHidden", this);
		}

		// we need to be able to read both the current value as well as the new value
		// var tmpVisible = this._visible;
		// this._visible = visible;

		/* A.T. 16/08/2008 BR35638: Dropdown framework: Cancelling SettingVisible or SettingHidden has no effect */
		if (!cancelEvent)
		{
			// if the dropdown is hidden, and we want it to show, GO
			if (visible && !this._visible)
			{
				this.__showDropDown();

				// if the dropdown is currently visible, and we want it to hide, GO
			} else if (!visible && this._visible)
			{
				this.__hideDropDown();
			}

			// do we fire these events if the dropdown is already visible / hidden ? 
			if (visible)
			{
				// fire set visible event
				this.get_Events()._fireEvent("SetVisible", this); // event after the dropdown has appeared

			} else
			{
				// fire set hidden event
				this.get_Events()._fireEvent("SetHidden", this); // event after the dropdown has been hidden
			}

			// if animations are enabled then we flip the visible flag in the doEnd() method of the 
			// drop down animation object. Since the dropdown animation constantly reads this flag, and uses setTimeout/interval, if we change it here
			// it will pick the wrong value
			if (!this._enableAnimations)
			{
				this._visible = visible;
			}

		}
	},

	get_Events: function()
	{
		///<summary>
		/// Returns a reference to the Infragistics.Web.UI.DropDownEvents object, which contains all the events of the behavior.
		///</summary>
		return this._events;
	},

	/***************************** END PUBLIC Properties *********************************/


	/****************************  PUBLIC Methods ****************************************/

	// not currently used
	getBounds: function()
	{
		///<summary>
		/// 
		///</summary>
		///<remarks>
		///
		///</remarks>
		return this._bounds;
	},

	// if the dropdown is currently hidden, cause it to show. If it is shown, cause it to hide
	triggerVisibility: function()
	{
		if (this._visible)
		{
			this.set_visible(false);
		} else
		{
			this.set_visible(true);
		}

	},

	set_containerMaxHeight: function(maxHeight, containerContent, container)
	{
        
        var realContainer = this.get_enableAnimations() ? this._animationsContainer : this._targetContainer;
        
		realContainer.style.left = -10000;
		realContainer.style.top = -10000;
		realContainer.style.display = 'block';
		realContainer.style.visibility = 'visible';

		if (maxHeight <= containerContent.offsetHeight)
		{
			container.style.height = maxHeight + 'px';
		}

		realContainer.style.left = 0;
		realContainer.style.top = 0;
		realContainer.style.display = 'none';
		realContainer.style.visibility = 'hidden';

	},

	///<summary>
	///  registers event handlers, initializes animation object (and animation container), sets the initial styles on the animation and target containers
	/// if the dropDownIsChild flag is true, we attach the dropdown container as a direct first child of the source element
	/// if not, it is absolutely positioned anywhere on the page and its position is calculated and adjusted using marginTop and MarginLeft
	///</summary>
	///<remarks>
	///
	///</remarks>
	init: function()
	{

		// attach handlers for the actual element events


		$addHandler(this._sourceElement, 'mouseup', this._mouseUpDelegate);
		$addHandler(this._sourceElement, 'click', this._mouseClickDelegate);
		$addHandler(this._sourceElement, 'mouseover', this._mouseOverDelegate);
		$addHandler(this._sourceElement, 'mousedown', this._mouseDownDelegate);
		$addHandler(this._sourceElement, 'keydown', this._keyDownDelegate);

		$addHandler(this._sourceElement, 'keyup', this._keyUpDelegate);
		$addHandler(this._sourceElement, 'focus', this._focusDelegate);
		$addHandler(this._sourceElement, 'blur', this._blurDelegate);

		if (this._dropDownIsChild)
		{

			this._sourceElement.appendChild(this._targetContainer);
		} else
		{

			document.forms[0].appendChild(this._targetContainer);
		}

		this._targetContainer.style.display = 'block';
		this._targetContainer.style.visibility = 'visible';
		//this._targetContainer.style.position= 'relative'; 
		this._targetContainer.style.position = ''; // very important for IE overflow:hidden bug. We must not set relative positioning !
		// stores the targetContainer height, so that it can be used later on - in case the actual height gets modified by animations and so on
		this._targetBounds = Sys.UI.DomElement.getBounds(this._targetContainer);
		this._containerHeight = this._targetBounds.height; // for convenience

		this._dropDownAnimation = new $IG.DropDownAnimation(this);
		this._dropDownAnimation.set_duration(this._animationDurationMs); // animation duration in milliseconds

		// look in the variable declaration for _animationsContainer for more info
		if (this._enableAnimations)
		{
			this._animationsContainer = document.createElement("div");
			this._animationsContainer.id = this._targetContainer.id + "_animations";
			this._animationsContainer.style.display = 'none';
			this._animationsContainer.style.visibility = 'hidden';
			this._animationsContainer.style.overflow = 'hidden'; // very important: so that the actual contents get correctly displayed while animating
			this._animationsContainer.style.position = 'absolute';
		}

		// choose the correct container to manipulate depending on whether animations are enabled or not
		// remember that for animations we use the approach where we create a separate animations container that is inserted
		// as the parent of our targetContainer. The target container has no knowledge
		// of the animations container
		var container = (this._enableAnimations) ? this._animationsContainer : this._targetContainer;


		if (this._dropDownIsChild)
		{
			this._sourceElement.insertBefore(container, this._sourceElement.firstChild);
		} else
		{
			// append as a first element of the first form !!!
			// if we append directly after the source (as a sibling), and the two
			// elements are in a scrolling container, some elements can still display
			// above the container !!! i.e. the dropdown container must be outside the scrolling container
			// for this to work properly
			document.forms[0].appendChild(container);
		}


		if (this._enableAnimations)
		{

			$util.setAbsoluteHeight(this._animationsContainer, 0);
			// if animations are enabled, we don't need to change the style of the targetContainer every time
			// it will just be controlled indirectly by the animationContainer's style
			this._containerHeight = this._targetBounds.height;
			//$util.setAbsoluteHeight(this._animationsContainer, this._targetBounds.height); // inherit the target container's height and width
			$util.setAbsoluteWidth(this._animationsContainer, this._targetBounds.width);

			// finally add this move handler, once we have attached the animations container - if any
			// background iFrame move handler (so that the iframe behind the popup contianer always stays
			// properly positioned
			$addHandler(this._animationsContainer, 'move', this._moveDelegate);

			// insert the animations container as a parent of the targetContainer
			this._animationsContainer.appendChild(this._targetContainer);

		} else
		{

			// if animations are disabled, directly change the style of the target container so that it is initially hidden
			this._targetContainer.style.display = 'none';
			this._targetContainer.style.visibility = 'hidden';
			this._targetContainer.style.position = 'absolute';
			$addHandler(this._targetContainer, 'move', this._moveDelegate);
		}

	},

	dispose: function()
	{


		// A.T: Bug #9792 Bug first , stop the animation, if any
		this._dropDownAnimation.stop();
		this._dropDownAnimation.onEnd();

		// remove event handlers
		/* O.K. 9410 10/22/08 - Behavior owner may have already disposed of this handler hence we need to wrap it in try/catch */
		try
		{
			$removeHandler(this._sourceElement, 'mouseup', this._mouseUpDelegate);
		} catch (e) { }

		/* O.K. 9410 10/22/08 - Behavior owner may have already disposed of this handler hence we need to wrap it in try/catch */
		try
		{
			$removeHandler(this._sourceElement, 'click', this._mouseClickDelegate);
		} catch (e) { }

		/* O.K. 9410 10/22/08 - Behavior owner may have already disposed of this handler hence we need to wrap it in try/catch */
		try
		{
			$removeHandler(this._sourceElement, 'mouseover', this._mouseOverDelegate);
		} catch (e) { }

		/* O.K. 9410 10/22/08 - Behavior owner may have already disposed of this handler hence we need to wrap it in try/catch */
		try
		{
			$removeHandler(this._sourceElement, 'mousedown', this._mouseDownDelegate);
		} catch (e) { }

		/* O.K. 9410 10/22/08 - Behavior owner may have already disposed of this handler hence we need to wrap it in try/catch */
		try
		{
			$removeHandler(this._sourceElement, 'keydown', this._keyDownDelegate);
		} catch (e) { }

		/* O.K. 9410 10/22/08 - Behavior owner may have already disposed of this handler hence we need to wrap it in try/catch */
		try
		{
			$removeHandler(this._sourceElement, 'keyup', this._keyUpDelegate);
		} catch (e) { }

		/* O.K. 9410 10/22/08 - Behavior owner may have already disposed of this handler hence we need to wrap it in try/catch */
		try
		{
			$removeHandler(this._sourceElement, 'focus', this._focusDelegate);
		} catch (e) { }

		/* O.K. 9410 10/22/08 - Behavior owner may have already disposed of this handler hence we need to wrap it in try/catch */
		try
		{
			$removeHandler(this._sourceElement, 'blur', this._blurDelegate);
		} catch (e) { }

		try
		{ /* Behavior owner may have already disposed of this handler hence we need to wrap it in try/catch */
			$removeHandler(this._targetContainer, 'move', this._moveDelegate);
		} catch (e) { }

		delete this._mouseUpDelegate;
		delete this._mouseClickDelegate;
		delete this._mouseOverDelegate;
		delete this._mouseDownDelegate;
		delete this._keyDownDelegate;
		delete this._keyUpDelegate;
		delete this._focusDelegate;
		delete this._blurDelegate;
		delete this._moveDelegate;

		// reset height, reset the animations container
		delete this._events;
		delete this._containerHeight;
		delete this._dropDownAnimation;
		delete this._animationsContainer;

		// clears the timeout for the automatic repositioning of the target container
		clearInterval(this._closeCheckID);
		delete this._closeCheckID;
		delete this._checkDelegate;
		/*
		DK 15 Oct 2008
		Since this is a javascript object, on dispose we break references to items on the
		html DOM as well.  
		*/
		// breaking connection to sourceElement and targetContainter
		this._sourceElement = null;
		this._targetContainer = null;

		// clear all used variables as well 
		delete this._position;
		this._outerContainer = null;
		delete this._offsetX;
		delete this._offsetY;
		delete this._containerHeight;
		delete this._offScreen;
		delete this._enableAutomaticPositioning;
		delete this._enableMovingTargetWithSource;
		delete this._enableAnimations;
		delete this._animationType;
		delete this._visible;
		delete this._visibleOnFocus;
		delete this._visibleOnBlur;
		delete this._visibleOnMouseOver;
		delete this._visibleOnClick;
		delete this._visibleOnKeyDown;
		delete this._dropDownAnimation;
		delete this._animationDurationMs;
		delete this._zIndex;
		delete this._targetBounds;
		delete this._dropDownIsChild;

	},

	//adjustPopupPosition: function(bounds)
	//{
	//    
	//}

	/****************************  END PUBLIC Methods ************************************/

	_onCheckPosition: function()
	{

		var oldPos = this._sourceLocation;
		var oldBounds = this._sourceBounds;

		// A.T. if true, it means that the dropdown is opened for some element (source) that is movable within a scrolling container
		// i.e. imagine a row edit template, whose parent is the row itself - hence, while the row is scrolled, if the dropdown
		// container and its row go off the visible grid area, we should close the dropdown 
		var shouldHideFromContainer = false;


		try
		{
			var currentPos = Sys.UI.DomElement.getLocation(this._sourceElement);
			var currentBounds = Sys.UI.DomElement.getBounds(this._sourceElement);

			// if this._outerContainer is defined, check whether the source element falls in the boundaries of the outerContainer
			if (this._outerContainer)
			{
				var outerContainerBounds = Sys.UI.DomElement.getBounds(this._outerContainer);
				var outerContainerPos = Sys.UI.DomElement.getLocation(this._outerContainer);
				if (currentPos.y + currentBounds.height > outerContainerBounds.height + outerContainerPos.y || currentPos.y < outerContainerPos.y)
				{
					shouldHideFromContainer = true;
				}
			}

		}
		catch (e)
		{
			return;
		}

		if (oldPos.x != currentPos.x || oldPos.y != currentPos.y || currentBounds.width != oldBounds.width || currentBounds.height != oldBounds.height)
		{

			if ((currentBounds.width <= 0 && currentBounds.height <= 0) || shouldHideFromContainer)
			{

				// source element is hidden, set the target to hidden as well
				this._targetContainer.style.visibility = 'hidden';
				this._targetContainer.style.display = 'none';

			} else
			{
				// reopen the dropdown
				if (this.get_visible())
				{
					this.set_visible(false);
					this.set_visible(true);
				}
			}

			this._sourceLocation = currentPos;
			this._sourceBounds = currentBounds;
		}
	},

	/****************************   EVENT HANDLERS ***************************************/

	_onMove: function()
	{
		/// <summary>
		/// Track the popup's movements so the hidden IFrame (IE6 only) can
		/// be moved along with it
		/// </summary>
		var container = (this._enableAnimations) ? this._animationsContainer : this._targetContainer;

		if (this._childFrame)
		{
			container.parentNode.insertBefore(this._childFrame, container);
			this._childFrame.style.top = container.style.top;
			this._childFrame.style.left = container.style.left;
		}
	},

	_mouseUpHandler: function(e)
	{
		// do we need this handler ? mouseClick should be enough
	},

	_mouseClickHandler: function(e)
	{
		// this.__handleTrigger(e);
	},

	_mouseOverHandler: function(e)
	{
		// cause the dropdown to show, if we have enabled this behavior via a set_visibleOnMouseOver(true) call
		if (this._visibleOnMouseOver)
		{
			this.__handleVisible(e);
		}
	},

	_mouseDownHandler: function(e)
	{
		// cause the dropdown to show, if we have enabled this behavior via a set_visibleOnMouseDown(true) call and mouseDown is invoked on the source
		if (this._visibleOnMouseDown)
		{
			this.__handleTrigger(e);
		}
	},

	_keyDownHandler: function(e)
	{
		// cause the dropdown to show, if we have enabled this behavior via a set_visibleOnKeyDown(true) call and keyDown is invoked on the source
		if (this._visibleOnKeyDown)
		{
			this.__handleVisible(e);
		}
	},

	_keyUpHandler: function(e)
	{
		// cause the dropdown to hide, if we have enabled this behavior via a set_visibleOnKeyDown(true) call and keyUp is invoked in the source
		if (this._visibleOnKeyDown)
		{
			this.__handleHidden(e);
		}
	},

	_focusHandler: function(e)
	{
		// cause the dropdown to show, if the source element gains focus
		if (this._visibleOnFocus)
		{
			this.__handleVisible(e);
		}
	},

	_blurHandler: function(e)
	{

		// cause the dropdown to hide, if the source element loses focus
		if (this._visibleOnBlur)
		{
			this.__handleHidden(e);
		}
	},

	/**************************** END EVENT HANDLERS *************************************/


	/***************************** PROTECTED Methods **************************************/

	_addBackgroundIFrame: function()
	{
		/// <summary>
		/// Add an empty IFRAME behind the popup (for IE6 only) so that SELECT, etc., won't
		/// show through the popup.
		/// </summary>

		// select the correct dropdown container depending on whether animations are enabled or not
		var container = (this._enableAnimations) ? this._animationsContainer : this._targetContainer;

		// Get the child frame
		if ((Sys.Browser.agent === Sys.Browser.InternetExplorer) && (Sys.Browser.version < 7))
		{

			// Create the child frame if it wasn't found
			if (!this._childFrame)
			{
				this._childFrame = document.createElement("iframe");
				this._childFrame.src = "javascript:'<html></html>';";
				this._childFrame.style.position = "absolute";
				this._childFrame.style.display = "none";
				this._childFrame.scrolling = "no";
				this._childFrame.frameBorder = "0";
				this._childFrame.tabIndex = "-1";
				this._childFrame.style.filter = "progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)";
				container.parentNode.insertBefore(this._childFrame, container);
			}

			// Position the frame exactly behind the element
			this._setBounds(this._childFrame, this._getBounds(container));
			this._childFrame.style.display = container.style.display; //inherit the display property 
			if (container.currentStyle && container.currentStyle.zIndex)
			{
				this._childFrame.style.zIndex = container.currentStyle.zIndex; // inherit the zIndex
			} else if (container.style.zIndex)
			{
				this._childFrame.style.zIndex = container.style.zIndex; // in case if it is inlined
			}
		}
	},

	/// sets the drop down as a child of the target
	_attach: function()
	{

		if (!this._dropDownIsChild)
		{
			this._sourceElement.appendChild(this._targetContainer);
		}
	},

	/// moves back the drop down into the animations frame (if any)
	_detach: function()
	{

		if (!this._dropDownIsChild)
		{
			if (this.get_enableAnimations())
			{

				this._animationsContainer.appendChild(this._targetContainer);
			}
			else
			{
				document.forms[0].appendChild(this._targetContainer);
			}
		}

	},

	_setAnimationEndListener: function(element)
	{
		this._animationEndListener = element;
	},

	_getBounds: function(element)
	{
		/// <summary>Gets the coordinates, width and height of an element.</summary>
		/// <param name="element" domElement="true"/>
		/// <returns type="Sys.UI.Bounds">
		///   A Bounds object with four fields, x, y, width and height, which contain the pixel coordinates,
		///   width and height of the element.
		/// </returns>
		var offset = $util.getPosition(element);
		return new Sys.UI.Bounds(offset.x, offset.y, element.offsetWidth || 0, element.offsetHeight || 0);
	},

	_setBounds: function(element, bounds)
	{
		/// <summary>
		/// Sets the "border-box" bounds of an element
		/// </summary>
		/// <param name="element" type="Sys.UI.DomElement" domElement="true">
		/// DOM element
		/// </param>
		/// <param name="bounds" type="Object">
		/// Bounds of the element (of the form {x,y,width,height})
		/// </param>
		/// <remarks>
		/// The "border-box" is the size of the content area *outside* of the borders and
		/// padding of an element.  The "border-box" size does not include the margins around
		/// the element.
		/// </remarks>

		if (!element)
		{
			throw Error.argumentNull('element');
		}
		if (!bounds)
		{
			throw Error.argumentNull('bounds');
		}
		$util.setAbsoluteHeight(element, bounds.height);
		$util.setAbsoluteWidth(element, bounds.width);

		this.__setLocation(element, bounds);
	},

	_adjustDropDownPosition: function(targetBounds, sourceBounds, currentX, currentY)
	{
		/// <summary>
		/// when the positioning is default/auto, and we detect that the dropdown 
		/// cannot be displayed below, we flip it to be displayed above the source element
		/// </summary>
		/// <param name="targetBounds" type="Sys.UI.Bounds" domElement="false">
		/// bounds of the target container
		/// </param>
		/// <param name="sourceBounds" type="Sys.UI.Bounds" domElement="false">
		/// bounds of the source element
		/// </param>
		/// <param name="currentX" type="int" domElement="false">
		/// current marginLeft offset
		/// </param>
		/// <param name="currentY" type="int" domElement="false">
		/// current marginTop offset
		/// </param>
		/// <remarks>
		/// </remarks>

		// whether the dropdown will be off the screen or not
		this._offScreen = false;
		var x = currentX, y = currentY;
		// target container bounds

		// retrieve the correct container reference depending on whether we have 
		// animations enabled or not
		var container = (this._enableAnimations) ? this._animationsContainer : this._targetContainer;

		// the current position (left,top) of the dropdown container
		// var targetContainerPosition = $util.getPosition(container);
		var targetContainerPosition = Sys.UI.DomElement.getLocation(container);

		//   var sourceElementPosition = $util.getPosition(this._sourceElement);
		var sourceElementPosition = Sys.UI.DomElement.getLocation(this._sourceElement);
		// x = targetContainerPosition.x;
		// y = sourceElementPosition.y - targetContainerPosition.y;

		// if reset is set to true, we will modify the container's marginTop property
		var reset = false;

		// detectoverflow on the bottom
		// note that it is very important that we account for the body scrollTop as well !!!
		var windowHeight = 0;
		var windowScrollTop = 0;

		if (document.compatMode == "BackCompat")
		{

			windowHeight = document.body.clientHeight;
			windowScrollTop = document.body.scrollTop;

		} else
		{
			// quirks
			windowHeight = window.innerHeight;
			windowScrollTop = window.pageYOffset;

			if ($util.IsIE)
			{
				windowHeight = document.documentElement.clientHeight;
				windowScrollTop = document.documentElement.scrollTop;
			}

		}

		// A.T. Bug #9407 - check if outerContainer was defined , in that case our boundaries
		// aren't the browser window or frame itself, but the container (i.e. grid fixed div)
		// so we should check the target location against these container bounds

		if (this._outerContainer)
		{

			// algorithm: 
			// 1. the target container is bigger than the outer container => show it below (always)

			// 2. the target container can be shown below (fully ) => show it below

			// 3. the target container cannot be shown below (will go off the bounds) , but: 
			// 3. a) will also go off the bounds if shown above => show it below
			// 3. b) will not go off the bounds if shown above => show it above

			// targetBounds
			// targetContainerPosition

			var outerContainerPos = Sys.UI.DomElement.getLocation(this._outerContainer);
			var outerContainerBounds = Sys.UI.DomElement.getBounds(this._outerContainer);

			if (targetBounds.height < outerContainerBounds.height)
			{
				if (targetContainerPosition.y + targetBounds.height > outerContainerPos.y + outerContainerBounds.height)
				{
					// try to show it above
					// 3.a)
					if (targetContainerPosition.y - targetBounds.height > outerContainerPos.y)
					{
						// flip the container position
						y -= targetBounds.height;

						if (this.get_position() != $IG.DropDownPopupPosition.Left && this.get_position() != $IG.DropDownPopupPosition.Right)
						{
							y -= sourceBounds.height;
						} else
						{
							y += sourceBounds.height;
						}

						reset = true;
						this._offScreen = true;
						y -= this._offsetY * 2; // account for the "Y" offset, but in the reverse direction
						// note that since we have already accounted for it, we need to do this twice now   
					}
				}
			}

		} else if (targetBounds.height > windowHeight - sourceElementPosition.y + windowScrollTop)
		{
			// flip the container position
			y -= targetBounds.height;

			if (this.get_position() != $IG.DropDownPopupPosition.Left && this.get_position() != $IG.DropDownPopupPosition.Right)
			{
				y -= sourceBounds.height;
			} else
			{
				y += sourceBounds.height;
			}

			reset = true;
			this._offScreen = true;
			y -= this._offsetY * 2; // account for the "Y" offset, but in the reverse direction
			// note that since we have already accounted for it, we need to do this twice now
		}

		if (reset)
		{
			container.style.marginTop = y + 'px';
		}

	},

	/***************************** END PROTECTED Methods **********************************/


	/***************************** PRIVATE Methods ****************************************/

	// helper method
	__handleHidden: function(e)
	{

		if (this._visible)
		{
			this.set_visible(false);
		}
	},

	// helper method
	__handleVisible: function(e)
	{
		if (!this._visible)
		{
			this.set_visible(true);
		}
	},

	// helper method
	__handleTrigger: function(e)
	{
		if (this._visible)
		{
			this.set_visible(false);
		} else
		{
			this.set_visible(true);
		}
	},

	__showDropDown: function()
	{
		/// <summary>
		/// Causes the dropdown to show
		/// </summary>

		// retrieve the correct container reference depending on whether we have animations enabled or not
		var container = (this._enableAnimations) ? this._animationsContainer : this._targetContainer;

		// initialize the container before we show it
		container.style.position = 'absolute';
		container.style.display = '';
		container.style.visibility = 'visible';
		container.style.zIndex = this._zIndex;

		/*
		*
		* we position the dropdown container to the source, by varying its marginLeft and marginTop properties
		*
		*/
		var x = 0, y = 0; // marginLeft, marginTop

		// default is left bottom
		y = Sys.UI.DomElement.getBounds(this._sourceElement).height;

		var targetBounds = this._targetBounds;
		var sourceBounds = Sys.UI.DomElement.getBounds(this._sourceElement);

		// if we want the container to be positioned anywhere above the source element
		var isTop = this._position == $IG.DropDownPopupPosition.TopLeft || this._position == $IG.DropDownPopupPosition.TopRight;

		// handle positioning
		switch (this._position)
		{

			case $IG.DropDownPopupPosition.Default:
				// default is left bottom . Also handles AUTO
				break;
			case $IG.DropDownPopupPosition.Center: // default is bottom
				x += sourceBounds.width / 2;
				x -= targetBounds.width / 2;
				break;
			case $IG.DropDownPopupPosition.Left:
				x -= targetBounds.width;
				y -= sourceBounds.height;
				break;
			case $IG.DropDownPopupPosition.Right:
				x += sourceBounds.width;
				y -= sourceBounds.height;
				break;
			case $IG.DropDownPopupPosition.BottomLeft:
				// this is the default positioning
				//x = 
				//y = 
				break;
			case $IG.DropDownPopupPosition.BottomRight:
				x += sourceBounds.width;
				x -= targetBounds.width;
				//y = 
				break;
			case $IG.DropDownPopupPosition.TopLeft:
				// x = 0;
				y -= targetBounds.height;
				y -= sourceBounds.height;
				break;
			case $IG.DropDownPopupPosition.TopRight:
				x += sourceBounds.width;
				x -= targetBounds.width;
				y -= targetBounds.height;
				y -= sourceBounds.height;
				break;
			default:
				break;
		}

		//if(!this._dropDownIsChild)
		//{
		container.style.marginLeft = '';
		container.style.marginTop = '';

		//  var p0 = $util.getPosition(this._sourceElement), p1 = $util.getPosition(container);
		var p0 = Sys.UI.DomElement.getLocation(this._sourceElement), p1 = Sys.UI.DomElement.getLocation(container);

		// A.T. Fix for Bug 9553
		if (Sys.Browser.agent == Sys.Browser.Safari && this._sourceElement.nodeName == 'TD')
		{
			y -= this._sourceElement.offsetTop;
			y += this._sourceElement.parentNode.offsetTop;
		}

		if (this._outerContainer && Sys.Browser.agent == Sys.Browser.Opera)
		{
			y -= this._outerContainer.scrollTop;
		}

		x += p0.x - p1.x;
		y += p0.y - p1.y;

		// A.T: BR35639: Dropdown framework: scrollX and scrollY are not taken into account
		//x -= p0.scrollX;
		//y -= p0.scrollY;
		//}

		// account for offsetX and offsetY
		x += this._offsetX;
		if (isTop)
		{
			y -= this._offsetY;
		} else
		{
			y += this._offsetY;
		}

		container.style.marginLeft = x + 'px';
		container.style.marginTop = y + 'px';

		// adjust the dropdown position in case it will display off the screen
		if (!isTop && this._enableAutomaticPositioning)
		{
			this._adjustDropDownPosition(targetBounds, sourceBounds, x, y);
		}

		/*AK 12-Mar-2009 this gets hidden in _onCheckPosition*/
		this._targetContainer.style.display = "";
		this._targetContainer.style.visibility = "visible";

		// in case the currentHeight was set when the container was in display:none mode
		// we want to make sure that the correct height is stored
		var currentHeight = Sys.UI.DomElement.getBounds(this._targetContainer).height;
		//if (currentHeight > this._containerHeight) {
		this._containerHeight = currentHeight;
		//}

		// adds an iframe on the back of the dropdown container in order to handle the SELECT bug with IE 6
		this._addBackgroundIFrame();

		// we need to know what is the max height towards which the animation will grow the container
		this._dropDownAnimation.set_maxHeight(this._containerHeight);

		if (this._enableAnimations)
		{
			this._dropDownAnimation.play(); // start the 'show' animation

		}

	},

	__hideDropDown: function()
	{
		if (this._enableAnimations)
		{
			this._dropDownAnimation.play(); // start the 'hide' animation

		} else
		{
			// if animations are enabled the stuff below will be done in the end() animation method
			this._targetContainer.style.display = 'none';
			this._targetContainer.style.visibility = 'hidden';
			// hide the background iframe
			if (this._childFrame)
			{
				this._childFrame.style.display = "none";
			}

		}

	},

	__notifyAnimationEnd: function()
	{
		if (this._animationEndListener != null && this._animationEndListener._onAnimationEnd)
			this._animationEndListener._onAnimationEnd();
	},

	__setLocation: function(element, point)
	{
		/// <summary>
		/// Sets the current location for an element.
		/// </summary>
		/// <param name="element" type="Sys.UI.DomElement" domElement="true">
		/// DOM element
		/// </param>
		/// <param name="point" type="Object">
		/// Point object (of the form {x,y})
		/// </param>
		/// <remarks>
		/// This method does not attempt to set the positioning mode of an element.
		/// The position is relative from the elements nearest position:relative or
		/// position:absolute element.
		/// </remarks>
		Sys.UI.DomElement.setLocation(element, point.x, point.y);
	}

	/***************************** END PRIVATE Methods ************************************/

};

$IG.DropDownBehavior.registerClass("Infragistics.Web.UI.DropDownBehavior");


/* this class is not yet implemented */
$IG.UIObjectDropDownBehavior = function()
{
    ///<summary>
    /// An object that allows the developer to specify elements and/or UIObjects that 
    /// should be source elements and/or target elements.  the Target element wll be the 
    /// drop down target (popup) while the source will be the element that receives 
    /// drop down events
    ///</summary>
}

$IG.UIObjectDropDownBehavior.prototype = 
{

};

$IG.UIObjectDropDownBehavior.registerClass("Infragistics.Web.UI.UIObjectDropDownBehavior");


$IG.DropDownEvents = function (behavior) 
{

    ///<summary>
    /// An object that allows the developer to attach event listeners associated with a 
    /// Infragistics.Web.UI.DropDownBehavior. All handlers should have the following signature: 
    /// handler (behavior, evntArgs)
    ///</summary>
    this._handlers ={};
    this._behavior = behavior;
}

$IG.DropDownEvents.prototype = 
{
    // this will be invoked after the dropdown container has been shown
    addSetVisibleHandler:function(handler)
    {
        ///<summary>
        /// 
        ///</summary>
        ///<param name="handler" type="Function">
        /// The function that should be called when the event is fired.
        ///</param>
        ///<remarks>
        ///
        ///</remarks>
        this.__addHandler("SetVisible", handler, $IG.DropDownEventArgs);
    },
    
    // this will be invoked after the dropdown container has been hidden
    addSetHiddenHandler:function(handler)
    {
        ///<summary>
        /// 
        ///</summary>
        ///<param name="handler" type="Function">
        /// The function that should be called when the event is fired.
        ///</param>
        ///<remarks>
        ///
        ///</remarks>
        this.__addHandler("SetHidden", handler, $IG.DropDownEventArgs);
    },
    
    // this will be invoked before the dropdown is physically hidden on the screen
    addSettingHiddenHandler:function(handler)
    {
        ///<summary>
        /// 
        ///</summary>
        ///<param name="handler" type="Function">
        /// The function that should be called when the event is fired.
        ///</param>
        ///<remarks>
        ///
        ///</remarks>
        this.__addHandler("SettingHidden", handler, $IG.CancelDropDownEventArgs);
    },
    
    // this will be invoked before the dropdown is physically shown on the screen
    addSettingVisibleHandler:function(handler)
    {
        ///<summary>
        /// 
        ///</summary>
        ///<param name="handler" type="Function">
        /// The function that should be called when the event is fired.
        ///</param>
        ///<remarks>
        ///
        ///</remarks>
        this.__addHandler("SettingVisible", handler, $IG.CancelDropDownEventArgs);
    },
    
    removeSetVisibleHandler:function()
    {
        ///<summary>
        /// removes the handler
        ///</summary>
        ///<remarks>
        ///
        ///</remarks>
        this.__removeHandler("SetVisible");
    },
    
    removeSettingVisibleHandler:function()
    {
        ///<summary>
        /// removes the handler
        ///</summary>
        ///<remarks>
        ///
        ///</remarks>
        this.__removeHandler("SettingVisible");
    },
    
    removeSetHiddenHandler:function()
    {
        ///<summary>
        /// 
        ///</summary>
        ///<remarks>
        ///
        ///</remarks>
        this.__removeHandler("SetHidden");
    },
    
    removeSettingHiddenHandler:function()
    {
        ///<summary>
        /// 
        ///</summary>
        ///<remarks>
        ///
        ///</remarks>
        this.__removeHandler("SettingHidden");
    },
    
    // we keep a map of handlers that have been registered
    __addHandler:function(name, handler, args)
    {
		var handlers = this._handlers[name];
		if(!handlers)
			this._handlers[name] = handlers = [];
		/* find not null item */
		var i = -1;
		while(++i < handlers.length)
			if(handlers[i])
				break;
		handlers[i] = [handler, args];
    },
    
    __removeHandler:function(name, handler, args)
    {
		var handlers = this._handlers[name];
		if(!handlers)
			return;
		var i = -1;
		while(++i < handlers.length)
		{
			var obj = handlers[i];
			if(obj && obj[0] == handler)
				handlers[i] = null;
		}
    },
    
    // fires an event using the registered handler for that event
    _fireEvent:function(name, evntArgs)
    {
		var handlers = this._handlers[name];
		var count = handlers ? handlers.length : 0;
		for(var i = 0; i < count; i++)
		{
			var handler = handlers[i];
			if(!handler)
				continue;
			var evnt = handler[0];
			var args = new handler[1](evntArgs);
			// if the cancel flag was set in the DropDown cancel event arguments
			// we will cancel this event
			evnt(this._behavior, args);
			if(args._cancel)
				return true; // will cancel
		}
		return false;
    }
}

$IG.DropDownEvents.registerClass("Infragistics.Web.UI.DropDownEvents");

$IG.DropDownEventArgs = function(behavior) 
{
    ///<summary>
    /// arguments class for dropdown events
    ///</summary>
    this._behavior = behavior;
}

$IG.DropDownEventArgs.prototype = 
{
    get_source: function()
    {
        ///<summary>
        /// 
        ///</summary>
        ///<remarks>
        ///
        ///</remarks>
        return this._behavior.get_sourceElement();
    },
    
    get_targetContainer: function()
    {
        ///<summary>
        /// 
        ///</summary>
        ///<remarks>
        ///
        ///</remarks>
        return this._behavior.get_targetContainer();
    },
    
    get_targetContent: function()
    {
        ///<summary>
        /// 
        ///</summary>
        ///<remarks>
        ///
        ///</remarks>
        return this._behavior.get_targetContent();
    },
    
    get_dropDownBehavior: function()
    {
        ///<summary>
        /// 
        ///</summary>
        ///<remarks>
        ///
        ///</remarks>
        return this._behavior;
    }
    
}

$IG.DropDownEventArgs.registerClass("Infragistics.Web.UI.DropDownEventArgs");


$IG.CancelDropDownEventArgs = function() 
{
    this._cancel = false; // to cancel the event
    $IG.CancelDropDownEventArgs.initializeBase(this);
}

$IG.CancelDropDownEventArgs.prototype = 
{
    get_cancel: function()
    {
        ///<summary>
        /// 
        ///</summary>
        ///<remarks>
        ///
        ///</remarks>
        return this._cancel;
    },
    
    set_cancel: function(cancel)
    {
        ///<summary>
        /// 
        ///</summary>
        ///<remarks>
        ///
        ///</remarks>
        this._cancel = cancel;
    }
}

$IG.CancelDropDownEventArgs.registerClass("Infragistics.Web.UI.CancelDropDownEventArgs", $IG.DropDownEventArgs);


///------------- DROP DOWN ANIMATION ----------------------

$IG.DropDownAnimation = function(behavior)
{
    ///
    /// <summary>
    /// the drop down animation extends $IG.AnimationBase
    /// it is a very simple animation that manipulates the height of the animationContainer which is the parent of the target dropdown container
    /// in case the animation is performed from bottom to top, we also manipulate the marginTop property
    /// to create the effect that the container actually slides from bottom to top
    ///
    /// we change the animationContainer's height on every animation tick, in the onNext() method
    /// </summary>
    ///
    this._dropDownBehavior = behavior;
    this._increaseDelta = 0; // number of pixels by which we modify the height on every animation tick
    this._marginDelta=0;
    this._accumulatedHeight = 0; // currently accumulated height
    this._maxHeight = 0; // maximum height to which we will grow the container
    this._minHeight=0;
    this._maxMargin=0; // max margin if the animation is from bottom to top
    this._container = null;
    this._isTop = false;
    this._accumulatedMarginTop = 0; // if the animation is from bottom to top
    
    $IG.DropDownAnimation.initializeBase(this);
}

$IG.DropDownAnimation.prototype = 
{

    set_maxHeight:function(maxHeight) {
    
        this._maxHeight = maxHeight;
    },

    onBegin:function() {

        this._container = this._dropDownBehavior.get_animationsContainer();
        
        var pos = this._dropDownBehavior.get_position();
        
        // calculate the number of pixels to increase the container height
        // we don't really need this if we use calc() from $IG.AnimationBase
        //this._increaseDelta = this._maxHeight / this.get_duration();
        
        if (this._dropDownBehavior.get_visible())
        {
            this._accumulatedHeight = this._maxHeight;
            // since the dropdown is already shown, and we will be performing an top to bottom 
            // animation, we will actually decrease the height of the container
            // this is not needed if we use calc() from $IG.AnimationBase
            this._increaseDelta = -1*this._increaseDelta;
        }

        if (this._dropDownBehavior.get_offScreen() || pos == $IG.DropDownPopupPosition.TopLeft || pos == $IG.DropDownPopupPosition.TopRight)
        {
            // in the case when the drop down container is positioned above the source element
            // we need to also change the marginTop to create the visually correct animation effect
            this._isTop = true;        
            this._marginDelta = this._increaseDelta;
            // we will grow the margin until it reaches the initial margin as if 
            // there was no animation taking place
            this._maxMargin = parseInt(this._container.style.marginTop); 

            // initial marginTop
            this._accumulatedMarginTop = this._maxMargin + this._maxHeight;
            
            if (this._dropDownBehavior.get_visible()) {
                // in case the dropdown is positioned above, and is already shown and the
                // animation will be from top to bottom (hiding)
                this._accumulatedMarginTop = this._maxMargin;
            }
            
            this._container.style.marginTop = this._accumulatedMarginTop + 'px';

           // this._accumulatedMarginTop = $util.getPosition(this._dropDownBehavior.get_sourceElement()).y;
            

            /*
            if (this._dropDownBehavior._dropDownIsChild) {
            
                if (this._dropDownBehavior.get_Visible()) {
                    this._accumulatedMarginTop = 0;
                } else {
                    this._accumulatedMarginTop = -1*this._accumulatedMarginTop;
                }
            }

            if (!this._dropDownBehavior.get_Visible() && !this._dropDownBehavior._dropDownIsChild)
            {
                this._accumulatedMarginTop = $util.getPosition(this._dropDownBehavior.get_targetContainer()).y;
                
            } 
            */
            
            //this._container.style.marginTop = this._accumulatedMarginTop + 'px';
        }

    },
    
    onNext:function() {
    
       // modify the height
      // if (this._dropDownBehavior.get_Visible()) {
      //  this._increaseDelta = this._calc($IG.AnimationEquationType.EaseInOut, this._time, this._maxHeight, 0, this.get_duration());
       //} else {
        this._increaseDelta = this._calc(this._dropDownBehavior.get_animationType(), this._time, 0, this._maxHeight, this.get_duration());
      // }

      if (this._dropDownBehavior.get_visible()) {
       this._increaseDelta = -1*this._increaseDelta;
      } 
      
      this._accumulatedHeight += this._increaseDelta;
       
       // stop the animation if we have surpassed the maximum height we can grow to
       if (this._accumulatedHeight >= this._maxHeight || this._accumulatedHeight <0 ) {
       
           if (this._accumulatedHeight<0)
                this._accumulatedHeight=0; 
           else if (this._accumulatedHeight>this._maxHeight)
                this._accumulatedHeight=this._maxHeight; // the accumulated height should never grow above the maximum height

           this.stop(); // stop the current animation -> onEnd will be called after this function exits
           
       } 
       if (this._isTop)
       {    
            this._accumulatedMarginTop -= this._increaseDelta;
            this._container.style.marginTop = parseInt(this._accumulatedMarginTop) + 'px';
           
       }
       
        $util.setAbsoluteHeight(this._container, parseInt(this._accumulatedHeight));
        
        // handle the background iFrame (IE6)
        if (this._dropDownBehavior._childFrame) {
            $util.setAbsoluteHeight(this._dropDownBehavior._childFrame, parseInt(this._accumulatedHeight));
        }
    },
    
    onEnd:function() {

        if (this._isTop) {
            // if the dropdown container is positioned on the top and we are changing the margins as well
            // we need to make sure that the current accumulated margin top doesn't surpass or goes below
            // the maximum initial margin, after the animation ends
            if (this._accumulatedMarginTop != this._maxMargin)
            {
                this._container.style.marginTop = this._maxMargin + 'px';
            }
        }
        
        //re-initialize these variables for the next animation play
        this._accumulatedHeight=0;
        this._accumulatedMarginTop = 0;
        this._increaseDelta=0;
        this._marginDelta=0;
        this._isTop=false;

        // the dropdown was visible, now we need to hide the container because 
        // it is hidden now
        /* ----------------------------- IMPORTANT ----------------------------------------- */
        // we must not call set_Visible as it will actually want to cause the popup
        // to show and hide
        // we just flip the _visible property in the dropdown behavior
        /* --------------------------------------------------------------------------------- */
        if (this._dropDownBehavior.get_visible()) {        

            this._container.style.display = 'none';
		    this._container.style.visibility = 'hidden';
		    // hide the iframe
		    if (this._dropDownBehavior._childFrame) {
                this._dropDownBehavior._childFrame.style.display = "none";
            }
            this._dropDownBehavior._visible = false;
         
        } else {
            this._dropDownBehavior._visible = true;
        }
        
        // notify listener for animation end event
        this._dropDownBehavior.__notifyAnimationEnd();

    }
}

$IG.DropDownAnimation.registerClass("Infragistics.Web.UI.DropDownAnimation", $IG.AnimationBase);