﻿//-----------------------------------------------------------------------------
// XControl
//
// Copyright 2005-2010 - Xcential Group LLC.
//
//-----------------------------------------------------------------------------

//=============================================================================
// Constructor

function XControl(
   id,
   create
)
{
   id = (id == null) ? null : id;
   create = (create == null) ? true : false;

   if (create)
      return new XControl(id, false);

   //--------------------------------------------------------------------------
   // Private Interface

   //--------------------------------------------------------------------------
   // Privileged Interface

   this.valueOf = function()
   {

      return oSpec;
   }

   //--------------------------------------------------------------------------

   this.setObjectValue = function(
      id
   )
   {
      id = (id == null) ? null : id;

      oSpec = XControl.getSpecFrom(id);

      return oSpec;
   }

   //--------------------------------------------------------------------------
   // Initialization

   var oSpec = this.setObjectValue(id);

   XControl.controls[oSpec.id] = this;

}

XControl.prototype.objectClass = "XControl";

//=============================================================================
// Static Interface

XControl.controls = new Array();

XControl.APPLY = true;
XControl.DONT_APPLY = false;

XControl.EXPAND = "expand";
XControl.COLLAPSE = "collapse";
XControl.TOGGLE = "toggle";

//-----------------------------------------------------------------------------

XControl.getSpecFrom = function(
   idOrRef
)
{
   idOrRef = (idOrRef == null) ? XUtils.generateId("urn:xcential-com:control:", XUtils.SCHEME_RANDOM) : idOrRef;

   var spec = null;
   switch (typeof(idOrRef))
   {
      case "string":
         var id = idOrRef;
         spec = new Array();
         spec.id = id;
         spec.className = "XControl";
         spec.tabIndex = null;
         spec.htmlNode = null;
         spec.mouseIn = false
         spec.mouseOut = true;
         spec.visible = true;
         spec.left = null;
         spec.top = null;
         spec.right = null;
         spec.bottom = null;
         spec.width = null;
         spec.height = null;
         spec.shadowSize = 0;
         spec.events = [];
         spec.quirksMode = false;
         break;
      case "number":
         throw XMsg("Cannot create a control from a number.");
         break;
      case "boolean":
         throw XMsg("Cannot create a control from a boolean.");
         break;
      case "function":
         try
         {
            return XControl.getSpecFrom(idOrRef());
         }
         catch (error)
         {
            XApp.logEvent(XApp.EVENT_ERROR, error);
            throw XMsg("Cannot create a control from a boolean.", error);
         }
      case "object":
         if (idOrRef.objectClass != null)
         {
            spec = XControl.getSpecFrom(idOrRef.valueOf());
         }
         else
         {
            spec = idOrRef;
            if (spec.className == null)
            {
               XApp.logEvent(XApp.EVENT_ERROR, error);
               throw XMsg("Cannot create a control from an invalid function or object.", error);
            }
         }
         break;
   }

   return spec;
}

//-----------------------------------------------------------------------------

XControl.getPixelHeight = function(
   id
)
{

   var element = $(id)

   var pixelHeight = null;
   if (false && element.runtimeStyle != null)
      pixelHeight = element.runtimeStyle["pixelHeight"];
   if (pixelHeight == null || pixelHeight == "")
      pixelHeight = element.style["pixelHeight"];
   if (pixelHeight == null || pixelHeight == "" || pixelHeight == 0)
   {
      if (element.style.pixelHeight)
         pixelHeight = element.style.pixelHeight;
      else
         pixelHeight = element.offsetHeight;
   }

   return pixelHeight;
}

//-----------------------------------------------------------------------------

XControl.getPixelWidth = function(
   id
)
{

   var element = $(id)

   var pixelWidth = null;
   if (false && element.runtimeStyle != null)
      pixelWidth = element.runtimeStyle["pixelWidth"];
   if (pixelWidth == null || pixelWidth == "")
      pixelWidth = element.style["pixelWidth"];
   if (pixelWidth == null || pixelWidth == "" || pixelWidth == 0)
   {
      if (element.style.pixelWidth)
         pixelWidth = element.style.pixelWidth;
      else
         pixelWidth = element.offsetWidth;
   }

   return pixelWidth;
}

//=============================================================================
// Event Handlers

XControl.prototype.onShow = null;
XControl.prototype.onHide = null;
XControl.prototype.onMouseEnter = null;
XControl.prototype.onMouseOver = null;
XControl.prototype.onMouseOut = null;
XControl.prototype.onMouseLeave = null;
XControl.prototype.onFocus = null;
XControl.prototype.onBlur = null;
XControl.prototype.onClick = null;
XControl.prototype.onKeyDown = null;
XControl.prototype.onAfterDraw = null;
XControl.prototype.onAfterRedraw = null;

XControl.prototype.toHTML = null;
XControl.prototype.configurePositioning = null;

//=============================================================================
// Event handlers

XControl.prototype.doMouseEnter = function(
   event
)
{
   event = (event == null) ? window.event : event;

   var spec = XControl.getSpecFrom(this.valueOf());

   spec.mouseIn = true;

   if (this.onMouseEnter)
      this.onMouseEnter(this);

}

//-----------------------------------------------------------------------------

XControl.prototype.doMouseOver = function(
   event
)
{
   event = (event == null) ? window.event : event;

   var spec = XControl.getSpecFrom(this.valueOf());

   if (spec.mouseIn == false)
      this.doMouseEnter(event);

   spec.mouseOut = false;

   if (this.onMouseOver)
      this.onMouseOver(this);

}

//-----------------------------------------------------------------------------

XControl.prototype.doMouseOut = function(
   event
)
{
   event = (event == null) ? window.event : event;

   var spec = XControl.getSpecFrom(this.valueOf());

   spec.mouseOut = true;

   setTimeout("XControl.controls['" + spec.id + "'].doMouseLeave(null)", 100);

   if (this.onMouseOut)
      this.onMouseOut(this);

}

//-----------------------------------------------------------------------------

XControl.prototype.doMouseLeave = function(
   event
)
{
   event = (event == null) ? window.event : event;

   var spec = XControl.getSpecFrom(this.valueOf());

   if (spec.mouseOut == false)
      return;

   spec.mouseIn = false;

   if (this.onMouseLeave)
      this.onMouseLeave(this);

}

//-----------------------------------------------------------------------------

XControl.prototype.doFocus = function(
   event
)
{
   event = (event == null) ? window.event : event;

   var spec = XControl.getSpecFrom(this.valueOf());

   if (this.onFocus)
      this.onFocus(this);

}

//-----------------------------------------------------------------------------

XControl.prototype.doBlur = function(
   event
)
{
   event = (event == null) ? window.event : event;

   var spec = XControl.getSpecFrom(this.valueOf());

   if (this.onBlur)
      this.onBlur(this);

}

//-----------------------------------------------------------------------------

XControl.prototype.doKeyDown = function(
   event
)
{
   event = (event == null) ? window.event : event;

   var spec = XControl.getSpecFrom(this.valueOf());

   if (this.onKeyDown)
      this.onKeyDown(this);
   else
   {
      var keyCode = event.keyCode;
      if (keyCode == XUI.KEY_ENTER)
      {
         this.doClick(event);
      }
   }

}

//-----------------------------------------------------------------------------

XControl.prototype.doClick = function(
   event
)
{
   event = (event == null) ? window.event : event;

   var spec = XControl.getSpecFrom(this.valueOf());

   //var htmlNode = spec.htmlNode;
   //if (htmlNode)
   //   htmlNode.focus();

   if (this.onClick)
      this.onClick(this);

}

//=============================================================================
// Public Interface

XControl.prototype.getId = function()
{

   var spec = XControl.getSpecFrom(this.valueOf());

   return spec.id;
}

//-----------------------------------------------------------------------------

XControl.prototype.getClass = function(
   castAs
)
{
   castAs = (castAs == null) ? null : castAs;

   var spec = XControl.getSpecFrom(this.valueOf());

   var className = spec.className;

   return (className == null) ? null : (castAs == null) ? className : castAs(className);
}

//-----------------------------------------------------------------------------

XControl.prototype.setClass = function(
   className
)
{
   className = (className == null) ? "XControl" : className;

   var spec = XControl.getSpecFrom(this.valueOf());

   spec.className = className;

   return className;
}

//-----------------------------------------------------------------------------

XControl.prototype.setTabIndex = function(
   tabIndex
)
{
   tabIndex = (tabIndex == null) ? null : tabIndex;

   var spec = XControl.getSpecFrom(this.valueOf());

   spec.tabIndex = tabIndex;

   return tabIndex;
}

//-----------------------------------------------------------------------------

XControl.prototype.getHtmlNode = function(
   castAs
)
{
   castAs = (castAs == null) ? null : castAs;

   var spec = XControl.getSpecFrom(this.valueOf());

   var htmlNode = spec.htmlNode;

   return (htmlNode == null) ? null : (castAs == null) ? htmlNode : castAs(htmlNode);
}

//-----------------------------------------------------------------------------

XControl.prototype.setHtmlNode = function(
   htmlNode
)
{

   var spec = XControl.getSpecFrom(this.valueOf());

   spec.htmlNode = htmlNode;

   return spec.htmlNode;
}

//-----------------------------------------------------------------------------

XControl.prototype.synchHtmlNode = function()
{

   var spec = XControl.getSpecFrom(this.valueOf());

   var htmlNode = $(spec.id);
   if (htmlNode)
      spec.htmlNode = htmlNode;

   return spec.htmlNode;
}

//-----------------------------------------------------------------------------

XControl.prototype.isVisible = function()
{

   var spec = XControl.getSpecFrom(this.valueOf());

   return spec.visible;
}

//-----------------------------------------------------------------------------

XControl.prototype.show = function()
{

   var spec = XControl.getSpecFrom(this.valueOf());

   spec.visible = true;

   if (spec.htmlNode)
      XUI(spec.htmlNode).setRuntimeStyle("display", "block");

   if (this.onShow)
      this.onShow(this);

   return spec.htmlNode;
}

//-----------------------------------------------------------------------------

XControl.prototype.hide = function()
{

   var spec = XControl.getSpecFrom(this.valueOf());

   spec.visible = false;

   if (spec.htmlNode)
      XUI(spec.htmlNode).setRuntimeStyle("display", "none");

   if (this.onHide)
      this.onHide(this);

   return spec.htmlNode;
}

//-----------------------------------------------------------------------------

XControl.prototype.setPosition = function(
   left,
   top,
   right,
   bottom,
   apply
)
{
   left = (left == null) ? null : left;
   top = (top == null) ? null : top;
   right = (right == null) ? null : right;
   bottom = (bottom == null) ? null : bottom;
   apply = (apply == null) ? XControl.APPLY : apply;

   var spec = XControl.getSpecFrom(this.valueOf());

   spec.left = (left != null) ? left : spec.left;
   spec.top = (top != null) ? top : spec.top;
   spec.right = (right != null) ? right : spec.right;
   spec.bottom = (bottom != null) ? bottom : spec.bottom;

   if (apply && spec.htmlNode && !spec.minimized && !spec.maximized)
      this.applyPositioning();

   return spec.htmlNode;
}

//-----------------------------------------------------------------------------

XControl.prototype.setDimensions = function(
   width,
   height,
   apply
)
{
   width = (width == null) ? null : width;
   height = (height == null) ? null : height;
   apply = (apply == null) ? XControl.APPLY : apply;

   var spec = XControl.getSpecFrom(this.valueOf());

   spec.width = (width != null) ? width : spec.width;
   spec.height = (height != null) ? height : spec.height;

   if (apply && spec.htmlNode && !spec.minimized && !spec.maximized)
      this.applyPositioning();

   return spec.htmlNode;
}

//-----------------------------------------------------------------------------

XControl.prototype.applyPositioning = function(
   positionSpec
)
{
   positionSpec = (positionSpec == null) ? XControl.getSpecFrom(this.valueOf()) : positionSpec;

   var spec = XControl.getSpecFrom(this.valueOf());

   if (this.configurePositioning)
      this.configurePositioning();

   var nodeXUI = XUI(spec.htmlNode);
   if (positionSpec.top != null || positionSpec.left != null || positionSpec.bottom != null || positionSpec.right != null)
   {
      nodeXUI.setRuntimeStyle("position", "absolute");
      nodeXUI.setRuntimeStyle("left", XUtils.dimText(positionSpec.left));
      nodeXUI.setRuntimeStyle("top", XUtils.dimText(positionSpec.top));
      nodeXUI.setRuntimeStyle("right", XUtils.dimText(positionSpec.right));
      nodeXUI.setRuntimeStyle("bottom", XUtils.dimText(positionSpec.bottom));
   }
   else
      nodeXUI.setRuntimeStyle("position", "static");

   var width = positionSpec.width;
   if (width != null && typeof(width) == "number")
      width = width + spec.shadowSize;
   var height = positionSpec.height;
   if (height != null && typeof(height) == "number")
      height = height + spec.shadowSize;

   if (XApp.isBrowser("MSIE", null, 7.0))
   {
      nodeXUI.setRuntimeExpression("width", null);
      if (width != null && width != "auto")
         nodeXUI.setRuntimeStyle("width", XUtils.dimText(width));
      else if (positionSpec.left != null && positionSpec.left != "auto" && positionSpec.right != null && positionSpec.right != "auto")
      {
         var offsetWidth = this.getAbsoluteLeft() + (positionSpec.right - spec.shadowSize);
         nodeXUI.setRuntimeExpression("width", "document.body.clientWidth - " + (offsetWidth-1));
      }
      nodeXUI.setRuntimeExpression("height", null);
      if (height != null && height != "auto")
         nodeXUI.setRuntimeStyle("height", XUtils.dimText(height));
      else if (positionSpec.top != null && positionSpec.top != "auto" && positionSpec.bottom != null && positionSpec.bottom != "auto")
      {
         var offsetHeight = this.getAbsoluteTop() + (positionSpec.bottom - spec.shadowSize);
         nodeXUI.setRuntimeExpression("height", "document.body.clientHeight - " + (offsetHeight-1));
      }
   }
   else
   {
      nodeXUI.setRuntimeStyle("width", XUtils.dimText(width));
      nodeXUI.setRuntimeStyle("height", XUtils.dimText(height));
   }

   return positionSpec;
}

//-----------------------------------------------------------------------------

XControl.prototype.getAbsoluteTop = function(
   traverseFrames,
   castAs
)
{
   traverseFrames = (traverseFrames == null) ? false : traverseFrames;
   castAs = (castAs == null) ? null : castAs;

   var spec = XControl.getSpecFrom(this.valueOf());

   return XUI.getAbsoluteTop(spec.htmlNode, traverseFrames, castAs);
}

//-----------------------------------------------------------------------------

XControl.prototype.getAbsoluteLeft = function(
   traverseFrames,
   castAs
)
{
   traverseFrames = (traverseFrames == null) ? false : traverseFrames;
   castAs = (castAs == null) ? null : castAs;

   var spec = XControl.getSpecFrom(this.valueOf());

   return XUI.getAbsoluteLeft(spec.htmlNode, traverseFrames, castAs);
}

//-----------------------------------------------------------------------------

XControl.prototype.getWidth = function(
   castAs
)
{
   castAs = (castAs == null) ? null : castAs;

   var spec = XControl.getSpecFrom(this.valueOf());

   return (spec.width) ? spec.width : XUI.getWidth(spec.htmlNode, castAs);
}

//-----------------------------------------------------------------------------

XControl.prototype.getHeight = function(
   castAs
)
{
   castAs = (castAs == null) ? null : castAs;

   var spec = XControl.getSpecFrom(this.valueOf());

   var height = null;
   if (spec.htmlNode)
   {
      height = spec.htmlNode.offsetHeight;
   }

   return (spec.height) ? spec.height : XUI.getHeight(spec.htmlNode, castAs);
}

//-----------------------------------------------------------------------------

XControl.prototype.setEvent = function(
   eventName,
   eventText
)
{
   eventText =( eventText == null) ? null : eventText;

   var spec = XControl.getSpecFrom(this.valueOf());

   if (!eventText)
   {
      spec.events[eventName] = null;
      if (spec.htmlNode)
      {
         spec.htmlNode.removeAttribute(eventName);
      }
   }
   else
   {

      // Note: For eventHandlers, prior to IE8, Internet Explorer returned
      //       a function pointer to an anonymous function that called the
      //       event rather than returning the eventText when querying the
      //       element attribute. This is a workaround.
      eventText = String(eventText).toString();
      if ((/anonymous/).test(eventText))
         eventText = XString(eventText.replace(/\r*\n\r*/g,"").replace(/^.*\{([^\}]*)\}.*$/,"$1")).trim();

      spec.events[eventName] = eventText;
      spec.events.push(eventName);
      if (spec.htmlNode)
      {
         spec.htmlNode.setAttribute(eventName, eventText);
      }
   }

}

//-----------------------------------------------------------------------------

XControl.prototype.getQuirksMode = function(
   castAs
)
{

   var spec = XControl.getSpecFrom(this.valueOf());

   return (castAs == null) ? spec.quirksMode : castAs(spec.quirksMode);
}

//-----------------------------------------------------------------------------

XControl.prototype.setQuirksMode = function(
   quirksMode
)
{
   quirksMode = (quirksMode == null) ? true : quirksMode;

   var spec = XControl.getSpecFrom(this.valueOf());

   spec.quirksMode = quirksMode;

   return spec.quirksMode;
}

//-----------------------------------------------------------------------------

XControl.prototype.focus = function()
{

   var spec = XControl.getSpecFrom(this.valueOf());

   if (spec.htmlNode)
      spec.htmlNode.focus();

}

//-----------------------------------------------------------------------------

XControl.prototype.draw = function(
   context
)
{
   context = (context == null) ? document : context;

   var spec = XControl.getSpecFrom(this.valueOf());

   if (typeof(context) == "string")
   {
      contextNode = $(context);
      if (contextNode)
         contextNode.innerHTML += this.toHTML();
   }
   else if (context.write)
      context.write(this.toHTML());

   spec.htmlNode = $(spec.id);

   if (this.onAfterDraw)
      this.onAfterDraw(this);

   return spec.htmlNode;
}

//-----------------------------------------------------------------------------

XControl.prototype.redraw = function(
   state
)
{
   state = (state == null) ? [] : state;

   var spec = XControl.getSpecFrom(this.valueOf());

   var previousDisplay = XUI(spec.id).getRuntimeStyle("display");

   if (this.toHTML)
      XUI(spec.id).setOuterHTML(this.toHTML(state));

   if (previousDisplay)
      XUI(spec.id).setRuntimeStyle("display", previousDisplay);

   spec.htmlNode = $(spec.id);

   if (this.onAfterRedraw)
      this.onAfterRedraw(this);

   return spec.htmlNode;
}

//=============================================================================

