// QL
if (typeof QL === 'undefined') {
    var QL = YAHOO;
}

// Dom
if (typeof $D === 'undefined') {
    var $D = QL.util.Dom;
}

// Event
if (typeof $E === 'undefined') {
    var $E = QL.util.Event;
}

// Selector
if (typeof $S === 'undefined') {
    var $S = QL.util.Selector;
}

// XMLHttpRequests (AJAX)
if (typeof $XHR === 'undefined') {
    var $XHR = QL.util.Connect;
}

// Cookie
if (typeof $C === 'undefined') {
    var $C = QL.util.Cookie;
}

// Create utilities namespace
QL.namespace('utilities');


// Prototypes
String.prototype.trim = function() {
    return this.replace(/^\s+|\s+$/g, '');
}

String.prototype.ltrim = function() {
    return this.replace(/^\s+/, '');
}

String.prototype.rtrim = function() {
    return this.replace(/\s+$/, '');
}

String.prototype.toTitleCase = function() {
    var pattern = /(\w)(\w*)/; // a letter, and then one, none or more letters

    var a = this.split(/\s+/g); // split the sentence into an array of words

    if ( a.length > 1 ) {
        for (i = 0 ; i < a.length ; i ++ ) {
            var parts = a[i].match(pattern); // just a temp variable to store the fragments in.
            if (parts != null) {
                var firstLetter = parts[1].toUpperCase();
                var restOfWord = parts[2].toLowerCase();
            }    

            a[i] = firstLetter + restOfWord; // re-assign it back to the array and move on
        }

        return a.join(' '); // join it back together
    } else {
        return a;
    }
}

String.prototype.formatCurrency = function(displayCents, dollarSign) {
 num = this.toString().replace(/\$|\,/g,'');
 numPrefix = (dollarSign == true) ? "" : "$";
 if(isNaN(num))
  num = "0";
  sign = (num == (num = Math.abs(num)));
  num = Math.floor(num*100+0.50000000001);
  cents = num%100;
  num = Math.floor(num/100).toString();
 if(cents<10)
  cents = "0" + cents;
 for (var i = 0; i < Math.floor((num.length-(1+i))/3); i++)
  num = num.substring(0,num.length-(4*i+3))+','+
  num.substring(num.length-(4*i+3));
 if (typeof displayCents != "undefined" && displayCents =="displayCents") {
  return (((sign)?'':'-') + numPrefix + num + '.' + cents);
 } else {
  return (((sign)?'':'-') + numPrefix + num); 
 } 
},


/**
 * Data Grid utilities.
 *
 * A collection of data grid utilities to make life easier.
 *
 * @namespace QL.utilities
 * @class DataGrid
 * @constructor
 */
QL.utilities.DataGrid = function()
{
    /**
     * Details for the decorative portion of the calculator
     *
     * @property decorativeDetails
     * @static
     * @type Object[]
     */
    var decorativeDetails = {
        // Decorative container
        decorativeContainer: document.createElement("TR")
    };

    return {

        /**
         * Decorates product collections when they are displayed in
         * order to keep from compromising markup
         *
         * @method productCollectionDecorator
         * @static
         * @param {Object} Table Element
         * @param {String} Class Name of Decorated Elements
         * @param {Array}  Array of Class Names of columns to be decorated
         */
        dataGridDecorator: function(datagrid, decorativeClassName, decorativeColumnClasses)
        {
            var decorativeContainer = decorativeDetails.decorativeContainer,
                decorativeElementClass = decorativeClassName,
                decorativeColumnClasses = decorativeColumnClasses;

            if(!datagrid) {
                return false;
            }

            // The element passed must be a table
            if (datagrid.nodeName.toUpperCase() != 'TABLE') {
                throw new Error("Specified parameter must be an HTML 'TABLE' element.");
            }

            // Store elements to be manipulated
            if (!datagrid.getElementsByTagName('THEAD')[0] || !datagrid.getElementsByTagName('TBODY')[0]) {
                throw new Error("Specified table must include THEAD and TBODY elements.");
            } else {
                var thead = datagrid.getElementsByTagName('THEAD')[0];
                var tbody = datagrid.getElementsByTagName('TBODY')[0];
            }

            // Insert our decorative TR container
            decorativeContainer.className = decorativeElementClass;

            var crown = thead.insertBefore(decorativeContainer.cloneNode(false), $D.getFirstChild(thead));
            var base = tbody.appendChild(decorativeContainer.cloneNode(false));

            var numberOfChildren = thead.getElementsByTagName("TH").length;

            // Grab each decorative column's target elements and decorate
            // Note that IE goes through some turmoil when innerHTML and THEAD meet up so
            // we're using standard node creation here
            for (var i = 0; i < numberOfChildren; i++) {

                // Grab last TD element in decorative column
                var decorativeElement = $D.getElementsByClassName(decorativeColumnClasses[i], 'TD', datagrid)[$D.getElementsByClassName(decorativeColumnClasses[i], 'TD', datagrid).length - 1];

                var TH = document.createElement('TH');
                var TD = document.createElement('TD');

                crown.appendChild(TH);
                base.appendChild(TD);

                // Add decorative markup if necessary
                if (decorativeElement) {
                    // Add class to decorative element
                    decorativeElement.className = decorativeColumnClasses[i]+'_bottom_cap';

                    // Insert additional markup in the thead and tbody of decorative columns
                    var SPAN = document.createElement('SPAN');
                    TH.className = decorativeColumnClasses[i];
                    TD.className = decorativeColumnClasses[i];
                    TH.appendChild(SPAN.cloneNode(false));
                    TD.appendChild(SPAN.cloneNode(false));
                }
            }
            return true;
        }
    };
}();


/**
 * Form utilities.
 *
 * A collection of form utilities to make life easier.
 *
 * @namespace QL.utilities
 * @class Form
 * @constructor
 */
QL.utilities.Form = function()
{

    return {

        /**
         * Ensures that specified element is a valid form element.
         *
         * @method  isValidFormElement
         * @param   {Object}    element
         * @return  {Boolean}
         */
         isValidFormElement: function(element)
        {
            if (typeof(element) !== 'object') {
                throw new TypeError('Specified element must be an object.');
            }

            var element = element.nodeName.toLowerCase();

            switch (element) {

                case 'input':
                case 'select':
                case 'textarea':
                    return true;

                default:
                    return false;
            }
        },

        /**
         * Finds all the child elements of a form.
         *
         * @method  getElements
         * @param   {Object}    form
         * @return  {Array}     validElements
         */
        getElements: function(form)
        {
            // Vars.
            var validElements = [];

            // Get form.
            var form = $D.get(form);

            if (!form || form.length === 0) return false;

            // Get all child elements.
            var elements = form.getElementsByTagName('*');

            if (elements.length === 0) return false;

            // Iterate elements. Add only valid form elements that are not
            // disabled or hidden.
            for (var i = 0; i < elements.length; i++) {
                if (this.isValidFormElement(elements[i])) {
                    if (!elements[i].getAttribute('disabled') && elements[i].getAttribute('type') !== 'hidden') {
                        validElements.push(elements[i]);
                    }
                }
            }

            return validElements;
        },

        /**
         * Gets the first element of a form.
         *
         * @param   {Object}    form
         * @return  {Array}     elements
         */
        getFirstElement: function(form)
        {
            // Get form elements.
            var elements = this.getElements(form);

            if (!elements || elements.length === 0) return false;

            // Return first element.
            return elements[0];
        },

        /**
         * Gives focus to the first element of a form.
         *
         * @param   {Object}    form
         */
        focusOnFirstElement: function(form)
        {
            // Get form elements.
            var element = this.getFirstElement(form);

            if (!element) return false;

            element.focus();
        },

        /**
         * Transforms a legend of a stated class into a newly specified
         * element with the same content as the legend and an optional
         * class.
         *
         * @param {String} targetClassName
         * @param {String} newElement
         * @param {String} newClassName
         * @static
         */
        transformLegends: function(targetClassName, newElement, newClassName)
        {
            // Grab the elements that we're looking for and place their
            // content into the new elements we're attaching to the document
            $D.batch($D.getElementsByClassName(targetClassName, 'LEGEND'), function(el) {
                var content = el.lastChild.nodeValue;
                var replacementElement = document.createElement(newElement);
                if(newClassName) {
                    $D.addClass(replacementElement, newClassName);
                }
                replacementElement.innerHTML = content;
                $D.insertAfter(replacementElement, el);
            });
        }

    };

}();

// Form
if (typeof $F === 'undefined') {
    var $F = QL.utilities.Form;
}

/**
 * Panel utilities.
 *
 * A collection of panel utilities to make life easier.
 *
 * @namespace QL.utilities
 * @class Panel
 * @constructor
 */
QL.utilities.Panel = function()
{
    /**
     * Details regarding tabview creation
     *
     * @property tabViewDetails
     * @static
     * @type Object[]
     */
    var tabViewDetails = {

        // Class of unordered list containing tabs
        tabContainerClass: 'yui-nav',

        // Class indicating an active tab
        activeTabClass: 'selected',

        // Prefix for panel elements
        panelPrefix: 'panel',

        // Prefix for tab elements
        tabPrefix: 'tab'

    };

    /**
     * Determines the default selected tab
     *
     * @method setActiveTab
     * @static
     */
    var setActiveTab = function(tabViewContainer)
    {
        var tabContainerClass = tabViewDetails.tabContainerClass,
            activeTabClass = tabViewDetails.activeTabClass,
            panelPrefix = tabViewDetails.panelPrefix,
            tabPrefix = tabViewDetails.tabPrefix;

        // Tab selection based on hash member of location object
        if(window.location.hash !== '') {
            if(window.location.hash.search(panelPrefix) != -1 && $D.get(window.location.hash.substring(1).replace(panelPrefix, tabPrefix))) {
                var activeTab = $D.get(window.location.hash.substring(1).replace(panelPrefix, tabPrefix));
                $D.addClass(activeTab, activeTabClass);

                // Scroll to top of page to give page reference
                scroll(0,0);

                return true;
            }
        }

        // Default selected tab if there is nothing/bad information in the hash member of the location object
        var activeTab = $D.getFirstChild($D.getElementsByClassName(tabContainerClass, 'UL', tabViewContainer)[0]);
        $D.addClass(activeTab, activeTabClass);
        return true;
    };

    return {
        /**
         * Enables tab view by wrapping the
         * YUI tabView constructor and automatically
         * setting the default active tab
         *
         * @method enableTabView
         * @static
         */
        enableTabView: function(tabViewContainer)
        {
            setActiveTab(tabViewContainer);
            var tabView = new QL.widget.TabView(tabViewContainer);
        }
    };
}();

/**
 * Window Object
 *
 * A collection of common window-related methods
 *
 * @namespace QL.utilities
 * @class Window
 * @constructor
 */
QL.utilities.Window = function()
{
    var defaultWindowName = 'WINDOW';

    var nameLimit = 1000;

    return {

        /**
         * Opens a new window
         *
         * Valid options are:
         * name, toolbar, location, directories, status,
         * menubar, scrollbars, resizable, width
         * height, top, left, and center
         *
         * Use 1/0 or 'yes'/'no' for most params
         *
         * @param {String} href
         * @param {Object} options
         * @static
         */
         open: function(href, options)
          {
              // Make sure we have the required parameters for the method
              if (!QL.lang.isString(href)) throw new TypeError('Specified parameter \'href\' must be a string.');

              try {
                  // If the window name is in the options object use it
                  var windowName = options.name;
                  var windowOptions = '';

                  // Logic to center the window
                  if (options.center || options.center === 1 || options.center === 'yes') {
                      var width  = options.width + 32; // Accomodate browser chrome
                      var height = options.height + 96;
                      options.top = (screen.height - height) / 2;
                      options.left = (screen.width - width) / 2;
                  }

                  // Build options arguments
                  for (option in options) {
                      windowOptions += option + '=' + options[option] + ',';
                  }

                  // Trim trailing commma
                  windowOptions = windowOptions.substring(0, (windowOptions.length - 1));
              } catch (e) {
                  var windowOptions = '',
                      windowName = defaultWindowName + Math.ceil(Math.random() * nameLimit);
              }

              // Open the new window
              var newWindow = window.open(href, windowName, windowOptions);

              newWindow.focus();
          },

        /**
         * Returns the querystring
         *
         * @static
         */
        getQueryString : function()
        {
            return window.location.search.substring(1);
        },

        /**
         * Takes a querystring and returns an object.
         * The string parameter is optional as the method
         * will otherwise grab the querystring of the window
         * it is called in.
         *
         * @param {String} optional querystring
         * @static
         */
        queryStringToObject : function(queryString)
        {
            var stringToManipulate;

            // Determine what querystring to manipulate
            if(!queryString) {
                stringToManipulate = this.getQueryString();
            } else {
                stringToManipulate = queryString;
            }

            // Split the string at the '&' and '=' characters to create the object
            if(stringToManipulate.length) {
                stringToManipulate = stringToManipulate.split('&');
                var querystringObject = {};
                for(var i = 0; i < stringToManipulate.length; i++) {
                    var key = stringToManipulate[i].split('=')[0];
                    var value = stringToManipulate[i].split('=')[1];
                    querystringObject[key] = value;
                }
            }

            return querystringObject;
        }
    };
}();

