// Gaia Ajax Copyright (C) 2008 - 2009 Gaiaware AS. details at http://gaiaware.net/

/* 
 * Gaia Ajax - Ajax Control Library for ASP.NET
 * Copyright (C) 2008 - 2009 Gaiaware AS
 * All rights reserved.
 * This program is distributed under either GPL version 3 
 * as published by the Free Software Foundation or the
 * Gaia Commercial License version 1 as published by
 * Gaiaware AS
 * read the details at http://gaiaware.net
 */

/* ---------------------------------------------------------------------------
   Common class for all WebControls, basically wraps the WebControl class
   --------------------------------------------------------------------------- */

// Creating our class
Gaia.WebControl = Class.create(Gaia.Control, {

  // This one should have been "overriden" in extended classes and that method should call "initializeWebControl" instead!
  initialize: function(){
    throw "You must override the initialize function in your derived class";
  },


  // "Constructor" for object
  initializeWebControl: function(element, options){
    this.initializeControl(element, options);
  },


  // Wraps the "AccessKey" property...
  // Note only works on IE...
  // TODO: Check up how to get to work on FF and Opera etc (if possible)
  setAccessKey: function(value){
    this.element.accessKey = value;
    if (!value) this.element.removeAttribute('accessKey');
    return this;
  },
  
  setAttribute: function(name, value){
    this.element.setAttribute(name, value);
    return this;
  },
  
  removeAttribute: function(name) {
    this.element.removeAttribute(name);
    return this;
  },

  // Wrapper for the "Style" property
  setStyle: function(styles){
    var styleFormatted = '';
    for( var idx in styles ) {
      var value = styles[idx];
      if (value)
        styleFormatted += idx + ':' + value + ';';
      else {
        var styleName = idx.camelize();
        this.element.style[styleName] = '';
        if (!Prototype.Browser.IE)
          delete this.element.style[styleName];
      }
    }
    if (styleFormatted)
        Element.setStyle(this.element, styleFormatted);
    return this;
  },

  // Returns a color, expects to get a string containing either 8 characters (hex number) or 6 characters
  // If it is given 8 characters it assumes the last two digits is the alpha channel. If it only recieves
  // 6 digits it returns an alpha value of 1.0.
  _parseARGB: function(value){
    if( value.length == 6 )
      return {color: '#'+value, alpha: 1.0};
    else {
      // Asserting alpha channel...
      // TODO: Check up if this logic is right...??
      // It looks as though it expects to get the color in RRGGBBAA formatting...?
      // I would expect the alpha to be the FIRST part (AA------) and not (------AA)...??
      return {color: '#'+value.substring(0,6), alpha: (parseInt(value.substring(7), 10)/255)};
    }
  },


  // Sets background color of widget
  setBackColor: function(value){
    var clr = this._parseARGB(value);
    this.setStyle({'background-color': clr.color});
    this.element.setOpacity(clr.alpha);
    return this;
  },


  // Sets border color of widget
  setBorderColor: function(value){
    this.setStyle({'border-color': this._parseARGB(value).color});
    return this;
  },


  // Sets the style of the border  ('Dottet', 'Ridged' or so on)
  setBorderStyle: function(value){
    this.setStyle({'border-style': value});
    return this;
  },


  // Sets the width of the border
  setBorderWidth: function(value){
    this.setStyle({'border-width': value});
    return this;
  },


  // Sets the CSS class, note it REMOVES ALL other css classes
  setCssClass: function(value){
    this.element.className = value;
    return this;
  },


  // Enables or disables the element (true/false)
  setEnabled: function(value){
    value ? Form.Element.enable(this.element.id) : Form.Element.disable(this.element.id);
    
    if (value && this.element.hasAttribute("disabled"))
        this.element.removeAttribute("disabled");
    
    return this;
  },


  // Sets the font of the element to either bold(true) or normal(false)
  setFontBold: function(value){
    this.setStyle({'font-weight': (value?'bold':'normal')});
    return this;
  },


  // Sets the font of the element to either italic(true) or normal(false)
  setFontItalic: function(value){
    this.setStyle({'font-style': (value?'italic':'normal')});
    return this;
  },


  // Sets the font family names to use for the element
  setFontNames: function(value){
    this.setStyle({'font-family': value});
    return this;
  },


  // Sets the font of the element to either overline style(true) or normal(false)
  setFontOverline: function(value){
    this.setStyle({'text-decoration': (value?'overline':'')});
    return this;
  },


  // Sets the font size of the element
  setFontSize: function(value){
    this.setStyle({'font-size': value});
    return this;
  },


  // Sets the font of the element to either strikeout(true) or normal(false)
  setFontStrikeout: function(value){
    this.setStyle({'text-decoration': (value?'line-through':'')});
    return this;
  },


  // Sets the font of the element to either underline(true) or normal(false)
  setFontUnderline: function(value){
    this.setStyle({'text-decoration': (value?'underline':'')});
    return this;
  },


  // Sets foreground (font) color, can take named color, color hexa value (6 or 3 digits) or 8 diget alpha and color value
  // Format is #AARRGGBB (AA=alpha, RR=red, GG=green, BB=blue)
  setForeColor: function(value){
    this.setStyle({color: this._parseARGB(value).color});
    return this;
  },


  // Sets the height of the element
  setHeight: function(value){
    this.setStyle({height: value});
    return this;
  },


  // Sets the tooltip of the element (title element)
  setToolTip: function(value){
    this.element.title = value;
    return this;
  },
  
  // Sets the tabindex of the element
  setTabIndex: function(value){
    this.element.tabIndex = value;
    return this;
  },

  // Sets the width of the element
  setWidth: function(value){
    this.setStyle({width: value});
    return this;
  },
  
  initializeDefaultValidation: function() {
    this.options = Object.extend({validate: 1, validationGroup: ''}, this.options);
  },
  
  setValidation: function(value) {
    this.options.validate = value;
    return this;
  },
  
  setValidationGroup: function(value) {
    this.options.validationGroup = value;
    return this;
  },
  
  bringToFront: function() {
    Gaia.WebControl.bringElementToFront(this.element);
  }
});


Gaia.WebControl.bringElementToFront = function(element) {

  // find parent stacking context
  var stackingContext = element.parentNode;

  while (stackingContext && stackingContext !== document.body && 
        !Gaia.WebControl.isStackingContext(stackingContext)) {
    stackingContext = stackingContext.parentNode;
  }

  // find topmost element in the stacking context
  var topMostIndex = 0;
  var nodes = $(stackingContext).childElements().without(element);
  
  while (nodes.length > 0) {
    var node = nodes.pop();

    // check if node creates new stacking context
    if (Gaia.WebControl.isStackingContext(node))
        topMostIndex = Math.max(topMostIndex, parseInt(Element.getStyle(node, 'zIndex'),  10) || 0);
    else
        nodes = nodes.concat(node.childElements());
  }

  // bring element to front in its stacking context
  var current = parseInt(Element.getStyle(element, 'zIndex'),  10);
  var suggested = topMostIndex + 1;
  if (isNaN(current) || (suggested > current))
    element.style.zIndex = suggested;

  // move its stacking context to front
  if (stackingContext !== document.body)
    Gaia.WebControl.bringElementToFront(stackingContext);
};

Gaia.WebControl.isStackingContext = function(element) {
    var zIndex   = parseInt(Element.getStyle(element, 'zIndex'),  10);
    var position = Element.getStyle(element, 'position');

    // check if it creates stacking context
    // 1. element should be positioned
    // 2. should have z-index other then 'auto'
    // 3. in case of Gecko/WebKit opacity also defines new stacking context
    return (position && position != 'static' && 
           !isNaN(zIndex) && (!Prototype.Browser.IE || zIndex !== 0)) ||
           ((Prototype.Browser.Gecko || Prototype.Browser.Safari) &&  
            element.getStyle('opacity') != 1.0);
};

Gaia_WebControl_browserFinishedLoading = true;
