/**
  *
  *  Copyright 2005 Sabre Airline Solutions
  *
  *  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
  *  file except in compliance with the License. You may obtain a copy of the License at
  *
  *         http://www.apache.org/licenses/LICENSE-2.0
  *
  *  Unless required by applicable law or agreed to in writing, software distributed under the
  *  License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
  *  either express or implied. See the License for the specific language governing permissions
  *  and limitations under the License.
  **/


// This module does NOT depend on prototype.js

/**
 * @namespace Main Rico object
 */
var Rico = {
  Version: '2.1',
  loadRequested: 1,
  loadComplete: 2,
  init : function() {
    try {  // fix IE background image flicker (credit: www.mister-pixel.com)
      document.execCommand("BackgroundImageCache", false, true);
    } catch(err) {}
    this.preloadMsgs='';
    var elements = document.getElementsByTagName('script');
    this.baseHref= location.protocol + "//" + location.host;
    this.loadedFiles={};
    this.windowIsLoaded=false;
    this.onLoadCallbacks=[];
    var filename,ricoFilename;
    for (var i=0; i<elements.length; i++) {
      if (!elements[i].src) continue;
      var src = elements[i].src;
      var slashIdx = src.lastIndexOf('/');
      var path = src.substring(0, slashIdx+1);
      filename = src.substring(slashIdx+1);
      var parmPos  = filename.indexOf('?');
      if (parmPos > 0) filename = filename.substring(0, parmPos);
      this.loadedFiles[filename]=this.loadComplete;
      if (filename == 'rico.js' || filename == 'min.rico.js') {
        ricoFilename=filename;
        var isRailsPath = (path.indexOf("/javascripts") >= 0);
        if (isRailsPath){
          this.jsDir = "/javascripts/";
          this.cssDir = "/stylesheets/";
          this.imgDir = "/images/";
          this.htmDir = "/";
          this.xslDir = "/";
        } else {
          this.jsDir = path;
          this.cssDir = path+'css/';
          this.imgDir = path+'images/';
          this.htmDir = path;
          this.xslDir = path;
        }
      }
    }
    if (!ricoFilename) throw('unable to locate rico.js or min.rico.js script element');
    if (typeof Prototype=='undefined') {
      if (typeof(google)=='object' && google.load)
        google.load('prototype', '1.6');
      else
        this.include('prototype.js');
    }
    if (ricoFilename == 'rico.js') {
      this.include('ricoCommon.js');
      this.languageInclude('en');   // in case a phrase is missing from a translation
    }
    var onloadAction=function() { Rico.windowLoaded(); };
    if (window.addEventListener)
      window.addEventListener('load', onloadAction, false);
    else if (window.attachEvent)
      window.attachEvent('onload', onloadAction);
    this.onLoad(function() { Rico.writeDebugMsg('Pre-load messages:\n'+Rico.preloadMsgs); });
  },

  // Array entries can reference a javascript file or css stylesheet
  // A dependency on another module can be indicated with a plus-sign prefix: '+DependsOnModule'
  moduleDependencies : {
    Accordion  : ['ricoBehaviors.js','ricoEffects.js','ricoComponents.js'],
    Color      : ['ricoStyles.js'],
    Corner     : ['ricoStyles.js'],
    DragAndDrop: ['ricoStyles.js','ricoEffects.js','ricoDragDrop.js'],
    Effect     : ['ricoEffects.js'],
    Calendar   : ['ricoCalendar.js', 'ricoCalendar.css'],
    Tree       : ['ricoTree.js', 'ricoTree.css'],
    ColorPicker: ['ricoColorPicker.js', 'ricoStyles.js', 'ricoColorPicker.css'],
    CustomMenu : ['ricoMenu.js', 'ricoMenu.css'],
    SimpleGrid : ['+Effect', 'ricoGridCommon.js', 'ricoGrid.css', 'ricoSimpleGrid.js'],
    LiveGridBasic : ['ricoGridCommon.js', 'ricoGrid.css', 'ricoBehaviors.js', 'ricoLiveGrid.js'],
    LiveGrid      : ['+Effect', '+LiveGridBasic', 'ricoLiveGridControls.js'],
    LiveGridMenu  : ['+CustomMenu', 'ricoLiveGridMenu.js'],
    LiveGridAjax  : ['+LiveGrid', 'ricoLiveGridAjax.js'],
    LiveGridJSON  : ['+LiveGridAjax', 'ricoLiveGridJSON.js'],
    LiveGridForms : ['+LiveGridAjax', '+LiveGridMenu', '+Accordion', '+Corner', 'ricoLiveGridForms.js', 'ricoLiveGridForms.css'],
    SpreadSheet   : ['+SimpleGrid', 'ricoSheet.js', 'ricoSheet.css']
  },
  
  languages : {
    de: "translations/ricoLocale_de.js",
    en: "translations/ricoLocale_en.js",
    es: "translations/ricoLocale_es.js",
    fr: "translations/ricoLocale_fr.js",
    it: "translations/ricoLocale_it.js",
    ja: "translations/ricoLocale_ja.js",
    ko: "translations/ricoLocale_ko.js",
    pt: "translations/ricoLocale_pt.js",
    zh: "translations/ricoLocale_zh.js"
  },
  
  languageInclude : function(lang2) {
    var filename=this.languages[lang2];
    if (filename) this.include(filename);
    return !!filename;
  },
  
  acceptLanguage : function(acceptLang) {
    var arLang=acceptLang.toLowerCase().split(',');
    for (var i=0; i<arLang.length; i++) {
      var lang2=arLang[i].match(/\w\w/);
      if (!lang2) continue;
      if (this.languageInclude(lang2)) return true;
    }
    return false;
  },

  // Expects one or more module or file names
  loadModule : function() {
    for (var a=0, length=arguments.length; a<length; a++) {
      var name=arguments[a];
      var dep=this.moduleDependencies[name];
      if (dep) {
        for (var i=0; i<dep.length; i++) {
          if (dep[i].substring(0,1)=='+') {
            this.loadModule(dep[i].slice(1));
          } else {
            this.include(dep[i]);
          }
        }
      } else {
        this.include(name);
      }
    }
  },

  include : function(filename) {
    if (this.loadedFiles[filename]) return;
    this.addPreloadMsg('include: '+filename);
    var ext = filename.substr(filename.lastIndexOf('.')+1);
    switch (ext.toLowerCase()) {
      case 'js':
        this.loadedFiles[filename]=filename.substring(0,4)=='rico' ? this.loadRequested : this.loadComplete;
        document.write("<script type='text/javascript' src='"+this.jsDir+filename+"'><\/script>");
        return;
      case 'css':
        var el = document.createElement('link');
        el.type = 'text/css';
        el.rel = 'stylesheet';
        el.href = this.cssDir+filename;
        this.loadedFiles[filename]=this.loadComplete;
        document.getElementsByTagName('head')[0].appendChild(el);
        return;
    }
  },

  // called after a script file has finished loading
  includeLoaded: function(filename) {
    this.loadedFiles[filename]=this.loadComplete;
    this.checkIfComplete();
  },

  // called by the document onload event
  windowLoaded: function() {
    this.windowIsLoaded=true;
    this.checkIfComplete();
  },

  checkIfComplete: function() {
    var waitingFor=this.windowIsLoaded ? '' : 'window';
    for(var filename in  this.loadedFiles) {
      if (this.loadedFiles[filename]==this.loadRequested)
        waitingFor+=' '+filename;
    }
    //window.status='waitingFor: '+waitingFor;
    this.addPreloadMsg('waitingFor: '+waitingFor);
    if (waitingFor.length==0) {
      this.addPreloadMsg('Processing callbacks');
      while (this.onLoadCallbacks.length > 0) {
        var callback=this.onLoadCallbacks.shift();
        if (callback) callback();
      }
    }
  },

  onLoad: function(callback,frontOfQ) {
    if (frontOfQ)
      this.onLoadCallbacks.unshift(callback);
    else
      this.onLoadCallbacks.push(callback);
    this.checkIfComplete();
  },

  isKonqueror : navigator.userAgent.toLowerCase().indexOf("konqueror") >= 0,

  // logging funtions

  startTime : new Date(),

  timeStamp: function() {
    var stamp = new Date();
    return (stamp.getTime()-this.startTime.getTime())+": ";
  },

  setDebugArea: function(id, forceit) {
    if (!this.debugArea || forceit) {
      var newarea=document.getElementById(id);
      if (!newarea) return;
      this.debugArea=newarea;
      newarea.value='';
    }
  },

  addPreloadMsg: function(msg) {
    this.preloadMsgs+=Rico.timeStamp()+msg+"\n";
  },

  writeDebugMsg: function(msg, resetFlag) {
    if (this.debugArea) {
      if (resetFlag) this.debugArea.value='';
      this.debugArea.value+=this.timeStamp()+msg+"\n";
    } else if (window.console) {
      if (window.console.firebug)
        window.console.log(this.timeStamp(),msg);
      else
        window.console.log(this.timeStamp()+msg);
    } else if (window.opera) {
      window.opera.postError(this.timeStamp()+msg);
    }
  }

}

Rico.init();

// ricoStyles.js


Rico.Color = Class.create(
/** @lends Rico.Color# */
{
/**
 * @class Methods to manipulate color values.
 * @constructs
 * @param red integer (0-255)
 * @param green integer (0-255)
 * @param blue integer (0-255)
 */
   initialize: function(red, green, blue) {
      this.rgb = { r: red, g : green, b : blue };
   },

   setRed: function(r) {
      this.rgb.r = r;
   },

   setGreen: function(g) {
      this.rgb.g = g;
   },

   setBlue: function(b) {
      this.rgb.b = b;
   },

   setHue: function(h) {

      // get an HSB model, and set the new hue...
      var hsb = this.asHSB();
      hsb.h = h;

      // convert back to RGB...
      this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
   },

   setSaturation: function(s) {
      // get an HSB model, and set the new hue...
      var hsb = this.asHSB();
      hsb.s = s;

      // convert back to RGB and set values...
      this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
   },

   setBrightness: function(b) {
      // get an HSB model, and set the new hue...
      var hsb = this.asHSB();
      hsb.b = b;

      // convert back to RGB and set values...
      this.rgb = Rico.Color.HSBtoRGB( hsb.h, hsb.s, hsb.b );
   },

   darken: function(percent) {
      var hsb  = this.asHSB();
      this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.max(hsb.b - percent,0));
   },

   brighten: function(percent) {
      var hsb  = this.asHSB();
      this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.min(hsb.b + percent,1));
   },

   blend: function(other) {
      this.rgb.r = Math.floor((this.rgb.r + other.rgb.r)/2);
      this.rgb.g = Math.floor((this.rgb.g + other.rgb.g)/2);
      this.rgb.b = Math.floor((this.rgb.b + other.rgb.b)/2);
   },

   isBright: function() {
      var hsb = this.asHSB();
      return this.asHSB().b > 0.5;
   },

   isDark: function() {
      return ! this.isBright();
   },

   asRGB: function() {
      return "rgb(" + this.rgb.r + "," + this.rgb.g + "," + this.rgb.b + ")";
   },

   asHex: function() {
      return "#" + this.rgb.r.toColorPart() + this.rgb.g.toColorPart() + this.rgb.b.toColorPart();
   },

   asHSB: function() {
      return Rico.Color.RGBtoHSB(this.rgb.r, this.rgb.g, this.rgb.b);
   },

   toString: function() {
      return this.asHex();
   }

});

/**
 * Factory method for creating a color from an RGB string
 * @param hexCode a 3 or 6 digit hex string, optionally preceded by a # symbol
 * @returns a Rico.Color object
 */
Rico.Color.createFromHex = function(hexCode) {
  if(hexCode.length==4) {
    var shortHexCode = hexCode;
    hexCode = '#';
    for(var i=1;i<4;i++)
      hexCode += (shortHexCode.charAt(i) + shortHexCode.charAt(i));
  }
  if ( hexCode.indexOf('#') == 0 )
    hexCode = hexCode.substring(1);
  if (!hexCode.match(/^[0-9A-Fa-f]{6}$/)) return null;
  var red   = hexCode.substring(0,2);
  var green = hexCode.substring(2,4);
  var blue  = hexCode.substring(4,6);
  return new Rico.Color( parseInt(red,16), parseInt(green,16), parseInt(blue,16) );
};

/**
 * Retrieves the background color of an HTML element
 * @param elem the DOM element whose background color should be retreived
 * @returns a Rico.Color object
 */
Rico.Color.createColorFromBackground = function(elem) {

   if (!elem.style) return new Rico.Color(255,255,255);
   var actualColor = Element.getStyle(elem, "background-color");

   // if color is tranparent, check parent
   // Safari returns "rgba(0, 0, 0, 0)", which means transparent
   if ( actualColor.match(/^(transparent|rgba\(0,\s*0,\s*0,\s*0\))$/i) && elem.parentNode )
      return Rico.Color.createColorFromBackground(elem.parentNode);

   if (actualColor == null) return new Rico.Color(255,255,255);

   if ( actualColor.indexOf("rgb(") == 0 ) {
      var colors = actualColor.substring(4, actualColor.length - 1 );
      var colorArray = colors.split(",");
      return new Rico.Color( parseInt( colorArray[0],10 ),
                             parseInt( colorArray[1],10 ),
                             parseInt( colorArray[2],10 )  );

   }
   else if ( actualColor.indexOf("#") == 0 ) {
      return Rico.Color.createFromHex(actualColor);
   }
   else
      return new Rico.Color(255,255,255);
};

/**
 * Converts hue/saturation/brightness to RGB
 * @returns a 3-element object: r=red, g=green, b=blue.
 */
Rico.Color.HSBtoRGB = function(hue, saturation, brightness) {

  var red   = 0;
	var green = 0;
	var blue  = 0;

  if (saturation == 0) {
     red = parseInt(brightness * 255.0 + 0.5,10);
	   green = red;
	   blue = red;
	}
	else {
      var h = (hue - Math.floor(hue)) * 6.0;
      var f = h - Math.floor(h);
      var p = brightness * (1.0 - saturation);
      var q = brightness * (1.0 - saturation * f);
      var t = brightness * (1.0 - (saturation * (1.0 - f)));

      switch (parseInt(h,10)) {
         case 0:
            red   = (brightness * 255.0 + 0.5);
            green = (t * 255.0 + 0.5);
            blue  = (p * 255.0 + 0.5);
            break;
         case 1:
            red   = (q * 255.0 + 0.5);
            green = (brightness * 255.0 + 0.5);
            blue  = (p * 255.0 + 0.5);
            break;
         case 2:
            red   = (p * 255.0 + 0.5);
            green = (brightness * 255.0 + 0.5);
            blue  = (t * 255.0 + 0.5);
            break;
         case 3:
            red   = (p * 255.0 + 0.5);
            green = (q * 255.0 + 0.5);
            blue  = (brightness * 255.0 + 0.5);
            break;
         case 4:
            red   = (t * 255.0 + 0.5);
            green = (p * 255.0 + 0.5);
            blue  = (brightness * 255.0 + 0.5);
            break;
          case 5:
            red   = (brightness * 255.0 + 0.5);
            green = (p * 255.0 + 0.5);
            blue  = (q * 255.0 + 0.5);
            break;
	    }
	}

   return { r : parseInt(red,10), g : parseInt(green,10) , b : parseInt(blue,10) };
};

/**
 * Converts RGB value to hue/saturation/brightness
 * @param r integer (0-255)
 * @param g integer (0-255)
 * @param b integer (0-255)
 * @returns a 3-element object: h=hue, s=saturation, b=brightness.
 * (unlike some HSB documentation which states hue should be a value 0-360, this routine returns hue values from 0 to 1.0)
 */
Rico.Color.RGBtoHSB = function(r, g, b) {

   var hue;
   var saturation;
   var brightness;

   var cmax = (r > g) ? r : g;
   if (b > cmax)
      cmax = b;

   var cmin = (r < g) ? r : g;
   if (b < cmin)
      cmin = b;

   brightness = cmax / 255.0;
   if (cmax != 0)
      saturation = (cmax - cmin)/cmax;
   else
      saturation = 0;

   if (saturation == 0)
      hue = 0;
   else {
      var redc   = (cmax - r)/(cmax - cmin);
    	var greenc = (cmax - g)/(cmax - cmin);
    	var bluec  = (cmax - b)/(cmax - cmin);

    	if (r == cmax)
    	   hue = bluec - greenc;
    	else if (g == cmax)
    	   hue = 2.0 + redc - bluec;
      else
    	   hue = 4.0 + greenc - redc;

    	hue = hue / 6.0;
    	if (hue < 0)
    	   hue = hue + 1.0;
   }

   return { h : hue, s : saturation, b : brightness };
};

/**
 * Creates a vertical gradient inside an element
 * @param e element where gradient will be created
 * @param startColor starting color, either a Rico.Color object or 6-character RGB string
 * @param endColor ending color, either a Rico.Color object or 6-character RGB string
 */
Rico.Color.createGradientV = function(e,startColor,endColor) {
  var c1=typeof(startColor)=='string' ? Rico.Color.createFromHex(startColor) : startColor;
  var c2=typeof(endColor)=='string' ? Rico.Color.createFromHex(endColor) : endColor;
  if (Prototype.Browser.IE) {
    e.style.filter = "progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr=\"" + c1.asHex() + "\",EndColorStr=\"" + c2.asHex() + "\")";
  } else {
    var colorArray = Rico.Color.createColorPath(c1,c2,Math.min(e.offsetHeight,50));
    var remh=e.offsetHeight,l=colorArray.length;
    var div=Rico.Color.createGradientContainer();
    var tmpDOM = document.createDocumentFragment();
    for(var g,h,p=0;p<colorArray.length;p++) {
      h = Math.round(remh/l) || 1;
      g = document.createElement("div");
      g.setAttribute("style","height:" + h + "px;width:100%;background-color:" + colorArray[p].asRGB() + ";");
      tmpDOM.appendChild(g);
      l--;
      remh-=h;
    }
    div.appendChild(tmpDOM);
    e.appendChild(div);
    tmpDOM = null;
  }
};

/**
 * Creates a horizontal gradient inside an element
 * @param e element where gradient will be created
 * @param startColor starting color, either a Rico.Color object or 6-character RGB string
 * @param endColor ending color, either a Rico.Color object or 6-character RGB string
 */
Rico.Color.createGradientH = function(e,startColor,endColor) {
  var c1=typeof(startColor)=='string' ? Rico.Color.createFromHex(startColor) : startColor;
  var c2=typeof(endColor)=='string' ? Rico.Color.createFromHex(endColor) : endColor;
  if (Prototype.Browser.IE) {
    e.style.filter = "progid:DXImageTransform.Microsoft.Gradient(GradientType=1,StartColorStr=\"" + c1.asHex() + "\",EndColorStr=\"" + c2.asHex() + "\")";
  } else {
    var colorArray = Rico.Color.createColorPath(c1,c2,Math.min(e.offsetWidth,50));
    var x=0,remw=e.offsetWidth,l=colorArray.length;
    var div=Rico.Color.createGradientContainer();
    var tmpDOM = document.createDocumentFragment();
    for(var p=0;p<colorArray.length;p++) {
      var w=Math.round(remw/l) || 1;
      var g = document.createElement("div");
      g.setAttribute("style","position:absolute;top:0px;left:" + x + "px;height:100%;width:" + w + "px;background-color:" + colorArray[p].asRGB() + ";");
      tmpDOM.appendChild(g);
      x+=w;
      l--;
      remw-=w;
    }
    div.appendChild(tmpDOM);
    e.appendChild(div);
    tmpDOM = null;
  }
};

/** creates containing element for gradient methods */
Rico.Color.createGradientContainer = function() {
  var div=document.createElement('div');
  div.style.height='100%';
  div.style.width='100%';
  div.style.position='absolute';
  div.style.top='0px';
  div.style.left='0px';
  div.style.zIndex=-1;
  return div;
};

/** calculates intermediate color values for gradient methods */
Rico.Color.createColorPath = function(color1,color2,slices) {
  var colorPath = [];
  var colorPercent = 1.0;
  var delta=1.0/slices;
  do {
    colorPath[colorPath.length]=Rico.Color.setColorHue(color1,colorPercent,color2);
    colorPercent-=delta;
  } while(colorPercent>0);
  return colorPath;
};

Rico.Color.setColorHue = function(originColor,opacityPercent,maskRGB) {
  return new Rico.Color(
    Math.round(originColor.rgb.r*opacityPercent + maskRGB.rgb.r*(1.0-opacityPercent)),
    Math.round(originColor.rgb.g*opacityPercent + maskRGB.rgb.g*(1.0-opacityPercent)),
    Math.round(originColor.rgb.b*opacityPercent + maskRGB.rgb.b*(1.0-opacityPercent))
  );
};


/**
 * @namespace
 */
Rico.Corner = {

   round: function(e, options) {
      e = $(e);
      
      // Evan Quirk
      // Fix to match Old Rico Automatic Padding
      Element.setStyle(e, {'paddingBottom':'5px'});
      
      this._setOptions(options);
      var color = this.options.color == "fromElement" ? this._background(e) : this.options.color;
      var bgColor = this.options.bgColor == "fromParent" ? this._background(e.parentNode) : this.options.bgColor;
      if (Prototype.Browser.Gecko && this.options.useMoz && !this.options.border && Element.getStyle(e,'background-image')=='none')
        this._roundCornersGecko(e, color);
      else if (typeof(Element.getStyle(e,'-webkit-border-radius'))=='string' && !this.options.border)
        this._roundCornersWebKit(e, color);
      else
        this._roundCornersImpl(e, color, bgColor);
   },

   _roundCornersImpl: function(e, color, bgColor) {
      this.options.numSlices = this.options.compact ? 2 : 4;
      this.borderColor = this._borderColor(color,bgColor);
      if(this.options.border)
         this._renderBorder(e,bgColor);
      if(this._isTopRounded())
         this._roundTopCorners(e,color,bgColor);
      if(this._isBottomRounded())
         this._roundBottomCorners(e,color,bgColor);
   },

   _roundCornersGecko: function(e, color) {
      var radius=this.options.compact ? '4px' : '8px';
      if (this._hasString(this.options.corners, "all"))
        Element.setStyle(e, {MozBorderRadius:radius}, true);
      else {
        if (this._hasString(this.options.corners, "top", "tl")) Element.setStyle(e, {MozBorderRadiusTopleft:radius}, true);
        if (this._hasString(this.options.corners, "top", "tr")) Element.setStyle(e, {MozBorderRadiusTopright:radius}, true);
        if (this._hasString(this.options.corners, "bottom", "bl")) Element.setStyle(e, {MozBorderRadiusBottomleft:radius}, true);
        if (this._hasString(this.options.corners, "bottom", "br")) Element.setStyle(e, {MozBorderRadiusBottomright:radius}, true);
      }
   },

   _roundCornersWebKit: function(e, color) {
      var radius=this.options.compact ? '4px' : '8px';
      if (this._hasString(this.options.corners, "all"))
        Element.setStyle(e, {WebkitBorderRadius:radius}, true);
      else {
        if (this._hasString(this.options.corners, "top", "tl")) Element.setStyle(e, {WebkitBorderTopLeftRadius:radius}, true);
        if (this._hasString(this.options.corners, "top", "tr")) Element.setStyle(e, {WebkitBorderTopRightRadius:radius}, true);
        if (this._hasString(this.options.corners, "bottom", "bl")) Element.setStyle(e, {WebkitBorderBottomLeftRadius:radius}, true);
        if (this._hasString(this.options.corners, "bottom", "br")) Element.setStyle(e, {WebkitBorderBottomRightRadius:radius}, true);
      }
   },

   _renderBorder: function(el,bgColor) {
      var wrapper=RicoUtil.wrapChildren(el);
      var borderValue = "1px solid " + this._borderColor(bgColor);
      Element.setStyle(wrapper,{
        borderLeft: borderValue,
        borderRight: borderValue,
        marginTop: '0px',
        marginBottom: '0px',
        padding: '1px',  // prevents margin collapse
        height: '100%'
      });
   },

   _roundTopCorners: function(el, color, bgColor) {
      var corner = this._createCorner(bgColor);
      for(var i=0 ; i < this.options.numSlices ; i++ )
         corner.appendChild(this._createCornerSlice(color,bgColor,i,"top"));
      el.style.paddingTop = '0px';
      el.insertBefore(corner,el.firstChild);
   },

   _roundBottomCorners: function(el, color, bgColor) {
      var corner = this._createCorner(bgColor);
      for(var i=(this.options.numSlices-1) ; i >= 0 ; i-- )
         corner.appendChild(this._createCornerSlice(color,bgColor,i,"bottom"));
      el.style.paddingBottom = 0;
      el.appendChild(corner);
   },

   _createCorner: function(bgColor) {
      var corner = document.createElement("div");
      corner.style.backgroundColor = (this._isTransparent() ? "transparent" : bgColor);
      return corner;
   },

   _createCornerSlice: function(color,bgColor, n, position) {
      var slice = document.createElement("span");

      var inStyle = slice.style;
      inStyle.backgroundColor = color;
      inStyle.display  = "block";
      inStyle.height   = "1px";
      inStyle.overflow = "hidden";
      inStyle.fontSize = "1px";

      if ( this.options.border && n == 0 ) {
         inStyle.borderTopStyle    = "solid";
         inStyle.borderTopWidth    = "1px";
         inStyle.borderLeftWidth   = "0px";
         inStyle.borderRightWidth  = "0px";
         inStyle.borderBottomWidth = "0px";
         inStyle.height            = "0px"; // assumes css compliant box model
         inStyle.borderColor       = this.borderColor;
      }
      else if(this.borderColor) {
         inStyle.borderColor = this.borderColor;
         inStyle.borderStyle = "solid";
         inStyle.borderWidth = "0px 1px";
      }

      if ( !this.options.compact && (n == (this.options.numSlices-1)) )
         inStyle.height = "2px";

      this._setMargin(slice, n, position);
      this._setBorder(slice, n, position);
      return slice;
   },

   _setOptions: function(options) {
      this.options = {
         corners : "all",
         color   : "fromElement",
         bgColor : "fromParent",
         blend   : true,
         border  : false,
         compact : false,
         useMoz  : true  // use native Gecko corners
      };
      Object.extend(this.options, options || {});
      if (this._isTransparent()) this.options.blend = false;
   },

   _whichSideTop: function() {
      if ( this._hasString(this.options.corners, "all", "top") )
         return "";

      if ( this.options.corners.indexOf("tl") >= 0 && this.options.corners.indexOf("tr") >= 0 )
         return "";

      if (this.options.corners.indexOf("tl") >= 0)
         return "left";
      else if (this.options.corners.indexOf("tr") >= 0)
          return "right";
      return "";
   },

   _whichSideBottom: function() {
      if ( this._hasString(this.options.corners, "all", "bottom") )
         return "";

      if ( this.options.corners.indexOf("bl")>=0 && this.options.corners.indexOf("br")>=0 )
         return "";

      if(this.options.corners.indexOf("bl") >=0)
         return "left";
      else if(this.options.corners.indexOf("br")>=0)
         return "right";
      return "";
   },

   _borderColor : function(color,bgColor) {
      if (color == "transparent") return bgColor;
      if (this.options.border) return this.options.border;
      if (!this.options.blend) return '';
      var cc1 = Rico.Color.createFromHex(bgColor);
      var cc2 = Rico.Color.createFromHex(color);
      if (cc1==null || cc2==null) {
         this.options.blend=false;
         return '';
      }
      cc1.blend(cc2);
      return cc1;
   },


   _setMargin: function(el, n, corners) {
      var marginSize = this._marginSize(n);
      var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom();

      if ( whichSide == "left" ) {
         el.style.marginLeft = marginSize + "px"; el.style.marginRight = "0px";
      }
      else if ( whichSide == "right" ) {
         el.style.marginRight = marginSize + "px"; el.style.marginLeft  = "0px";
      }
      else {
         el.style.marginLeft = marginSize + "px"; el.style.marginRight = marginSize + "px";
      }
   },

   _setBorder: function(el,n,corners) {
      var borderSize = this._borderSize(n);
      var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom();
      if ( whichSide == "left" ) {
         el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = "0px";
      }
      else if ( whichSide == "right" ) {
         el.style.borderRightWidth = borderSize + "px"; el.style.borderLeftWidth  = "0px";
      }
      else {
         el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = borderSize + "px";
      }
      if (this.options.border) {
        el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = borderSize + "px";
      }
   },

   _marginSize: function(n) {
      if ( this._isTransparent() )
         return 0;

      var marginSizes          = [ 5, 3, 2, 1 ];
      var blendedMarginSizes   = [ 3, 2, 1, 0 ];
      var compactMarginSizes   = [ 2, 1 ];
      var smBlendedMarginSizes = [ 1, 0 ];

      if ( this.options.compact && this.options.blend )
         return smBlendedMarginSizes[n];
      else if ( this.options.compact )
         return compactMarginSizes[n];
      else if ( this.options.blend )
         return blendedMarginSizes[n];
      else
         return marginSizes[n];
   },

   _borderSize: function(n) {
      var transparentBorderSizes = [ 5, 3, 2, 1 ];
      var blendedBorderSizes     = [ 2, 1, 1, 1 ];
      var compactBorderSizes     = [ 1, 0 ];
      var actualBorderSizes      = [ 0, 2, 0, 0 ];

      if ( this.options.compact && (this.options.blend || this._isTransparent()) )
         return 1;
      else if ( this.options.compact )
         return compactBorderSizes[n];
      else if ( this.options.blend )
         return blendedBorderSizes[n];
      else if ( this.options.border )
         return actualBorderSizes[n];
      else if ( this._isTransparent() )
         return transparentBorderSizes[n];
      return 0;
   },

   _background: function(elem) {
     try {
       var actualColor = Element.getStyle(elem, "background-color");

       // if color is tranparent, check parent
       // Safari returns "rgba(0, 0, 0, 0)", which means transparent
       if ( actualColor.match(/^(transparent|rgba\(0,\s*0,\s*0,\s*0\))$/i) && elem.parentNode )
          return this._background(elem.parentNode);

       return actualColor == null ? "#ffffff" : actualColor;
     } catch(err) {
       return "#ffffff";
     }
   },

   _hasString: function(str) {
     for(var i=1 ; i<arguments.length ; i++) {
       if (str.indexOf(arguments[i]) >= 0) return true;
     }
     return false;
   },

   _isTransparent: function() { return this.options.color == "transparent"; },
   _isTopRounded: function() { return this._hasString(this.options.corners, "all", "top", "tl", "tr"); },
   _isBottomRounded: function() { return this._hasString(this.options.corners, "all", "bottom", "bl", "br"); },
   _hasSingleTextChild: function(el) { return el.childNodes.length == 1 && el.childNodes[0].nodeType == 3; }
};

Rico.includeLoaded('ricoStyles.js');

