var Success_String = " ✔";
var Failure_String = " ✘";
var Rightward_Arrow = "&#x2192;";

/* This library requires prototype. */

/* Extend the Element constructor in prototype to append elements or text nodes as children.
 * Usage: new Element ("div", {'class': "Shiny"}, new Array ("This is shiny", new Element ("input", {name: "Dull"}) ) );
 * Requires Prototype v1.6 or better.  Works recursively.  Could be a nasty hack.  Use as your own risk.
 * Written by Jesse Lang, November 2008 */
(function() {
  var element = this.Element;
  this.Element = function(tagName, attributes, children) {
    attributes = attributes || { };
    children = children || new Array ();
    tagName = tagName.toLowerCase();
    var cache = Element.cache;
    if (Prototype.Browser.IE && attributes.name) {
      tagName = '<' + tagName + ' name="' + attributes.name + '">';
      delete attributes.name;
      var newElement = Element.writeAttribute(document.createElement (tagName), attributes);
      for(i = 0; i < children.length; i++) {
         if(typeof(children [i]) == "object") {
            newElement.appendChild (children [i]);
         } else if(typeof(children [i]) == "string") {
            newElement.appendChild (document.createTextNode(children [i]) );
         }
      }
      return newElement;
    }
    if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));
    var newElement = Element.writeAttribute(cache[tagName].cloneNode(false), attributes);
    for(var i = 0; i < children.length; i++) {
      if(typeof(children [i]) == "object") {
         newElement.appendChild (children [i]);
      } else if(typeof(children [i]) == "string") {
         newElement.appendChild (document.createTextNode(children [i]) );
      }
    }
    return newElement;
  };
  Object.extend(this.Element, element || { });
  if (element) this.Element.prototype = element.prototype;
}).call(window);

/* Source: http://github.com/kangax/protolicious/tree/master/event.simulate.js */
/**
* Event.simulate(@element, eventName[, options]) -> Element
*
* - @element: element to fire event on
* - eventName: name of event to fire (only MouseEvents and HTMLEvents interfaces are supported)
* - options: optional object to fine-tune event properties - pointerX, pointerY, ctrlKey, etc.
*
* $('foo').simulate('click'); // => fires "click" event on an element with id=foo
*
**/
(function(){

  var eventMatchers = {
    'HTMLEvents': /^(?:load|unload|abort|error|select|change|submit|reset|focus|blur|resize|scroll)$/,
    'MouseEvents': /^(?:click|mouse(?:down|up|over|move|out))$/
  }
  var defaultOptions = {
    pointerX: 0,
    pointerY: 0,
    button: 0,
    ctrlKey: false,
    altKey: false,
    shiftKey: false,
    metaKey: false,
    bubbles: true,
    cancelable: true
  }

  Event.simulate = function(element, eventName) {
    var options = Object.extend(defaultOptions, arguments[2] || { });
    var oEvent, eventType = null;

    element = $(element);

    for (var name in eventMatchers) {
      if (eventMatchers[name].test(eventName)) { eventType = name; break; }
    }

    if (!eventType)
      throw new SyntaxError('Only HTMLEvents and MouseEvents interfaces are supported');

    if (document.createEvent) {
      oEvent = document.createEvent(eventType);
      if (eventType == 'HTMLEvents') {
        oEvent.initEvent(eventName, options.bubbles, options.cancelable);
      }
      else {
        oEvent.initMouseEvent(eventName, options.bubbles, options.cancelable, document.defaultView,
          options.button, options.pointerX, options.pointerY, options.pointerX, options.pointerY,
          options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.button, element);
      }
      element.dispatchEvent(oEvent);
    }
    else {
      options.clientX = options.pointerX;
      options.clientY = options.pointerY;
      oEvent = Object.extend(document.createEventObject(), options);
      element.fireEvent('on' + eventName, oEvent);
    }
    return element;
  }

  Element.addMethods({ simulate: Event.simulate });
})();

var Common =
{
   /* I was going to use this to traverse XMLDocument elements, but prototype doesn't seem to work on those. */
   Get_Node_Value:   function (Element)
                     {
                        function Is_Text_Node (Element)
                        {
                           return Element.nodeType == 3;
                        }

                        return Element.childNodes.find (Is_Text_Node);
                     }
}

var Common_List =
{
   Blank:   function (Element)
            {
               function Remove_Non_Blank_Options (Element)
               {
                  if (!Element.hasClassName ("Blank") )
                  {
                     Element.remove ();
                  }
               }

               Element.descendants ().each (Remove_Non_Blank_Options);
               return Element;
            },

   Valid_Selection:  function (Element)
                     {
                        var Item = $(Element.options [Element.selectedIndex]);
                        return (!Item.hasClassName ("Blank") && !Item.disabled && Item.value != "");
                     }

}

Element.addMethods (Common);
Element.addMethods ("select", Common_List);
