////////////////////////////
// INCLUDES:
// ricoAjax.js
// ricoCommon.js
// ricoEffects.js
// ricoBehaviors.js
// ricoDragDrop.js
// ricoComponents.js
// demosPage.js
////////////////////////////
////////////////////////////////////////////////////
// start ricoAjax.js

//-------------------- ricoAjaxEngine.js
Rico.AjaxEngine = Class.create();

Rico.AjaxEngine.prototype = {

   initialize: function() {
      this.ajaxElements = new Array();
      this.ajaxObjects  = new Array();
      this.requestURLS  = new Array();
      this.options = {};
   },

   registerAjaxElement: function( anId, anElement ) {
      if ( !anElement )
         anElement = $(anId);
      this.ajaxElements[anId] = anElement;
   },

   registerAjaxObject: function( anId, anObject ) {
      this.ajaxObjects[anId] = anObject;
   },

   registerRequest: function (requestLogicalName, requestURL) {
      this.requestURLS[requestLogicalName] = requestURL;
   },

   sendRequest: function(requestName, options) {
      // Allow for backwards Compatibility
      if ( arguments.length >= 2 )
       if (typeof arguments[1] == 'string')
         options = {parameters: this._createQueryString(arguments, 1)};
      this.sendRequestWithData(requestName, null, options);
   },

   sendRequestWithData: function(requestName, xmlDocument, options) {
      var requestURL = this.requestURLS[requestName];
      if ( requestURL == null )
         return;

      // Allow for backwards Compatibility
      if ( arguments.length >= 3 )
        if (typeof arguments[2] == 'string')
          options.parameters = this._createQueryString(arguments, 2);

      new Ajax.Request(requestURL, this._requestOptions(options,xmlDocument));
   },

   sendRequestAndUpdate: function(requestName,container,options) {
      // Allow for backwards Compatibility
      if ( arguments.length >= 3 )
        if (typeof arguments[2] == 'string')
          options.parameters = this._createQueryString(arguments, 2);

      this.sendRequestWithDataAndUpdate(requestName, null, container, options);
   },

   sendRequestWithDataAndUpdate: function(requestName,xmlDocument,container,options) {
      var requestURL = this.requestURLS[requestName];
      if ( requestURL == null )
         return;

      // Allow for backwards Compatibility
      if ( arguments.length >= 4 )
        if (typeof arguments[3] == 'string')
          options.parameters = this._createQueryString(arguments, 3);

      var updaterOptions = this._requestOptions(options,xmlDocument);

      new Ajax.Updater(container, requestURL, updaterOptions);
   },

   // Private -- not part of intended engine API --------------------------------------------------------------------

   _requestOptions: function(options,xmlDoc) {
      var requestHeaders = ['X-Rico-Version', Rico.Version ];
      var sendMethod = 'post';
      if ( xmlDoc == null )
        if (Rico.prototypeVersion < 1.4)
        requestHeaders.push( 'Content-type', 'text/xml' );
      else
          sendMethod = 'get';
      (!options) ? options = {} : '';

      if (!options._RicoOptionsProcessed){
      // Check and keep any user onComplete functions
        if (options.onComplete)
             options.onRicoComplete = options.onComplete;
        // Fix onComplete
        if (options.overrideOnComplete)
          options.onComplete = options.overrideOnComplete;
        else
          options.onComplete = this._onRequestComplete.bind(this);
        options._RicoOptionsProcessed = true;
      }

     // Set the default options and extend with any user options
     this.options = {
                     requestHeaders: requestHeaders,
                     parameters:     options.parameters,
                     postBody:       xmlDoc,
                     method:         sendMethod,
                     onComplete:     options.onComplete
                    };
     // Set any user options:
     Object.extend(this.options, options);
     return this.options;
   },

   _createQueryString: function( theArgs, offset ) {
      var queryString = ""
      for ( var i = offset ; i < theArgs.length ; i++ ) {
          if ( i != offset )
            queryString += "&";

          var anArg = theArgs[i];

          if ( anArg.name != undefined && anArg.value != undefined ) {
            queryString += anArg.name +  "=" + escape(anArg.value);
          }
          else {
             var ePos  = anArg.indexOf('=');
             var argName  = anArg.substring( 0, ePos );
             var argValue = anArg.substring( ePos + 1 );
             queryString += argName + "=" + escape(argValue);
          }
      }
      return queryString;
   },

   _onRequestComplete : function(request) {
      if(!request)
          return;
      // User can set an onFailure option - which will be called by prototype
      if (request.status != 200)
        return;

      var response = request.responseXML.getElementsByTagName("ajax-response");
      if (response == null || response.length != 1)
         return;
      this._processAjaxResponse( response[0].childNodes );
      
      // Check if user has set a onComplete function
      var onRicoComplete = this.options.onRicoComplete;
      if (onRicoComplete != null)
          onRicoComplete();
   },

   _processAjaxResponse: function( xmlResponseElements ) {
      for ( var i = 0 ; i < xmlResponseElements.length ; i++ ) {
         var responseElement = xmlResponseElements[i];

         // only process nodes of type element.....
         if ( responseElement.nodeType != 1 )
            continue;

         var responseType = responseElement.getAttribute("type");
         var responseId   = responseElement.getAttribute("id");

         if ( responseType == "object" )
            this._processAjaxObjectUpdate( this.ajaxObjects[ responseId ], responseElement );
         else if ( responseType == "element" )
            this._processAjaxElementUpdate( this.ajaxElements[ responseId ], responseElement );
         else
            alert('unrecognized AjaxResponse type : ' + responseType );
      }
   },

   _processAjaxObjectUpdate: function( ajaxObject, responseElement ) {
      ajaxObject.ajaxUpdate( responseElement );
   },

   _processAjaxElementUpdate: function( ajaxElement, responseElement ) {
      ajaxElement.innerHTML = RicoUtil.getContentAsString(responseElement);
   }

}

var ajaxEngine = new Rico.AjaxEngine();




////////////////////////////////////////////////////
// start ricoCommon.js
/**
  *
  *  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.
  **/

if (typeof Rico=='undefined')
  throw("Cannot find the Rico object");
if (typeof Prototype=='undefined')
  throw("Rico requires the Prototype JavaScript framework");
Rico.prototypeVersion = parseFloat(Prototype.Version.split(".")[0] + "." + Prototype.Version.split(".")[1]);
if (Rico.prototypeVersion < 1.3)
  throw("Rico requires Prototype JavaScript framework version 1.3 or greater");

/** @singleton */
var RicoUtil = {

   getDirectChildrenByTag: function(e, tagName) {
      var kids = new Array();
      var allKids = e.childNodes;
      tagName=tagName.toLowerCase();
      for( var i = 0 ; i < allKids.length ; i++ )
         if ( allKids[i] && allKids[i].tagName && allKids[i].tagName.toLowerCase() == tagName )
            kids.push(allKids[i]);
      return kids;
   },

   createXmlDocument : function() {
      if (document.implementation && document.implementation.createDocument) {
         var doc = document.implementation.createDocument("", "", null);

         if (doc.readyState == null) {
            doc.readyState = 1;
            doc.addEventListener("load", function () {
               doc.readyState = 4;
               if (typeof doc.onreadystatechange == "function")
                  doc.onreadystatechange();
            }, false);
         }

         return doc;
      }

      if (window.ActiveXObject)
          return Try.these(
            function() { return new ActiveXObject('MSXML2.DomDocument')   },
            function() { return new ActiveXObject('Microsoft.DomDocument')},
            function() { return new ActiveXObject('MSXML.DomDocument')    },
            function() { return new ActiveXObject('MSXML3.DomDocument')   }
          ) || false;

      return null;
   },

   getInnerText: function(el) {
     if (typeof el == "string") return el;
     if (typeof el == "undefined") { return el };
     var cs = el.childNodes;
     var l = cs.length;
     if (el.innerText) return el.innerText;  //Not needed but it is faster
     var str = "";
     for (var i = 0; i < l; i++) {
       switch (cs[i].nodeType) {
         case 1: //ELEMENT_NODE
           str += (cs[i].tagName.toLowerCase()=='img') ? cs[i].src : ts_getInnerText(cs[i]);
           break;
         case 3: //TEXT_NODE
           str += cs[i].nodeValue;
           break;
       }
     }
     return str;
   },

   // For Konqueror 3.5, isEncoded must be true
   getContentAsString: function( parentNode, isEncoded ) {
      if (isEncoded) return this._getEncodedContent(parentNode);
      if (typeof parentNode.xml != 'undefined') return this._getContentAsStringIE(parentNode);
      return this._getContentAsStringMozilla(parentNode);
   },

   _getEncodedContent: function(parentNode) {
      if (parentNode.innerHTML) return parentNode.innerHTML;
      switch (parentNode.childNodes.length) {
        case 0:  return "";
        case 1:  return parentNode.firstChild.nodeValue;
        default: return parentNode.childNodes[1].nodeValue;
      }
   },

  _getContentAsStringIE: function(parentNode) {
     var contentStr = "";
     for ( var i = 0 ; i < parentNode.childNodes.length ; i++ ) {
         var n = parentNode.childNodes[i];
         if (n.nodeType == 4) {
             contentStr += n.nodeValue;
         }
         else {
           contentStr += n.xml;
       }
     }
     return contentStr;
  },

  _getContentAsStringMozilla: function(parentNode) {
     var xmlSerializer = new XMLSerializer();
     var contentStr = "";
     for ( var i = 0 ; i < parentNode.childNodes.length ; i++ ) {
          var n = parentNode.childNodes[i];
          if (n.nodeType == 4) { // CDATA node
              contentStr += n.nodeValue;
          }
          else {
            contentStr += xmlSerializer.serializeToString(n);
        }
     }
     return contentStr;
  },
  
  docElement: function() {
    return (document.compatMode && document.compatMode.indexOf("CSS")!=-1) ? document.documentElement : document.getElementsByTagName("body")[0];
  },

/**
 * return available height - excludes scrollbar & margin
 */
  windowHeight: function() {
    return window.innerHeight? window.innerHeight : this.docElement().clientHeight;
    //return this.docElement().clientHeight;
  },

/**
 * return available width - excludes scrollbar & margin
 */
  windowWidth: function() {
    return this.docElement().clientWidth;
  },

  docScrollLeft: function() {
     if ( window.pageXOffset )
        return window.pageXOffset;
     else if ( document.documentElement && document.documentElement.scrollLeft )
        return document.documentElement.scrollLeft;
     else if ( document.body )
        return document.body.scrollLeft;
     else
        return 0;
  },

  docScrollTop: function() {
     if ( window.pageYOffset )
        return window.pageYOffset;
     else if ( document.documentElement && document.documentElement.scrollTop )
        return document.documentElement.scrollTop;
     else if ( document.body )
        return document.body.scrollTop;
     else
        return 0;
  },

  nan2zero: function(n) {
    if (typeof(n)=='string') n=parseInt(n);
    return isNaN(n) || typeof(n)=='undefined' ? 0 : n;
  },

  eventKey: function(e) {
    if( typeof( e.keyCode ) == 'number'  ) {
      return e.keyCode; //DOM
    } else if( typeof( e.which ) == 'number' ) {
      return e.which;   //NS 4 compatible
    } else if( typeof( e.charCode ) == 'number'  ) {
      return e.charCode; //also NS 6+, Mozilla 0.9+
    }
    return -1;  //total failure, we have no way of obtaining the key code
  },

/**
 * Return the previous sibling that has the specified tagName
 */
   getPreviosSiblingByTagName: function(el,tagName) {
   	var sib=el.previousSibling;
   	while (sib) {
   		if ((sib.tagName==tagName) && (sib.style.display!='none')) return sib;
   		sib=sib.previousSibling;
   	}
   	return null;
   },

/**
 * Return the parent HTML element that has the specified tagName.
 * @param className optional
 */
   getParentByTagName: function(el,tagName,className) {
   	var par=el;
   	tagName=tagName.toLowerCase();
   	while (par) {
   		if (par.tagName && par.tagName.toLowerCase()==tagName)
        if (!className || par.className.indexOf(className)>=0) return par;
   		par=par.parentNode;
   	}
   	return null;
   },

/**
 * Wrap the children of a DOM element in a new element
 * @param el the element whose children are to be wrapped
 * @param cls class name of the wrapper (optional)
 * @param id id of the wrapper (optional)
 * @param wrapperTag type of wrapper element to be created (optional, defaults to DIV)
 */
  wrapChildren: function(el,cls,id,wrapperTag) {
    var tag=wrapperTag || 'div';
    var wrapper = document.createElement(tag);
    if (id) wrapper.id=id;
    if (cls) wrapper.className=cls;
    while (el.firstChild)
      wrapper.appendChild(el.firstChild);
    el.appendChild(wrapper);
    return wrapper;
  },
  
/**
 * Format a positive number
 * @param decPlaces the number of digits to display after the decimal point
 * @param thouSep the character to use as the thousands separator
 * @param decPoint the character to use as the decimal point
 */
  formatPosNumber: function(posnum,decPlaces,thouSep,decPoint) {
    var a=posnum.toFixed(decPlaces).split(/\./);
    if (thouSep) {
      var rgx = /(\d+)(\d{3})/;
      while (rgx.test(a[0]))
        a[0]=a[0].replace(rgx, '$1'+thouSep+'$2');
    }
    return a.join(decPoint);
  },

/**
 * Post condition - if childNodes[n] is refChild, than childNodes[n+1] is newChild.
 */
  DOMNode_insertAfter: function(newChild,refChild) {
    var parentx=refChild.parentNode;
    if(parentx.lastChild==refChild) { return parentx.appendChild(newChild);}
    else {return parentx.insertBefore(newChild,refChild.nextSibling);}
  },
   
  positionCtlOverIcon: function(ctl,icon) {
    if (ctl.style.display=='none') ctl.style.display='block';
    var offsets=Position.page(icon);
    var correction=Prototype.Browser.IE ? 1 : 2;  // based on a 1px border
    var lpad=this.nan2zero(Element.getStyle(icon,'padding-left'))
    ctl.style.left = (offsets[0]+lpad+correction)+'px';
    var scrTop=this.docScrollTop();
    var newTop=offsets[1] + correction + scrTop;
    var ctlht=ctl.offsetHeight;
    var iconht=icon.offsetHeight;
    if (newTop+iconht+ctlht < this.windowHeight()+scrTop)
      newTop+=iconht;  // display below icon
    else
      newTop=Math.max(newTop-ctlht,scrTop);  // display above icon
    ctl.style.top = newTop+'px';
  },

  createFormField: function(parent,elemTag,elemType,id,name) {
    if (typeof name!='string') name=id;
    if (Prototype.Browser.IE) {
      // IE cannot set NAME attribute on dynamically created elements
      var s=elemTag+' id="'+id+'"';
      if (elemType) s+=' type="'+elemType+'"';
      if (elemTag.match(/^(form|input|select|textarea|object|button|img)$/)) s+=' name="'+name+'"';
      var field=document.createElement('<'+s+' />');
    } else {
      var field=document.createElement(elemTag);
      if (elemType) field.type=elemType;
      field.id=id;
      if (typeof field.name=='string') field.name=name;
    }
    parent.appendChild(field);
    return field;
  },

/**
 * Gets the value of the specified cookie
 */
  getCookie: function(itemName) {
    var arg = itemName+'=';
    var alen = arg.length;
    var clen = document.cookie.length;
    var i = 0;
    while (i < clen) {
      var j = i + alen;
      if (document.cookie.substring(i, j) == arg) {
        var endstr = document.cookie.indexOf (';', j);
        if (endstr == -1) endstr=document.cookie.length;
        return unescape(document.cookie.substring(j, endstr));
      }
      i = document.cookie.indexOf(' ', i) + 1;
      if (i == 0) break;
    }
    return null;
  },
  
/**
 * Write information to cookie.
 * For cookies to be retained for the current session only, set daysToKeep=null.
 * To erase a cookie, pass a negative daysToKeep value.
 */
  setCookie: function(itemName,itemValue,daysToKeep,cookiePath,cookieDomain) {
  	var c = itemName+"="+escape(itemValue);
  	if (typeof(daysToKeep)=='number') {
  		var date = new Date();
  		date.setTime(date.getTime()+(daysToKeep*24*60*60*1000));
  		c+="; expires="+date.toGMTString();
  	}
  	if (typeof(cookiePath)=='string') c+="; path="+cookiePath;
  	if (typeof(cookieDomain)=='string') c+="; domain="+cookieDomain;
    document.cookie = c;
  }

};


// Translation helper object
/** @singleton */
var RicoTranslate = {
  phrases : {},
  thouSep : ",",
  decPoint: ".",
  langCode: "en",
  re      : /^(\W*)\b(.*)\b(\W*)$/,
  dateFmt : "mm/dd/yyyy",
  timeFmt : "hh:mm:ss a/pm",
  monthNames: ['January','February','March','April','May','June',
               'July','August','September','October','November','December'],
  dayNames: ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
  
  addPhrase: function(fromPhrase, toPhrase) {
    this.phrases[fromPhrase]=toPhrase;
  },
  
/**
 * fromPhrase may contain multiple words/phrases separated by tabs
 * and each portion will be looked up separately.
 * Punctuation & spaces at the beginning or
 * ending of a phrase are ignored.
 */
  getPhrase: function(fromPhrase) {
    var words=fromPhrase.split(/\t/);
    var transWord,translated = '';
    for (var i=0; i<words.length; i++) {
      if (this.re.exec(words[i])) {
        transWord=this.phrases[RegExp.$2];
        translated += (typeof transWord=='string') ? RegExp.$1+transWord+RegExp.$3 : words[i];
      } else {
        translated += words[i];
      }
    }
    return translated;
  }
}


if (!Date.prototype.formatDate) {
  Date.prototype.formatDate = function(fmt) {
    var d=this;
    var datefmt=(typeof fmt=='string') ? datefmt=fmt : 'translateDate';
    switch (datefmt) {
      case 'locale':
      case 'localeDateTime':
        return d.toLocaleString();
      case 'localeDate':
        return d.toLocaleDateString();
      case 'translate':
      case 'translateDateTime':
        datefmt=RicoTranslate.dateFmt+' '+RicoTranslate.timeFmt;
        break;
      case 'translateDate':
        datefmt=RicoTranslate.dateFmt;
        break;
    }
    return datefmt.replace(/(yyyy|mmmm|mmm|mm|dddd|ddd|dd|hh|nn|ss|a\/p)/gi,
      function($1) {
        switch ($1.toLowerCase()) {
        case 'yyyy': return d.getFullYear();
        case 'mmmm': return RicoTranslate.monthNames[d.getMonth()];
        case 'mmm':  return RicoTranslate.monthNames[d.getMonth()].substr(0, 3);
        case 'mm':   return (d.getMonth() + 1).toPaddedString(2);
        case 'm':    return (d.getMonth() + 1);
        case 'dddd': return RicoTranslate.dayNames[d.getDay()];
        case 'ddd':  return RicoTranslate.dayNames[d.getDay()].substr(0, 3);
        case 'dd':   return d.getDate().toPaddedString(2);
        case 'd':    return d.getDate();
        case 'hh':   return ((h = d.getHours() % 12) ? h : 12).toPaddedString(2);
        case 'h':    return ((h = d.getHours() % 12) ? h : 12);
        case 'HH':   return d.getHours().toPaddedString(2);
        case 'H':    return d.getHours();
        case 'nn':   return d.getMinutes().toPaddedString(2);
        case 'ss':   return d.getSeconds().toPaddedString(2);
        case 'a/p':  return d.getHours() < 12 ? 'a' : 'p';
        }
      }
    );
  }
}

if (!Date.prototype.setISO8601) {
/**
 * Converts a string in ISO 8601 format to a date object.
 * Returns true if string is a valid date or date-time.
 * Based on info at http://delete.me.uk/2005/03/iso8601.html
 */
  Date.prototype.setISO8601 = function (string) {
    if (!string) return false;
    var d = string.match(/(\d\d\d\d)(?:-?(\d\d)(?:-?(\d\d)(?:[T ](\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|(?:([-+])(\d\d)(?::?(\d\d))?)?)?)?)?)?/);
    if (!d) return false;
    var offset = 0;
    var date = new Date(d[1], 0, 1);
  
    if (d[2]) { date.setMonth(d[2] - 1); }
    if (d[3]) { date.setDate(d[3]); }
    if (d[4]) { date.setHours(d[4]); }
    if (d[5]) { date.setMinutes(d[5]); }
    if (d[6]) { date.setSeconds(d[6]); }
    if (d[7]) { date.setMilliseconds(Number("0." + d[7]) * 1000); }
    if (d[8]) {
        if (d[10] && d[11]) offset = (Number(d[10]) * 60) + Number(d[11]);
        offset *= ((d[9] == '-') ? 1 : -1);
        offset -= date.getTimezoneOffset();
    }
    var time = (Number(date) + (offset * 60 * 1000));
    this.setTime(Number(time));
    return true;
  }
}

if (!Date.prototype.toISO8601String) {
/**
 * Convert date to an ISO 8601 formatted string.
 * <p>format is an integer in the range 1-6:<dl>
 * <dt>1 (year)</dt>
 *   <dd>YYYY (eg 1997)</dd>
 * <dt>2 (year and month)</dt>
 *   <dd>YYYY-MM (eg 1997-07)</dd>
 * <dt>3 (complete date)</dt>
 *   <dd>YYYY-MM-DD (eg 1997-07-16)</dd>
 * <dt>4 (complete date plus hours and minutes)</dt>
 *   <dd>YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00)</dd>
 * <dt>5 (complete date plus hours, minutes and seconds)</dt>
 *   <dd>YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00)</dd>
 * <dt>6 (complete date plus hours, minutes, seconds and a decimal
 *   fraction of a second)</dt>
 *   <dd>YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00)</dd>
 *</dl>
 * Based on: http://www.codeproject.com/jscript/dateformat.asp
 */
  Date.prototype.toISO8601String = function (format, offset) {
    if (!format) { var format = 6; }
    if (!offset) {
        var offset = 'Z';
        var date = this;
    } else {
        var d = offset.match(/([-+])([0-9]{2}):([0-9]{2})/);
        var offsetnum = (Number(d[2]) * 60) + Number(d[3]);
        offsetnum *= ((d[1] == '-') ? -1 : 1);
        var date = new Date(Number(Number(this) + (offsetnum * 60000)));
    }

    var zeropad = function (num) { return ((num < 10) ? '0' : '') + num; }

    var str = "";
    str += date.getUTCFullYear();
    if (format > 1) { str += "-" + zeropad(date.getUTCMonth() + 1); }
    if (format > 2) { str += "-" + zeropad(date.getUTCDate()); }
    if (format > 3) {
        str += "T" + zeropad(date.getUTCHours()) +
               ":" + zeropad(date.getUTCMinutes());
    }
    if (format > 5) {
        var secs = Number(date.getUTCSeconds() + "." +
                   ((date.getUTCMilliseconds() < 100) ? '0' : '') +
                   zeropad(date.getUTCMilliseconds()));
        str += ":" + zeropad(secs);
    } else if (format > 4) { str += ":" + zeropad(date.getUTCSeconds()); }

    if (format > 3) { str += offset; }
    return str;
  }
}

if (!String.prototype.formatDate) {
  String.prototype.formatDate = function(fmt) {
    var s=this.replace(/-/g,'/');
    var d = new Date(s);
    return isNaN(d) ? this : d.formatDate(fmt);
  }
}

if (!Number.prototype.formatNumber) {
/**
 * Format a number according to the specs in assoc array 'fmt'.
 * Result is a string, wrapped in a span element with a class of: negNumber, zeroNumber, posNumber
 * These classes can be set in CSS to display negative numbers in red, for example.
 * 
 * <p>fmt may contain:<dl>
 *   <dt>multiplier </dt><dd> the original number is multiplied by this amount before formatting</dd>
 *   <dt>decPlaces  </dt><dd> number of digits to the right of the decimal point</dd>
 *   <dt>thouSep    </dt><dd> character to use as the thousands separator</dd>
 *   <dt>prefix     </dt><dd> string added to the beginning of the result (e.g. a currency symbol)</dd>
 *   <dt>suffix     </dt><dd> string added to the end of the result (e.g. % symbol)</dd>
 *   <dt>negSign    </dt><dd> specifies format for negative numbers: L=leading minus, T=trailing minus, P=parens</dd>
 *</dl>
 */
  Number.prototype.formatNumber = function(fmt) {
    if (isNaN(this)) return 'NaN';
    var n=this;
    if (typeof fmt.multiplier=='number') n*=fmt.multiplier;
    var decPlaces=typeof fmt.decPlaces=='number' ? fmt.decPlaces : 0;
    var thouSep=typeof fmt.thouSep=='string' ? fmt.thouSep : RicoTranslate.thouSep;
    var decPoint=typeof fmt.decPoint=='string' ? fmt.decPoint : RicoTranslate.decPoint;
    var prefix=fmt.prefix || "";
    var suffix=fmt.suffix || "";
    var negSign=typeof fmt.negSign=='string' ? fmt.negSign : "L";
    negSign=negSign.toUpperCase();
    var s,cls;
    if (n<0.0) {
      s=RicoUtil.formatPosNumber(-n,decPlaces,thouSep,decPoint);
      if (negSign=="P") s="("+s+")";
      s=prefix+s;
      if (negSign=="L") s="-"+s;
      if (negSign=="T") s+="-";
      cls='negNumber';
    } else {
      cls=n==0.0 ? 'zeroNumber' : 'posNumber';
      s=prefix+RicoUtil.formatPosNumber(n,decPlaces,thouSep,decPoint);
    }
    return "<span class='"+cls+"'>"+s+suffix+"</span>";
  }
}

if (!String.prototype.formatNumber) {
/**
 * Take a string that can be converted via parseFloat
 * and format it according to the specs in assoc array 'fmt'.
 */
  String.prototype.formatNumber = function(fmt) {
    var n=parseFloat(this);
    return isNaN(n) ? this : n.formatNumber(fmt);
  }
}

/**
 * Fix select control bleed-thru on floating divs in IE.
 * Based on technique published by Joe King at:
 * http://dotnetjunkies.com/WebLog/jking/archive/2003/10/30/2975.aspx
 */
Rico.Shim = Class.create();

if (Prototype.Browser.IE) {
  Rico.Shim.prototype = {
  
    initialize: function() {
      this.ifr = document.createElement('iframe');
      this.ifr.style.position="absolute";
      this.ifr.style.display = "none";
      this.ifr.src="javascript:false;";
      var body = document.getElementsByTagName("body")[0];
      body.appendChild(this.ifr);
    },
  
    hide: function() {
      this.ifr.style.display = "none";
    },
    
    show: function(DivRef) {
      this.ifr.style.width = DivRef.offsetWidth;
      this.ifr.style.height= DivRef.offsetHeight;
      this.ifr.style.top   = DivRef.style.top;
      this.ifr.style.left  = DivRef.style.left;
      this.ifr.style.zIndex= DivRef.currentStyle.zIndex - 1;
      //this.ifr.style.border = "2px solid green"; // for debugging
      this.ifr.style.display = "block";
    }
  }
} else {
  Rico.Shim.prototype = {
    initialize: function() {},
    hide: function() {},
    show: function() {}
  }
}


/**
 * Rico.Shadow is intended for positioned elements.
 * Uses blur filter in IE, and alpha-transparent png images for all other browsers.
 * Based on: http://www.positioniseverything.net/articles/dropshadows.html
 */
Rico.Shadow = Class.create();

Rico.Shadow.prototype = {

  initialize: function(DivRef) {
    this.div = document.createElement('div');
    this.div.style.position="absolute";
    if (typeof this.div.style.filter=='undefined') {
      new Image().src = Rico.imgDir+"shadow.png";
      new Image().src = Rico.imgDir+"shadow_ur.png";
      new Image().src = Rico.imgDir+"shadow_ll.png";
      this.createShadow();
      this.offset=5;
    } else {
      this.div.style.backgroundColor='#888';
      this.div.style.filter='progid:DXImageTransform.Microsoft.Blur(makeShadow=1, shadowOpacity=0.3, pixelRadius=3)';
      this.offset=0; // MS blur filter already does offset
    }
    this.div.style.display = "none";
    DivRef.parentNode.appendChild(this.div);
    this.DivRef=DivRef;
  },

  createShadow: function() {
    var tab = document.createElement('table');
    tab.style.height='100%';
    tab.style.width='100%';
    tab.cellSpacing=0;
    tab.dir='ltr';

    var tr1=tab.insertRow(-1);
    tr1.style.height='8px';
    var td11=tr1.insertCell(-1);
    td11.style.width='8px';
    var td12=tr1.insertCell(-1);
    td12.style.background="transparent url("+Rico.imgDir+"shadow_ur.png"+") no-repeat right bottom"

    var tr2=tab.insertRow(-1);
    var td21=tr2.insertCell(-1);
    td21.style.background="transparent url("+Rico.imgDir+"shadow_ll.png"+") no-repeat right bottom"
    var td22=tr2.insertCell(-1);
    td22.style.background="transparent url("+Rico.imgDir+"shadow.png"+") no-repeat right bottom"

    this.div.appendChild(tab);
  },

  hide: function() {
    this.div.style.display = "none";
  },
  
  show: function() {
    this.div.style.width = this.DivRef.offsetWidth + 'px';
    this.div.style.height= this.DivRef.offsetHeight + 'px';
    this.div.style.top   = (parseInt(this.DivRef.style.top)+this.offset)+'px';
    this.div.style.left  = (parseInt(this.DivRef.style.left)+this.offset)+'px';
    this.div.style.zIndex= parseInt(Element.getStyle(this.DivRef,'z-index')) - 1;
    this.div.style.display = "block";
  }
}

Rico.Menu = Class.create();

Rico.Menu.prototype = {

  initialize: function(options) {
    this.options = {
      width        : "15em",
      hideOnEscape : true,
      hideOnClick  : true
    };
    if (typeof options=='string')
      this.options.width=options;
    else
      Object.extend(this.options, options || {});
    this.hideFunc=null;
    this.highlightElem=null;
  },
  
  createDiv: function(parentNode) {
    if (this.div) return;
    this.div = document.createElement('div');
    this.div.className = Prototype.Browser.WebKit ? 'ricoMenuSafari' : 'ricoMenu';
    this.div.style.position="absolute";
    this.div.style.width=this.options.width;
    if (!parentNode) {
      parentNode = document.getElementsByTagName("body")[0];
      if (!parentNode) alert('no document body!');
    }
    parentNode.appendChild(this.div);
    this.width=this.div.offsetWidth
    this.shim=new Rico.Shim();
    this.shadow=new Rico.Shadow(this.div);
    this.hidemenu();
    this.itemCount=0;
    this.direction=Element.getStyle(this.div,'direction').toLowerCase();  // ltr or rtl
    if (this.options.hideOnClick)
      Event.observe(document,"click", this.cancelmenu.bindAsEventListener(this), false);
    if (this.options.hideOnEscape)
      Event.observe(document,"keyup", this.checkKey.bindAsEventListener(this), false);
  },
  
  ignoreMenuClicks: function() {
    Event.observe(this.div,"click", this.ignoreClick.bindAsEventListener(this), false);
  },

  ignoreClick: function(e) {
    Event.stop(e);
    return false;
  },
  
  // event handler to process keyup events (hide menu on escape key)
  checkKey: function(e) {
    if (RicoUtil.eventKey(e)==27) this.cancelmenu(e);
    return true;
  },

  showmenu: function(e,hideFunc){
    Event.stop(e);
    this.hideFunc=hideFunc;
    if (this.div.childNodes.length==0) {
      this.cancelmenu();
      return false;
    }
    this.openmenu(e.clientX,e.clientY,0,0);
  },
  
  openmenu: function(x,y,clickItemWi,clickItemHt) {
    var margin=6; // account for shadow
    var newLeft=RicoUtil.docScrollLeft()+x;
    //window.status='openmenu: newLeft='+newLeft+' width='+this.width+' windowWi='+RicoUtil.windowWidth();
    if (this.direction == 'rtl') {
      if (newLeft > this.width+clickItemWi) newLeft-=this.width+clickItemWi;
    } else {
      if (x+this.width+margin > RicoUtil.windowWidth()) newLeft-=this.width+clickItemWi;
    }
    this.div.style.left=newLeft+"px";
    var newTop=RicoUtil.docScrollTop()+y;
    var contentHt=this.div.offsetHeight;
    if (y+contentHt+margin > RicoUtil.windowHeight())
      newTop=Math.max(newTop-contentHt+clickItemHt,0);
    this.div.style.top=newTop+"px";
    this.div.style.visibility ="visible";
    this.shim.show(this.div);
    this.shadow.show();
    return false;
  },

  clearMenu: function() {
    this.div.innerHTML="";
    this.defaultAction=null;
    this.itemCount=0;
  },

  addMenuHeading: function(hdg,translate) {
    var el=document.createElement('div')
    el.innerHTML =(translate==null || translate==true) ? RicoTranslate.getPhrase(hdg) : hdg;
    el.className='ricoMenuHeading';
    this.div.appendChild(el);
  },

  addMenuBreak: function() {
    var brk=document.createElement('div');
    brk.className="ricoMenuBreak";
    this.div.appendChild(brk);
  },

  addSubMenuItem: function(menutext, submenu, translate) {
    var dir=this.direction=='rtl' ? 'left' : 'right';
    var a=this.addMenuItem(menutext,null,true,null,translate);
    a.className='ricoSubMenu';
    a.style.backgroundImage='url('+Rico.imgDir+dir+'.gif)';
    a.style.backgroundRepeat='no-repeat';
    a.style.backgroundPosition=dir;
    a.onmouseover=this.showSubMenu.bind(this,a,submenu);
    a.onmouseout=this.subMenuOut.bindAsEventListener(this);
  },
  
  showSubMenu: function(a,submenu) {
    if (this.openSubMenu) this.hideSubMenu();
    this.openSubMenu=submenu;
    this.openMenuAnchor=a;
    var pos=Position.page(a);
    if (a.className=='ricoSubMenu') a.className='ricoSubMenuOpen';
    submenu.openmenu(pos[0]+a.offsetWidth, pos[1], a.offsetWidth-2, a.offsetHeight+2);
  },
  
  subMenuOut: function(e) {
    if (!this.openSubMenu) return;
    Event.stop(e);
    var elem=Event.element(e);
    var reltg = (e.relatedTarget) ? e.relatedTarget : e.toElement;
    try {
      while (reltg != null && reltg != this.openSubMenu.div)
        reltg=reltg.parentNode;
    } catch(err) {}
    if (reltg == this.openSubMenu.div) return;
    this.hideSubMenu();
  },
  
  hideSubMenu: function() {
    if (this.openMenuAnchor) {
      this.openMenuAnchor.className='ricoSubMenu';
      this.openMenuAnchor=null;
    }
    if (this.openSubMenu) {
      this.openSubMenu.hidemenu();
      this.openSubMenu=null;
    }
  },

  addMenuItem: function(menutext,action,enabled,title,translate,target) {
    this.itemCount++;
    if (translate==null) translate=true;
    var a = document.createElement(typeof action=='string' ? 'a' : 'div');
    if ( arguments.length < 3 || enabled ) {
      switch (typeof action) {
        case 'function': 
          a.onclick = action; 
          break;
        case 'string'  : 
          a.href = action; 
          if (target) a.target = target; 
          break
      }
      a.className = 'enabled';
      if (this.defaultAction==null) this.defaultAction=action;
    } else {
      a.disabled = true;
      a.className = 'disabled';
    }
    a.innerHTML = translate ? RicoTranslate.getPhrase(menutext) : menutext;
    if (typeof title=='string')
      a.title = translate ? RicoTranslate.getPhrase(title) : title;
    a=this.div.appendChild(a);
    Event.observe(a,"mouseover", this.mouseOver.bindAsEventListener(this), false);
    Event.observe(a,"mouseout", this.mouseOut.bindAsEventListener(this), false);
    return a;
  },
  
  mouseOver: function(e) {
    if (this.highlightElem && this.highlightElem.className=='enabled-hover') {
      // required for Safari
      this.highlightElem.className='enabled';
      this.highlightElem=null;
    }
    var elem=Event.element(e);
    if (this.openMenuAnchor && this.openMenuAnchor!=elem)
      this.hideSubMenu();
    if (elem.className=='enabled') {
      elem.className='enabled-hover';
      this.highlightElem=elem;
    }
  },

  mouseOut: function(e) {
    var elem=Event.element(e);
    if (elem.className=='enabled-hover') elem.className='enabled';
    if (this.highlightElem==elem) this.highlightElem=null;
  },

  isVisible: function() {
    return this.div && this.div.style.visibility!="hidden";
  },
  
  cancelmenu: function() {
    if (this.hideFunc) this.hideFunc();
    this.hideFunc=null;
    this.hidemenu();
  },

  hidemenu: function() {
    if (!this.div) return;
    this.shim.hide();
    this.shadow.hide();
    if (this.openSubMenu) this.openSubMenu.hidemenu();
    this.div.style.visibility="hidden";
    // make sure it stays out of the way and doesn't cause a scrollbar to appear
    this.div.style.top = '0px';
    this.div.style.left= '0px';
  }

};

Rico.includeLoaded('ricoCommon.js');


////////////////////////////////////////////////////
// start ricoEffects.js
/**
  *  (c) 2005-2007 Richard Cowin (http://openrico.org)
  *
  *  Rico is 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
  **/

Rico.animate = function(effect){
	new Rico.Effect.Animator().play(effect, arguments[1]);
}


Rico.Effect = {}
Rico.Effect.easeIn = function(step){
  return Math.sqrt(step)
}
Rico.Effect.easeOut = function(step){
  return step*step
}
Rico.Stepping = {}
Rico.Stepping.easeIn = Rico.Effect.easeIn;
Rico.Stepping.easeOut = Rico.Effect.easeOut;

Rico.Effect.Animator = Class.create();
Rico.Effect.Animator.prototype = {
	initialize : function(effect) {
		this.animateMethod = this.animate.bind(this);
		this.options = arguments[1] || {};
		this.stepsLeft = 0;
		if (!effect) return;
		this.reset(effect, arguments[1]);
	},
	reset: function(effect){
		this.effect = effect;
    if (arguments[1]) this.setOptions(arguments[1]);
		this.stepsLeft = this.options.steps;
		this.duration = this.options.duration;
	},
	setOptions: function(options){
	  this.options = Object.extend({
			steps: 10,
			duration: 200,
			rate: function(steps){ return steps;}
    }, options|| {});
	},
	play: function(effect) {
	  this.setOptions(arguments[1])
	  if (effect)
  	  if (effect.step)
  		  this.reset(effect, arguments[1]);
  		else{
  		  $H(effect).keys().each((function(e){
  		    var effectClass = {fadeOut:Rico.Effect.FadeOut}[e];
  		    this.reset(new effectClass(effect[e]));
  		  }).bind(this))		  
  		}
		this.animate();
	},
	stop: function() {
		this.stepsLeft = this.options.steps;
	},
	pause: function() {
		this.interupt = true;
	},
	resume: function() {
	  this.interupt = false;
	  if (this.stepsLeft >0)
	    this.animate();
	},
	animate: function() {
	  if (this.interupt)
	    return;
		if (this.stepsLeft <=0) {
			if (this.effect.finish)  this.effect.finish();
			if (this.options.onFinish) this.options.onFinish();
			return;
		}
		if (this.timer)
			clearTimeout(this.timer);
		this.effect.step(this.options.rate(this.stepsLeft));
		this.startNextStep();
  },
	startNextStep: function() {
		var stepDuration = Math.round(this.duration/this.stepsLeft) ;
    this.duration -= stepDuration;
    this.stepsLeft--;
    this.timer = setTimeout(this.animateMethod, stepDuration);
	},
  isPlaying: function(){
    return this.stepsLeft != 0 && !this.interupt;
  }
}

Rico.Effect.Group = Class.create();
Rico.Effect.Group.prototype = {
  initialize: function(effects){
    this.effects = effects;
  },
  step: function(stepsToGo){ 
    this.effects.each(function(e){e.step(stepsToGo)});
  },
  finish: function(){
    this.effects.each(function(e){if (e.finish) e.finish()});
  }
}

Rico.Effect.SizeAndPosition = Class.create();
Rico.Effect.SizeAndPosition.prototype = {
   initialize: function(element, x, y, w, h) {
      this.element = $(element);
      this.x = x || this.element.offsetLeft;
      this.y = y || this.element.offsetTop;
      this.w = w || this.element.offsetWidth;
      this.h = h || this.element.offsetHeight;
   },
   step: function(stepsToGo) {  
			var left = this.element.offsetLeft + ((this.x - this.element.offsetLeft)/stepsToGo) + "px"
			var top = this.element.offsetTop + ((this.y - this.element.offsetTop)/stepsToGo) + "px"
			var width = this.element.offsetWidth + ((this.w - this.element.offsetWidth)/stepsToGo) + "px"
			var height = this.element.offsetHeight + ((this.h - this.element.offsetHeight)/stepsToGo) + "px"
      var style = this.element.style;
			style.left = left;
			style.top = top;
			style.width = width;
			style.height = height;
   }
}

Rico.AccordionEffect = Class.create();
Rico.AccordionEffect.prototype = {
  initialize: function(toClose, toOpen, height) {
    this.toClose   = toClose;
    this.toOpen    = toOpen;
/*    if (!navigator.appVersion.match(/\bMSIE\b/)) {*/
      Element.makeClipping(toOpen);
      Element.makeClipping(toClose);
/*    }*/
    Rico.Controls.disableNativeControls(toClose);
    Element.show(toOpen);
    this.toOpen.style.height = "0px";
    this.endHeight = height;
  },
  step: function(framesLeft) {
     var cHeight = Math.max(1,this.toClose.offsetHeight - parseInt((parseInt(this.toClose.offsetHeight))/framesLeft));
     var closeHeight = cHeight + "px";
     var openHeight = (this.endHeight - cHeight) + "px"
     this.toClose.style.height = closeHeight;
     this.toOpen.style.height = openHeight;
  },
  finish: function(){
    Element.hide(this.toClose)
    this.toOpen.style.height = this.endHeight + "px";
    this.toClose.style.height = "0px";
    if (!navigator.appVersion.match(/\bMSIE\b/)) {
      Element.undoClipping(this.toOpen);
      Element.undoClipping(this.toClose);
    }

		Rico.Controls.enableNativeControls(this.toOpen);
  }
};

Rico.Effect.SizeFromBottom = Class.create()
Rico.Effect.SizeFromBottom.prototype = {
  initialize: function(element, y, h) {
    this.element = $(element);
    this.y = y || this.element.offsetTop;
    this.h = h || this.element.offsetHeight;
    this.options  = arguments[3] || {};
  },
  step: function(framesToGo) {  
		var top = this.element.offsetTop + ((this.y - this.element.offsetTop)/framesToGo) + "px"
		var height = this.element.offsetHeight + ((this.h - this.element.offsetHeight)/framesToGo) + "px"
    var style = this.element.style;
		style.height = height;     
		style.top = top;
  }
}

Rico.Effect.Position = Class.create();
Rico.Effect.Position.prototype = {
  initialize: function(element, x, y) {
    this.element = $(element);
    this.x = x || this.element.offsetLeft;
    this.destTop = y || this.element.offsetTop;
  },
  step: function(stepsToGo) {  
  	var left = this.element.offsetLeft + ((this.x - this.element.offsetLeft)/stepsToGo) + "px"
  	var top = this.element.offsetTop + ((this.destTop - this.element.offsetTop)/stepsToGo) + "px"
    var style = this.element.style;
  	style.left = left;
  	style.top = top;
  }
}

Rico.Effect.FadeTo = Class.create()
Rico.Effect.FadeTo.prototype = {
  initialize: function(element, value){
    this.element = element;
    this.opacity = Element.getStyle(this.element, 'opacity') || 1.0;
    this.target = Math.min(value, 1.0);
  },
  step: function(framesLeft) {
    var curOpacity = Element.getStyle(this.element, 'opacity');
    var newOpacity = curOpacity + (this.target - curOpacity)/framesLeft
    Rico.Effect.setOpacity(this.element, Math.min(Math.max(0,newOpacity),1.0));
  }
}

Rico.Effect.FadeOut = Class.create()
Rico.Effect.FadeOut.prototype = {
  initialize: function(element){
    this.effect = new Rico.Effect.FadeTo(element, 0.0)
  },
  step: function(framesLeft) {
    this.effect.step(framesLeft);
  }
}

Rico.Effect.FadeIn = Class.create()
Rico.Effect.FadeIn.prototype = {
  initialize: function(element){
    var options = arguments[1] || {}
    var startValue = options.startValue || 0
    Element.setStyle(element, 'opacity', startValue);
    this.effect = new Rico.Effect.FadeTo(element, 1.0)
  },
  step: function(framesLeft) {
    this.effect.step(framesLeft);
  }
}

Rico.Effect.setOpacity= function(element, value) {
   element.style.filter = "alpha(opacity:"+Math.round(value*100)+")";
   element.style.opacity = value; 
}

Rico.Effect.SizeFromTop = Class.create()
Rico.Effect.SizeFromTop.prototype = {
  initialize: function(element, scrollElement, y, h) {
     this.element = $(element);
     this.h = h || this.element.offsetHeight;
	//	 element.style.top = y;
     this.scrollElement = scrollElement;
     this.options  = arguments[4] || {};
     this.baseHeight = this.options.baseHeight ||  Math.max(this.h, this.element.offsetHeight)
  },
  step: function(framesToGo) {  
    var rawHeight = this.element.offsetHeight + ((this.h - this.element.offsetHeight)/framesToGo);
		var height = rawHeight + "px"
		var scroll = (rawHeight - this.baseHeight) + "px";
		this.scrollElement.style.top = scroll;
		this.element.style.height = height;     
  }
}


Rico.Effect.Height = Class.create()
Rico.Effect.Height.prototype = {
  initialize: function(element, endHeight) {
    this.element = element
		this.endHeight = endHeight
  },
  step: function(stepsLeft) {
    if (this.element.constructor != Array){
      var height = this.element.offsetHeight + ((this.endHeight - this.element.offsetHeight)/stepsLeft) + "px"
      this.element.style.height = height;
    } else {
      var height = this.element[0].offsetHeight + ((this.endHeight - this.element[0].offsetHeight)/stepsLeft) + "px"
      this.element.each(function(e){e.style.height = height})
    }
  }
}

Rico.Effect.SizeWidth = Class.create();
Rico.Effect.SizeWidth.prototype = {
    initialize: function(element, endWidth) {
      this.element = element
			this.endWidth = endWidth
    },
    step: function(stepsLeft) {
       delta = Math.abs(this.endWidth - parseInt(this.element.offsetWidth))/(stepsLeft);
       this.element.style.width = (this.element.offsetWidth - delta) + "px";
    }
}

//these are to support non Safari browsers and keep controls from bleeding through on absolute positioned element.
Rico.Controls = {
	editors: [],
	scrollSelectors: [],
	
	disableNativeControls: function(element) {
		Rico.Controls.defaultDisabler.disableNative(element);
  },
	enableNativeControls: function(element){
		Rico.Controls.defaultDisabler.enableNative(element);
	},
	prepareForSizing: function(element){
    Element.makeClipping(element)
    Rico.Controls.disableNativeControls(element)
  },
  resetSizing: function(element){
    Element.undoClipping(element)
    Rico.Controls.enableNativeControls(element)
	},
	registerScrollSelectors: function(selectorSet) {
	  selectorSet.each(function(s){Rico.Controls.scrollSelectors.push(Rico.selector(s))});
	}
}

Rico.Controls.Disabler = Class.create();
Rico.Controls.Disabler.prototype = {
	initialize: function(){
		this.options = Object.extend({
			excludeSet: [],
			hidables: Rico.Controls.editors
    }, arguments[0] || {});
	},
  disableNative: function(element) {
    if (!(/Konqueror|Safari|KHTML/.test(navigator.userAgent))){
			if (!navigator.appVersion.match(/\bMSIE\b/))
				this.blockControls(element).each(function(e){Element.makeClipping(e)});
			else
			  this.hidableControls(element).each(function(e){e.disable()});
    }
  },
  enableNative: function(element){
    if (!(/Konqueror|Safari|KHTML/.test(navigator.userAgent))){
			if (!navigator.appVersion.match(/\bMSIE\b/))
				this.blockControls(element).each(function(e){Element.undoClipping(e)});
			else
			  this.hidableControls(element).each(function(e){e.enable()});
    }
  },
	blockControls: function(element){
	  try{
		var includes = [];
		if (this.options.includeSet)
			includes = this.options.includeSet;
		else{
		  var selectors = this.options.includeSelectors || Rico.Controls.scrollSelectors;
			includes = selectors.map(function(s){return s.findAll(element)}).flatten();
    }
		return includes.select(function(e){return (Element.getStyle(e, 'display') != 'none') && !this.options.excludeSet.include(e)}.bind(this));
  }catch(e) { return []}
	},
	hidableControls: function(element){
		if (element)
			return this.options.hidables.select(function(e){return Element.childOf(e, element)});
		else
			return this.options.hidables;
	}
}	
                    
Rico.Controls.defaultDisabler = new Rico.Controls.Disabler();
Rico.Controls.blankDisabler = new Rico.Controls.Disabler({includeSet:[],hidables:[]});
                 
Rico.Controls.HidableInput = Class.create(); 
Rico.Controls.HidableInput.prototype = {
	initialize: function(field, view){	
		this.field = field;
		this.view = view;
		this.enable();
		Rico.Controls.editors.push(this);
	},
	enable: function(){
		Element.hide(this.view);
		Element.show(this.field);
	},
	disable: function(){
		this.view.value = $F(this.field);
		if (this.field.offsetWidth > 1) {
	    this.view.style.width =  parseInt(this.field.offsetWidth)  + "px";
		  Element.hide(this.field);
		  Element.show(this.view);
	  }
	}
}


Element.forceRefresh = function(item) {
  try {
    var n = document.createTextNode(' ')
    item.appendChild(n); item.removeChild(n);
  } catch(e) { }
};

////////////////////////////////////////////////////
// start ricoBehaviors.js
/**
  *  (c) 2005-2007 Richard Cowin (http://openrico.org)
  *
  *  Rico is 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
  **/

Rico.EventWrapper = Class.create();
Rico.EventWrapper.prototype = {
  initialize: function(handler, target){
    this.handler = handler;
    this.target = target;
    this.wrapper = this.wrapperCall.bindAsEventListener(this)
  },
  wrapperCall: function(event){
    this.handler(event, this.target)
  }
}
   
Rico.Ajax = {};

Rico.CachedAjax = {
  cacheTime: 600,
  cachedRequests: {}
}

Rico.CachedReplaceHTML = Class.create();
Rico.CachedReplaceHTML.prototype = {
  initialize:function(){
  }
}

Rico.Ajax.Request = Class.create();
Rico.Ajax.Request.prototype = {
  initialize:function(url, options){
    key = url;
    if (options.parameters)
      key += options.parameters    
    request = Rico.CachedAjax.cachedRequests[key]
    if (request)
      request.evalResponse();
    else
      Rico.CachedAjax.cachedRequests[key] = new Ajax.Request(url, options);
  }
}

Rico.selectionSet = function(set, options){
  new Rico.SelectionSet(set, options)
}

Rico.SelectionSet = Class.create(); 
Rico.SelectionSet.prototype = {
	initialize: function(selectionSet, options){
		this.options = options || {}
    if (typeof selectionSet == 'string')
      selectionSet = $$(selectionSet)
	  this.previouslySelected = [];
		this.selectionSet = selectionSet;
		this.selectedClassName = this.options.selectedClass || "selected";
		this.selectNode = this.options.selectNode || function(e){return e};
		this.onSelect = this.options.onSelect;
    this.onFirstSelect = this.options.onFirstSelect;
		this.clickHandler = this.click.bind(this);
		selectionSet.each(function(e) {Event.observe(e, "click", new Rico.EventWrapper(this.clickHandler,e).wrapper);}.bind(this))
    if (!this.options.noDefault)
		  this.selectIndex(this.options.selectedIndex || 0)
	},
	reset: function(){
	  this.previouslySelected = [];
	  this.notifySelected(this.selected);
	},
	select: function(element){
		if (this.selected == element)
			return;

		if (this.selected)
		  new Element.ClassNames(this.selectNode(this.selected)).remove(this.selectedClassName)
    
    this.notifySelected(element)

		this.selected = element;
		new Element.ClassNames(this.selectNode(this.selected)).add(this.selectedClassName)
	},
	notifySelected: function(element){
    var index = this.selectionSet.indexOf(element)
    if (this.onFirstSelect && !this.previouslySelected[index]){
      this.onFirstSelect(element, index)
      this.previouslySelected[index] = true;
    }
  	if (this.onSelect)
      try{
  	    this.onSelect(element, index)
      } catch (e) {}
	},
	selectIndex: function(index){
		this.select(this.selectionSet[index])
	},  
	nextSelectItem: function(index){
    var index = this.selectionSet.indexOf(this.selected)
    if (index + 1 >= this.selectionSet.length)
      return this.selectionSet[index - 1];
    else
      return this.selectionSet[index + 1];	  
	},
	selectNext: function(){
    var index = this.selectionSet.indexOf(this.selected)
    if (index >= this.selectionSet.length)
      this.selectIndex(index - 1)
    else
      this.selectIndex(index + 1)
	},
	click: function(event,target) {
		this.select(target);
	},
	add: function(item){
	//	this.selectionSet.push(item)
	  if (item.constructur == Array)
	    item.each(function(e){
	      	Event.observe(e, "click", new Rico.EventWrapper(this.clickHandler,item).wrapper);
	    }.bind(this))
	  else
		  Event.observe(item, "click", new Rico.EventWrapper(this.clickHandler,item).wrapper);
	},
	remove: function(item){
	  this.selectionSet = this.selectionSet.without(item)
			//Todo: need to cleanup all events on item - need to keep track of eventwrappers
	},
	removeAll: function(){
		
	}
 }

Rico.HoverSet = Class.create();
Rico.HoverSet.prototype = {
    initialize: function(hoverSet, options){
      options = options || [];
      this.hoverSet = hoverSet;
      this.hoverClassName = options.hoverClass || "hover";
      this.hoverNodes = options.hoverNodes || function(e){return [e]};
  		this.listenerHover    = this._onHover.bind(this)
      this.listenerEndHover = this._onUnHover.bind(this)
      
  	  this.hoverSet.each((function(e) {Event.observe(e, "mousemove", new Rico.EventWrapper(this.listenerHover,e).wrapper);}).bind(this))
  	  this.hoverSet.each((function(e) {Event.observe(e, "mouseout", new Rico.EventWrapper(this.listenerEndHover,e).wrapper);}).bind(this))	
  	},
   	_onHover: function(event,target) {
   	  this.hover(target);
   	},	
   	_onUnHover: function(event,target) {
   	  this.unHover(target);
   	},
   	hover: function(target) {
   	  this.hoverNodes(target).each((function(t){Element.classNames(t).add(this.hoverClassName)}).bind(this));
   	},	
   	unHover: function(target) {
   	  this.hoverNodes(target).each((function(t){Element.classNames(t).remove(this.hoverClassName)}).bind(this));
   	},
		add: function(item){
  	  Event.observe(item, "mousemove", new Rico.EventWrapper(this.listenerHover,item).wrapper);
  	  Event.observe(item, "mouseout", new Rico.EventWrapper(this.listenerEndHover,item).wrapper);
		},
		remove: function(item){
			//Todo: need to cleanup all events on item - need to keep terack of eventwrappers
			//stopObserving
			//Event.stopObserving(e, "mousemove", new Rico.EventWrapper(this.listenerHover,e).wrapper);}).bind(this))
  	  //this.hoverSet.each((function(e) {Event.observe(e, "mouseout", new Rico.EventWrapper(this.listenerEndHover,e).wrapper);}).bind(this))
			//hoverSet
		},
		removeAll: function(item){
		}
}
 

Rico.Hover = {
  groups: {},
  clearCurrent: function(group) {
    var last_hover = Rico.Hover.groups[group];
    if(!last_hover) return  
    clearTimeout(last_hover[0])
    last_hover[1].end()
    Rico.Hover.groups[group] = null;
  }, 
  end: function(group) {
  	Rico.Hover.groups[group][1].end();
  },
  endWith: function(hover, group) {
  	var timer = setTimeout('Rico.Hover.end("'+ group + '")', hover.exitDelay)
    Rico.Hover.groups[group] = [timer, hover]
  }
}

Rico.HoverDisplay = Class.create();
Rico.HoverDisplay.prototype = {
  initialize: function(element, options) {
  	this.element = element;
  	this.options = options || {};
  	this.group = this.options.group;
  	this.exitDelay = this.options.delay || 1000;
  },
  begin: function() {
    Rico.Hover.clearCurrent(this.group)
		Element.show(this.element)
  },
  end: function(delay) {
    if(delay)
       	Rico.Hover.endWith(this, this.group);
    else 
		  Element.hide(this.element)		  
  }
}


////////////////////////////////////////////////////
// start ricoDragDrop.js
/**
  *
  *  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.
  **/
//-------------------- ricoDragAndDrop.js
Rico.DragAndDrop = Class.create();

Rico.DragAndDrop.prototype = {

   initialize: function() {
      this.dropZones                = new Array();
      this.draggables               = new Array();
      this.currentDragObjects       = new Array();
      this.dragElement              = null;
      this.lastSelectedDraggable    = null;
      this.currentDragObjectVisible = false;
      this.interestedInMotionEvents = false;
      this._mouseDown = this._mouseDownHandler.bindAsEventListener(this);
      this._mouseMove = this._mouseMoveHandler.bindAsEventListener(this);
      this._mouseUp = this._mouseUpHandler.bindAsEventListener(this);
   },

   registerDropZone: function(aDropZone) {
      this.dropZones[ this.dropZones.length ] = aDropZone;
   },

   deregisterDropZone: function(aDropZone) {
      var newDropZones = new Array();
      var j = 0;
      for ( var i = 0 ; i < this.dropZones.length ; i++ ) {
         if ( this.dropZones[i] != aDropZone )
            newDropZones[j++] = this.dropZones[i];
      }

      this.dropZones = newDropZones;
   },

   clearDropZones: function() {
      this.dropZones = new Array();
   },

   registerDraggable: function( aDraggable ) {
      this.draggables[ this.draggables.length ] = aDraggable;
      this._addMouseDownHandler( aDraggable );
   },

   clearSelection: function() {
      for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
         this.currentDragObjects[i].deselect();
      this.currentDragObjects = new Array();
      this.lastSelectedDraggable = null;
   },

   hasSelection: function() {
      return this.currentDragObjects.length > 0;
   },

   setStartDragFromElement: function( e, mouseDownElement ) {
      this.origPos = RicoUtil.toDocumentPosition(mouseDownElement);
      this.startx = e.screenX - this.origPos.x
      this.starty = e.screenY - this.origPos.y
      //this.startComponentX = e.layerX ? e.layerX : e.offsetX;
      //this.startComponentY = e.layerY ? e.layerY : e.offsetY;
      //this.adjustedForDraggableSize = false;

      this.interestedInMotionEvents = this.hasSelection();
      this._terminateEvent(e);
   },

   updateSelection: function( draggable, extendSelection ) {
      if ( ! extendSelection )
         this.clearSelection();

      if ( draggable.isSelected() ) {
         this.currentDragObjects.removeItem(draggable);
         draggable.deselect();
         if ( draggable == this.lastSelectedDraggable )
            this.lastSelectedDraggable = null;
      }
      else {
         this.currentDragObjects[ this.currentDragObjects.length ] = draggable;
         draggable.select();
         this.lastSelectedDraggable = draggable;
      }
   },

   _mouseDownHandler: function(e) {
      if ( arguments.length == 0 )
         e = event;

      // if not button 1 ignore it...
      var nsEvent = e.which != undefined;
      if ( (nsEvent && e.which != 1) || (!nsEvent && e.button != 1))
         return;

      var eventTarget      = e.target ? e.target : e.srcElement;
      var draggableObject  = eventTarget.draggable;

      var candidate = eventTarget;
      while (draggableObject == null && candidate.parentNode) {
         candidate = candidate.parentNode;
         draggableObject = candidate.draggable;
      }
   
      if ( draggableObject == null )
         return;

      this.updateSelection( draggableObject, e.ctrlKey );

      // clear the drop zones postion cache...
      if ( this.hasSelection() )
         for ( var i = 0 ; i < this.dropZones.length ; i++ )
            this.dropZones[i].clearPositionCache();

      this.setStartDragFromElement( e, draggableObject.getMouseDownHTMLElement() );
   },


   _mouseMoveHandler: function(e) {
      var nsEvent = e.which != undefined;
      if ( !this.interestedInMotionEvents ) {
         //this._terminateEvent(e);
         return;
      }

      if ( ! this.hasSelection() )
         return;

      if ( ! this.currentDragObjectVisible )
         this._startDrag(e);

      if ( !this.activatedDropZones )
         this._activateRegisteredDropZones();

      //if ( !this.adjustedForDraggableSize )
      //   this._adjustForDraggableSize(e);

      this._updateDraggableLocation(e);
      this._updateDropZonesHover(e);

      this._terminateEvent(e);
   },

   _makeDraggableObjectVisible: function(e)
   {
      if ( !this.hasSelection() )
         return;

      var dragElement;
      if ( this.currentDragObjects.length > 1 )
         dragElement = this.currentDragObjects[0].getMultiObjectDragGUI(this.currentDragObjects);
      else
         dragElement = this.currentDragObjects[0].getSingleObjectDragGUI();

      // go ahead and absolute position it...
      if ( RicoUtil.getElementsComputedStyle(dragElement, "position")  != "absolute" )
/*      if (Element.getStyle(dragElement,'position')=='absolute')*/
         dragElement.style.position = "absolute";

      // need to parent him into the document...
      if ( dragElement.parentNode == null || dragElement.parentNode.nodeType == 11 )
         document.body.appendChild(dragElement);

      this.dragElement = dragElement;
      this._updateDraggableLocation(e);

      this.currentDragObjectVisible = true;
   },

   /**
   _adjustForDraggableSize: function(e) {
      var dragElementWidth  = this.dragElement.offsetWidth;
      var dragElementHeight = this.dragElement.offsetHeight;
      if ( this.startComponentX > dragElementWidth )
         this.startx -= this.startComponentX - dragElementWidth + 2;
      if ( e.offsetY ) {
         if ( this.startComponentY > dragElementHeight )
            this.starty -= this.startComponentY - dragElementHeight + 2;
      }
      this.adjustedForDraggableSize = true;
   },
   **/

   _leftOffset: function(e) {
	   return e.offsetX ? document.body.scrollLeft : 0
	},

   _topOffset: function(e) {
	   return e.offsetY ? document.body.scrollTop:0
	},

		
   _updateDraggableLocation: function(e) {
      var dragObjectStyle = this.dragElement.style;
      dragObjectStyle.left = (e.screenX + this._leftOffset(e) - this.startx) + "px"
      dragObjectStyle.top  = (e.screenY + this._topOffset(e) - this.starty) + "px";
   },

   _updateDropZonesHover: function(e) {
      var n = this.dropZones.length;
      for ( var i = 0 ; i < n ; i++ ) {
         if ( ! this._mousePointInDropZone( e, this.dropZones[i] ) )
            this.dropZones[i].hideHover();
      }

      for ( var i = 0 ; i < n ; i++ ) {
         if ( this._mousePointInDropZone( e, this.dropZones[i] ) ) {
            if ( this.dropZones[i].canAccept(this.currentDragObjects) )
               this.dropZones[i].showHover();
         }
      }
   },

   _startDrag: function(e) {
      for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
         this.currentDragObjects[i].startDrag();

      this._makeDraggableObjectVisible(e);
   },

   _mouseUpHandler: function(e) {
      if ( ! this.hasSelection() )
         return;

      var nsEvent = e.which != undefined;
      if ( (nsEvent && e.which != 1) || (!nsEvent && e.button != 1))
         return;

      this.interestedInMotionEvents = false;

      if ( this.dragElement == null ) {
         this._terminateEvent(e);
         return;
      }

      if ( this._placeDraggableInDropZone(e) )
         this._completeDropOperation(e);
      else {
         this._terminateEvent(e);
         Rico.animate(new Rico.Effect.Position( this.dragElement, this.origPos.x, this.origPos.y),
                      {duration: 200,
                       steps: 20,
                       onFinish : this._doCancelDragProcessing.bind(this) } );
      }

     Event.stopObserving(document.body, "mousemove", this._mouseMove);
     Event.stopObserving(document.body, "mouseup",  this._mouseUp);
   },

   _retTrue: function () {
      return true;
   },

   _completeDropOperation: function(e) {
      if ( this.dragElement != this.currentDragObjects[0].getMouseDownHTMLElement() ) {
         if ( this.dragElement.parentNode != null )
            this.dragElement.parentNode.removeChild(this.dragElement);
      }

      this._deactivateRegisteredDropZones();
      this._endDrag();
      this.clearSelection();
      this.dragElement = null;
      this.currentDragObjectVisible = false;
      this._terminateEvent(e);
   },

   _doCancelDragProcessing: function() {
      this._cancelDrag();

        if ( this.dragElement != this.currentDragObjects[0].getMouseDownHTMLElement() && this.dragElement)
           if ( this.dragElement.parentNode != null )
              this.dragElement.parentNode.removeChild(this.dragElement);


      this._deactivateRegisteredDropZones();
      this.dragElement = null;
      this.currentDragObjectVisible = false;
   },

   _placeDraggableInDropZone: function(e) {
      var foundDropZone = false;
      var n = this.dropZones.length;
      for ( var i = 0 ; i < n ; i++ ) {
         if ( this._mousePointInDropZone( e, this.dropZones[i] ) ) {
            if ( this.dropZones[i].canAccept(this.currentDragObjects) ) {
               this.dropZones[i].hideHover();
               this.dropZones[i].accept(this.currentDragObjects);
               foundDropZone = true;
               break;
            }
         }
      }

      return foundDropZone;
   },

   _cancelDrag: function() {
      for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
         this.currentDragObjects[i].cancelDrag();
   },

   _endDrag: function() {
      for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
         this.currentDragObjects[i].endDrag();
   },

   _mousePointInDropZone: function( e, dropZone ) {

      var absoluteRect = dropZone.getAbsoluteRect();

      return e.clientX  > absoluteRect.left + this._leftOffset(e) &&
             e.clientX  < absoluteRect.right + this._leftOffset(e) &&
             e.clientY  > absoluteRect.top + this._topOffset(e)   &&
             e.clientY  < absoluteRect.bottom + this._topOffset(e);
   },

   _addMouseDownHandler: function( aDraggable )
   {
       htmlElement  = aDraggable.getMouseDownHTMLElement();
      if ( htmlElement  != null ) { 
         htmlElement.draggable = aDraggable;
         Event.observe(htmlElement , "mousedown", this._onmousedown.bindAsEventListener(this));
         Event.observe(htmlElement, "mousedown", this._mouseDown);
      }
   },

   _activateRegisteredDropZones: function() {
      var n = this.dropZones.length;
      for ( var i = 0 ; i < n ; i++ ) {
         var dropZone = this.dropZones[i];
         if ( dropZone.canAccept(this.currentDragObjects) )
            dropZone.activate();
      }

      this.activatedDropZones = true;
   },

   _deactivateRegisteredDropZones: function() {
      var n = this.dropZones.length;
      for ( var i = 0 ; i < n ; i++ )
         this.dropZones[i].deactivate();
      this.activatedDropZones = false;
   },

   _onmousedown: function () {
     Event.observe(document.body, "mousemove", this._mouseMove);
     Event.observe(document.body, "mouseup",  this._mouseUp);
   },

   _terminateEvent: function(e) {
      if ( e.stopPropagation != undefined )
         e.stopPropagation();
      else if ( e.cancelBubble != undefined )
         e.cancelBubble = true;

      if ( e.preventDefault != undefined )
         e.preventDefault();
      else
         e.returnValue = false;
   },


	   initializeEventHandlers: function() {
	      if ( typeof document.implementation != "undefined" &&
	         document.implementation.hasFeature("HTML",   "1.0") &&
	         document.implementation.hasFeature("Events", "2.0") &&
	         document.implementation.hasFeature("CSS",    "2.0") ) {
	         document.addEventListener("mouseup",   this._mouseUpHandler.bindAsEventListener(this),  false);
	         document.addEventListener("mousemove", this._mouseMoveHandler.bindAsEventListener(this), false);
	      }
	      else {
	         document.attachEvent( "onmouseup",   this._mouseUpHandler.bindAsEventListener(this) );
	         document.attachEvent( "onmousemove", this._mouseMoveHandler.bindAsEventListener(this) );
	      }
	   }
	}

	var dndMgr = new Rico.DragAndDrop();
	dndMgr.initializeEventHandlers();


//-------------------- ricoDraggable.js
Rico.Draggable = Class.create();

Rico.Draggable.prototype = {

   initialize: function( type, htmlElement ) {
      this.type          = type;
      this.htmlElement   = $(htmlElement);
      this.selected      = false;
   },

   /**
    *   Returns the HTML element that should have a mouse down event
    *   added to it in order to initiate a drag operation
    *
    **/
   getMouseDownHTMLElement: function() {
      return this.htmlElement;
   },

   select: function() {
      this.selected = true;

      if ( this.showingSelected )
         return;

      var htmlElement = this.getMouseDownHTMLElement();

      var color = Rico.Color.createColorFromBackground(htmlElement);
      color.isBright() ? color.darken(0.033) : color.brighten(0.033);

      this.saveBackground = RicoUtil.getElementsComputedStyle(htmlElement, "backgroundColor", "background-color");
//      this.saveBackground = Element.getStyle(htmlElement,'backgroundColor') || Element.getStyle(htmlElement,'background-color')
      htmlElement.style.backgroundColor = color.asHex();
      this.showingSelected = true;
   },

   deselect: function() {
      this.selected = false;
      if ( !this.showingSelected )
         return;

      var htmlElement = this.getMouseDownHTMLElement();

      htmlElement.style.backgroundColor = this.saveBackground;
      this.showingSelected = false;
   },

   isSelected: function() {
      return this.selected;
   },

   startDrag: function() {
   },

   cancelDrag: function() {
   },

   endDrag: function() {
   },

   getSingleObjectDragGUI: function() {
      return this.htmlElement;
   },

   getMultiObjectDragGUI: function( draggables ) {
      return this.htmlElement;
   },

   getDroppedGUI: function() {
      return this.htmlElement;
   },

   toString: function() {
      return this.type + ":" + this.htmlElement + ":";
   }

}


//-------------------- ricoDropzone.js
Rico.Dropzone = Class.create();

Rico.Dropzone.prototype = {

   initialize: function( htmlElement ) {
      this.htmlElement  = $(htmlElement);
      this.absoluteRect = null;
   },

   getHTMLElement: function() {
      return this.htmlElement;
   },

   clearPositionCache: function() {
      this.absoluteRect = null;
   },

   getAbsoluteRect: function() {
      if ( this.absoluteRect == null ) {
         var htmlElement = this.getHTMLElement();
         var pos = RicoUtil.toViewportPosition(htmlElement);

         this.absoluteRect = {
            top:    pos.y,
            left:   pos.x,
            bottom: pos.y + htmlElement.offsetHeight,
            right:  pos.x + htmlElement.offsetWidth
         };
      }
      return this.absoluteRect;
   },

   activate: function() {
      var htmlElement = this.getHTMLElement();
      if (htmlElement == null  || this.showingActive)
         return;

      this.showingActive = true;
      this.saveBackgroundColor = htmlElement.style.backgroundColor;

      var fallbackColor = "#ffea84";
      var currentColor = Rico.Color.createColorFromBackground(htmlElement);
      if ( currentColor == null )
         htmlElement.style.backgroundColor = fallbackColor;
      else {
         currentColor.isBright() ? currentColor.darken(0.2) : currentColor.brighten(0.2);
         htmlElement.style.backgroundColor = currentColor.asHex();
      }
   },

   deactivate: function() {
      var htmlElement = this.getHTMLElement();
      if (htmlElement == null || !this.showingActive)
         return;

      htmlElement.style.backgroundColor = this.saveBackgroundColor;
      this.showingActive = false;
      this.saveBackgroundColor = null;
   },

   showHover: function() {
      var htmlElement = this.getHTMLElement();
      if ( htmlElement == null || this.showingHover )
         return;

      this.saveBorderWidth = htmlElement.style.borderWidth;
      this.saveBorderStyle = htmlElement.style.borderStyle;
      this.saveBorderColor = htmlElement.style.borderColor;

      this.showingHover = true;
      htmlElement.style.borderWidth = "1px";
      htmlElement.style.borderStyle = "solid";
      //htmlElement.style.borderColor = "#ff9900";
      htmlElement.style.borderColor = "#ffff00";
   },

   hideHover: function() {
      var htmlElement = this.getHTMLElement();
      if ( htmlElement == null || !this.showingHover )
         return;

      htmlElement.style.borderWidth = this.saveBorderWidth;
      htmlElement.style.borderStyle = this.saveBorderStyle;
      htmlElement.style.borderColor = this.saveBorderColor;
      this.showingHover = false;
   },

   canAccept: function(draggableObjects) {
      return true;
   },

   accept: function(draggableObjects) {
      var htmlElement = this.getHTMLElement();
      if ( htmlElement == null )
         return;

      n = draggableObjects.length;
      for ( var i = 0 ; i < n ; i++ )
      {
         var theGUI = draggableObjects[i].getDroppedGUI();
/*         if (Element.getStyle(theGUI,'position')=='absolute')*/
         if ( RicoUtil.getElementsComputedStyle( theGUI, "position" ) == "absolute" )
         {
            theGUI.style.position = "static";
            theGUI.style.top = "";
            theGUI.style.top = "";
         }
         htmlElement.appendChild(theGUI);
      }
   }
}

RicoUtil = Object.extend(RicoUtil, {
   getElementsComputedStyle: function ( htmlElement, cssProperty, mozillaEquivalentCSS) {
      if ( arguments.length == 2 )
         mozillaEquivalentCSS = cssProperty;

      var el = $(htmlElement);
      if ( el.currentStyle )
         return el.currentStyle[cssProperty];
      else
         return document.defaultView.getComputedStyle(el, null).getPropertyValue(mozillaEquivalentCSS);
   },

   createXmlDocument : function() {
      if (document.implementation && document.implementation.createDocument) {
         var doc = document.implementation.createDocument("", "", null);

         if (doc.readyState == null) {
            doc.readyState = 1;
            doc.addEventListener("load", function () {
               doc.readyState = 4;
               if (typeof doc.onreadystatechange == "function")
                  doc.onreadystatechange();
            }, false);
         }

         return doc;
      }

      if (window.ActiveXObject)
          return Try.these(
            function() { return new ActiveXObject('MSXML2.DomDocument')   },
            function() { return new ActiveXObject('Microsoft.DomDocument')},
            function() { return new ActiveXObject('MSXML.DomDocument')    },
            function() { return new ActiveXObject('MSXML3.DomDocument')   }
          ) || false;

      return null;
   },

   getContentAsString: function( parentNode ) {
      return parentNode.xml != undefined ? 
         this._getContentAsStringIE(parentNode) :
         this._getContentAsStringMozilla(parentNode);
   },

  _getContentAsStringIE: function(parentNode) {
     var contentStr = "";
     for ( var i = 0 ; i < parentNode.childNodes.length ; i++ ) {
         var n = parentNode.childNodes[i];
         if (n.nodeType == 4) {
             contentStr += n.nodeValue;
         }
         else {
           contentStr += n.xml;
       }
     }
     return contentStr;
  },

  _getContentAsStringMozilla: function(parentNode) {
     var xmlSerializer = new XMLSerializer();
     var contentStr = "";
     for ( var i = 0 ; i < parentNode.childNodes.length ; i++ ) {
          var n = parentNode.childNodes[i];
          if (n.nodeType == 4) { // CDATA node
              contentStr += n.nodeValue;
          }
          else {
            contentStr += xmlSerializer.serializeToString(n);
        }
     }
     return contentStr;
  },

   toViewportPosition: function(element) {
      return this._toAbsolute(element,true);
   },

   toDocumentPosition: function(element) {
      return this._toAbsolute(element,false);
   },

   /**
    *  Compute the elements position in terms of the window viewport
    *  so that it can be compared to the position of the mouse (dnd)
    *  This is additions of all the offsetTop,offsetLeft values up the
    *  offsetParent hierarchy, ...taking into account any scrollTop,
    *  scrollLeft values along the way...
    *
    * IE has a bug reporting a correct offsetLeft of elements within a
    * a relatively positioned parent!!!
    **/
   _toAbsolute: function(element,accountForDocScroll) {

      if ( navigator.userAgent.toLowerCase().indexOf("msie") == -1 )
         return this._toAbsoluteMozilla(element,accountForDocScroll);

      var x = 0;
      var y = 0;
      var parent = element;
      while ( parent ) {

         var borderXOffset = 0;
         var borderYOffset = 0;
         if ( parent != element ) {
            var borderXOffset = parseInt(this.getElementsComputedStyle(parent, "borderLeftWidth" ));
            var borderYOffset = parseInt(this.getElementsComputedStyle(parent, "borderTopWidth" ));
            borderXOffset = isNaN(borderXOffset) ? 0 : borderXOffset;
            borderYOffset = isNaN(borderYOffset) ? 0 : borderYOffset;
         }

         x += parent.offsetLeft - parent.scrollLeft + borderXOffset;
         y += parent.offsetTop - parent.scrollTop + borderYOffset;
         parent = parent.offsetParent;
      }

      if ( accountForDocScroll ) {
         x -= this.docScrollLeft();
         y -= this.docScrollTop();
      }

      return { x:x, y:y };
   },

   /**
    *  Mozilla did not report all of the parents up the hierarchy via the
    *  offsetParent property that IE did.  So for the calculation of the
    *  offsets we use the offsetParent property, but for the calculation of
    *  the scrollTop/scrollLeft adjustments we navigate up via the parentNode
    *  property instead so as to get the scroll offsets...
    *
    **/
   _toAbsoluteMozilla: function(element,accountForDocScroll) {
      var x = 0;
      var y = 0;
      var parent = element;
      while ( parent ) {
         x += parent.offsetLeft;
         y += parent.offsetTop;
         parent = parent.offsetParent;
      }

      parent = element;
      while ( parent &&
              parent != document.body &&
              parent != document.documentElement ) {
         if ( parent.scrollLeft  )
            x -= parent.scrollLeft;
         if ( parent.scrollTop )
            y -= parent.scrollTop;
         parent = parent.parentNode;
      }

      if ( accountForDocScroll ) {
         x -= this.docScrollLeft();
         y -= this.docScrollTop();
      }

      return { x:x, y:y };
   },

   docScrollLeft: function() {
      if ( window.pageXOffset )
         return window.pageXOffset;
      else if ( document.documentElement && document.documentElement.scrollLeft )
         return document.documentElement.scrollLeft;
      else if ( document.body )
         return document.body.scrollLeft;
      else
         return 0;
   },

   docScrollTop: function() {
      if ( window.pageYOffset )
         return window.pageYOffset;
      else if ( document.documentElement && document.documentElement.scrollTop )
         return document.documentElement.scrollTop;
      else if ( document.body )
         return document.body.scrollTop;
      else
         return 0;
   }
});

Rico.includeLoaded('ricoDragDrop.js');



////////////////////////////////////////////////////
// start ricoComponents.js
/**
  *  (c) 2005-2007 Richard Cowin (http://openrico.org)
  *  (c) 2005-2007 Matt Brown (http://dowdybrown.com)
  *
  *  Rico is 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
  **/
  

Rico.ContentTransitionBase = function() {}
Rico.ContentTransitionBase.prototype = {
	initialize: function(titles, contents, options) { 
    if (typeof titles == 'string')
      titles = $$(titles)
    if (typeof contents == 'string')
      contents = $$(contents)
	  
	  this.titles = titles;
	  this.contents = contents;
		this.options = Object.extend({
			duration:200, 
			steps:8,
			rate:Rico.Effect.easeIn
	  }, options || {});
	  this.hoverSet = new Rico.HoverSet(titles, options);
		contents.each(function(p){ if (p) Element.hide(p)})
	  this.selectionSet = new Rico.SelectionSet(titles, Object.extend(this.options, {onSelect: this.select.bind(this)}));
		if (this.initContent) this.initContent();
	},
	reset: function(){
	  this.selectionSet.reset();
	},
	select: function(title) {
	  if ( this.selected == this.contentOf(title)) return
		var panel = this.contentOf(title); 
		if (this.transition){
			if (this.selected){
			  var effect = this.transition(panel)
			  if (effect) Rico.animate(effect, this.options)
      }
			else
				Element.show(panel);
		}else{
			if (this.selected)
				Element.hide(this.selected)
			Element.show(panel);
		}
		this.selected = panel;
	},
	add: function(title, content){
		this.titles.push(title);
		this.contents.push(content);
		this.hoverSet.add(title);
		this.selectionSet.add(title);	
		this.selectionSet.select(title);
	},
	remove: function(title){},
	removeAll: function(){
		this.hoverSet.removeAll();
		this.selectionSet.removeAll();
	},
	openByIndex: function(index){this.selectionSet.selectIndex(index)},
	contentOf: function(title){ return this.contents[this.titles.indexOf(title)]}
}

Rico.ContentTransition = Class.create();
Rico.ContentTransition.prototype = Object.extend(new Rico.ContentTransitionBase(),{});

Rico.SlidingPanel = Class.create();
Rico.SlidingPanel.prototype = {
	initialize: function(panel) {
		this.panel = panel;
		this.options = arguments[1] || {};
		this.closed = true;
		this.showing = false
		this.openEffect = this.options.openEffect;
		this.closeEffect = this.options.closeEffect;
		this.animator = new Rico.Effect.Animator();
		Element.makeClipping(this.panel)
	},
	toggle: function () {
		if(!this.showing){
			this.open();
		} else { 
			this.close();
    }
	},
	open: function () {
	  if (this.closed){
	    this.showing = true;
		  Element.show(this.panel);
  		this.options.disabler.disableNative();
    }
		/*this.animator.stop();*/
		this.animator.play(this.openEffect,
		 									{ onFinish:function(){ Element.undoClipping($(this.panel))}.bind(this),
												rate:Rico.Effect.easeIn});
	},
 	close: function () {
		Element.makeClipping(this.panel)
		this.animator.stop();
		this.showing = false;
		this.animator.play(this.closeEffect,
	                     { onFinish:function(){  Element.hide(this.panel); 	
																							this.options.disabler.enableNative()}.bind(this),	
												rate:Rico.Effect.easeOut});
	}
}


//-------------------------------------------
// Example components
//-------------------------------------------

Rico.Accordion = Class.create();
Rico.Accordion.prototype = Object.extend(new Rico.ContentTransitionBase(), {
  initContent: function() { 
		this.selected.style.height = this.options.panelHeight + "px";
	},
  transition: function(p){ 
    if (!this.options.noAnimate)
		  return new Rico.AccordionEffect(this.selected, p, this.options.panelHeight);
    else{
      p.style.height = this.options.panelHeight + "px";
      if (this.selected) Element.hide(this.selected);
  		Element.show(p);
    }
	}
})


Rico.TabbedPanel = Class.create();
Rico.TabbedPanel.prototype = Object.extend(new Rico.ContentTransitionBase(), {
  initContent: function() { 
		if (false && (this.options.panelHeight=='auto' || this.options.panelWidth=='auto')) {
		  // 'auto' is not working yet
		  var maxwi=0, maxht=0;
		  for (var i=0; i<this.contents.length; i++) {
		    var d=Element.getDimensions(this.contents[i]);
		    maxwi=Math.max(maxwi,d.width);
		    maxht=Math.max(maxht,d.height);
		  }
		  //alert('maxwi='+maxwi+' maxht='+maxht);
		  if (this.options.panelWidth=='auto') this.options.panelWidth=maxwi;
		  if (this.options.panelHeight=='auto') this.options.panelHeight=maxht;
		}
	  if (typeof this.options.panelWidth=='number') this.options.panelWidth+="px";
	  if (typeof this.options.panelHeight=='number') this.options.panelHeight+="px";
    if (Rico.Corner) {
      this.options.color='transparent';
      this.options.corners='top';
      for (var i=0; i<this.titles.length; i++)
        if (this.titles[i]) {
          if (this.options.panelHdrWidth) this.titles[i].style.width=this.options.panelHdrWidth;
          Rico.Corner.round(this.titles[i], this.options);
        }
    }
		this.transition(this.selected);
	},
  transition: function(p){ 
    if (this.selected) Element.hide(this.selected);
		Element.show(p);
    if (this.options.panelHeight) p.style.height = this.options.panelHeight;
    if (this.options.panelWidth) p.style.width = this.options.panelWidth;
	}
})


Rico.SlidingPanel.top = function(panel, innerPanel){
	var options = Object.extend({
		disabler: Rico.Controls.defaultDisabler
  }, arguments[2] || {});
	var height = options.height || Element.getDimensions(innerPanel)[1] || innerPanel.offsetHeight;
	var top = options.top || Position.positionedOffset(panel)[1];
	options.openEffect = new Rico.Effect.SizeFromTop(panel, innerPanel, top, height, {baseHeight:height});
	options.closeEffect = new Rico.Effect.SizeFromTop(panel, innerPanel, top, 1, {baseHeight:height});
  panel.style.height = "0px";
	innerPanel.style.top = -height + "px";	
	return new Rico.SlidingPanel(panel, options);
}

Rico.SlidingPanel.bottom = function(panel){
	var options = Object.extend({
		disabler: Rico.Controls.blankDisabler
  }, arguments[1] || {});
	var height = options.height || Element.getDimensions(panel).height;
	var top = Position.positionedOffset(panel)[1];
	options.openEffect = new Rico.Effect.SizeFromBottom(panel, top - height, height);
	options.closeEffect = new Rico.Effect.SizeFromBottom(panel, top, 1);
	return new Rico.SlidingPanel(panel, options); 
}

Rico.includeLoaded('ricoComponents.js');


////////////////////////////////////////////////////
// start demosPage.js

   var saveHeight;
   var showing = true;

   function toggleSlide() {
      if ( showing )
         { slideMenuUp(); showing = false; }
      else
         { slideMenuDown(); showing = true; }
   }

   function slideMenuUp() {
      var menu = $('demosMenu');
      saveHeight = menu.offsetHeight;

      menu.style.overflow = "hidden";
      new Rico.Effect.Size( menu, null, 1, 120, 8 );

      $('demoPanelLink').innerHTML = "Show demo panel";
   }

   function slideMenuDown() {
      var menu = $('demosMenu');
      new Rico.Effect.Size( menu, null, saveHeight, 120, 8, {complete:function() { $(menu).style.overflow = "visible"; }} );
      $('demoPanelLink').innerHTML = "Hide demo panel";
   }


Event.observe(window, 'load', function(){ 
   Rico.Corner.round( 'ajaxDemos',     {corners:'tl br',bgColor:'#adba8c'} );
   Rico.Corner.round( 'dragdropDemos', {corners:'tl br',bgColor:'#adba8c'} );
   Rico.Corner.round( 'cinemaDemos',   {corners:'tl br',bgColor:'#adba8c'} );
   Rico.Corner.round( 'extraDemos',    {corners:'tl br',bgColor:'#adba8c'} );
})

