(function($){
    
    // form placeholder text // PART ONE
    var _oldvalfn = $.fn.val;
    $.fn.val = function(value, suppressOnchange) {
        if (arguments.length == 0) {
            return _oldvalfn.apply(this, arguments);
        }

        if (value) value = new String(value);
        var prev = _oldvalfn.apply(this, []);
        var ret = _oldvalfn.apply(this, arguments);
        if (prev != value && arguments.length<2) $(this).trigger("change");
        return ret;
    }
    function _setupDefaultFormField(field) {
        if ($(field).is(":disabled")) {
            $(field).addClass("idleF disF");
        }
        else {
            if ($(field).val() == "" || $(field).val() == $(field).attr("placeholder")) {
                $(field).val($(field).attr("placeholder"), true);
                $(field).removeClass("focusF").addClass("idleF");
            }
            else
                $(field).removeClass("focusF").addClass("compF");
        }
    }
    
    $(document).ready(function() {
    
        // form placeholder text // PART TWO
        $("select.flexselect").flexselect({
            onSelect: function(hiddenField, visibleField, selectedValue, selectedName) {
                $(visibleField).removeClass("idleF").addClass("compF");
            }
        });
        $('form.npf input[type="text"], form.npf input[type="password"], form.npf input[type="email"], form.npf input[type="search"], form.npf textarea').each(function() {
            _setupDefaultFormField(this);
            $(this).focus(function() {
                if ($(this).hasClass("idleF"))
                    $(this).val("", true);
                else
                    this.select();
                $(this).removeClass("idleF compF").addClass("focusF");
            });
            $(this).bind("change", function() {
                //alert('change');
                if ($(this).val() == "" || $(this).val() == $(this).attr("placeholder")) {
                    $(this).val($(this).attr("placeholder"), true);
                    $(this).removeClass("focusF").removeClass("compF").addClass("idleF");
                }
                else
                    $(this).removeClass("idleF").addClass("compF");
            });
            $(this).blur(function() {
                _setupDefaultFormField(this);
            });
        });
        $("form.npf").bind("submit", function() {
            $(this).find(":input[class~='idleF']").val("", true);
        });
        $("form.npf").bind("reset", function() {
            $(this).find(':input[class~="compF"]').val("", true);
            $(this).find('select option:selected').attr("selected", "");
            $(this).find(':input').trigger("blur");
            $(this).find('.flexselect-hidden-field').val("", true);
            return false;
        });
        $("form.npf").bind("postSubmit", function() {
            $(this).find(':input').trigger("blur");
            return false;
        });
        
    });
    
})(this.jQuery);





/*******************************************************************************
********************************************************************************
 * BEGIN FLEXSELECT
 * Modified to alter user interaction behavior -- neby 6/10
 *
 * flexselect: a jQuery plugin, version: 0.2 (2009-03-16)
 * @requires jQuery v1.3 or later
 *
 * FlexSelect is a jQuery plugin that makes it easy to convert a select box into
 * a Quicksilver-style, autocompleting, flex matching selection tool.
 *
 * For usage and examples, visit:
 * http://rmm5t.github.com/jquery-flexselect/
 *
 * Licensed under the MIT:
 * http://www.opensource.org/licenses/mit-license.php
 *
 * Copyright (c) 2009, Ryan McGeary (ryanonjavascript -[at]- mcgeary [*dot*] org)
 */
(function($) {
  $.flexselect = function(select, options) { this.init(select, options); };

  $.extend($.flexselect.prototype, {
    settings: {
      allowMismatch: false,
      selectedClass: "flexselect_selected",
      dropdownClass: "flexselect_dropdown",
      inputIdTransform:    function(id)   { return id + "_flexselect"; },
      inputNameTransform:  function(name) { return; },
      dropdownIdTransform: function(id)   { return id + "_flexselect_dropdown"; },
      onSelect:            function(elem, value, name)     { return; },
      height: "",
      maxHeight: ""
    },
    select: null,
    input: null,
    hidden: null,
    dropdown: null,
    dropdownList: null,
    cache: [],
    results: [],
    lastAbbreviation: null,
    abbreviationBeforeFocus: null,
    selectedIndex: 0,
    picked: -1,
    dropdownMouseover: false, // Workaround for poor IE behaviors
    isPositioned: false,

    init: function(select, options) {
      $.extend(this.settings, options);
      this.select = $(select);
      this.preloadCache();
      this.renderControls();
      this.wire();
    },

    preloadCache: function() {
      this.cache = this.select.children("option").map(function() {
        return { name: $.trim($(this).text()), value: $(this).val(), score: 0.0 };
      });
    },

    renderControls: function() {
      var selected = this.select.children("option:selected");

      this.hidden = $("<input type='hidden' class='flexselect-hidden-field'/>").attr({
        id: this.select.attr("id"),
        name: this.select.attr("name")
      }).val(selected.val());

      this.input = $("<input type='text' autocomplete='off' />").attr({
        id: this.settings.inputIdTransform(this.select.attr("id")),
        name: this.settings.inputNameTransform(this.select.attr("name")),
        accesskey: this.select.attr("accesskey"),
        tabindex: this.select.attr("tabindex"),
        style: this.select.attr("style"),
        placeholder: this.select.attr("placeholder"),
        defaultValue: $.trim(selected.text())
      }).addClass(this.select.attr("class")).val($.trim(selected.text()));

      this.dropdown = $("<div></div>").attr({
        id: this.settings.dropdownIdTransform(this.select.attr("id"))
      }).addClass(this.settings.dropdownClass);

      if (this.settings.height != "") {
        this.dropdown.css("height", this.settings.height);
      }

      if (this.settings.maxHeight != "") {
        this.dropdown.css("max-height", this.settings.maxHeight);
      }

      this.dropdownList = $("<ul></ul>");
      this.dropdown.append(this.dropdownList);

      this.select.after(this.input).after(this.hidden).remove();
      $("body").append(this.dropdown);

      if ("undefined" == typeof $(this.hidden).parents("form").get(0).elements[$(this.hidden).attr("name")]) {
          $(this.hidden).parents("form").get(0).elements[$(this.hidden).attr("name")] =
              $(this.hidden).get(0);
      }

    },

    position: function() {
        if (this.isPositioned)
            return;

        var dropdownBorderWidth = this.dropdown.outerWidth() - this.dropdown.innerWidth();
        var inputOffset = this.input.offset();
        this.dropdown.css({
            'width': (this.input.outerWidth() - dropdownBorderWidth) + "px",
            'top': (inputOffset.top + this.input.outerHeight()) + "px",
            'left': inputOffset.left + "px"
        });
        this.isPositioned = true;
    },

    wire: function() {
      var self = this;

      this.input.click(function() {
        //alert('Flexselect click');
        self.lastAbbreviation = null;
        self.focus();
      });

      this.input.mouseup(function(event) {
        // This is so Safari selection actually occurs.
        event.preventDefault();
      });

      this.input.focus(function() {
        //alert('Flexselect focus.  picked='+self.picked);
        //self.debug("focus");
        $(this).addClass("focusF");
        self.abbreviationBeforeFocus = self.input.val();
        self.input.select();
        //if (!self.picked)
        self.renderUnfiltered();
      });

      this.input.blur(function() {
        //alert('Flexselect blur');
        $(this).removeClass("focusF");
        if (!self.dropdownMouseover) {
          self.hide();
          if (self.picked == -1 && $(this).hasClass("idleF")) self.reset();
        }
      });

      this.dropdownList.mouseover(function (event) {
        if (event.target.tagName == "LI") {
          var rows = self.dropdown.find("li");
          self.markSelected(rows.index($(event.target)));
        }
      });
      this.dropdownList.mouseleave(function () {
        self.markSelected(-1);
      });
      this.dropdownList.mouseup(function (event) {
        self.pickSelected(true);
        self.focusAndHide();
      });
      this.dropdown.mouseover(function (event) {
        self.dropdownMouseover = true;
      });
      this.dropdown.mouseleave(function (event) {
        self.dropdownMouseover = false;
      });
      this.dropdown.mousedown(function (event) {
        event.preventDefault();
      });

      this.input.keyup(function(event) {
        switch (event.keyCode) {
          case 13: // return
            event.preventDefault();
            self.pickSelected(true);
            self.focusAndHide();
            break;
          case 27: // esc
            event.preventDefault();
            self.reset();
            self.focusAndHide();
            break;
          //case 40: // down
          //  self.renderUnfiltered();
          //  break;
          default:
            self.filterResults();
            break;
        }
      });

      this.input.keydown(function(event) {
        switch (event.keyCode) {
          case 9:  // tab
            self.pickSelected(false);
            self.hide();
            break;
          case 33: // pgup
            event.preventDefault();
            self.markFirst();
            break;
          case 34: // pgedown
            event.preventDefault();
            self.markLast();
            break;
          case 38: // up
            event.preventDefault();
            self.moveSelected(-1, 'up');
            break;
          case 40: // down
            event.preventDefault();
            self.moveSelected(1, 'down');
            break;
          case 13: // return
          case 27: // esc
            event.preventDefault();
            event.stopPropagation();
            break;
        }
      });
    },

    renderUnfiltered: function() {
        var abbreviation = this.input.val();
        if (abbreviation == this.lastAbbreviation) return;

        var results = [];
        $.each(this.cache, function() {
        results.push(this);
        });
        this.results = results;

        var list = this.dropdownList.html("");
        $.each(this.results, function() {
        // list.append($("<li/>").html(this.name + " <small>[" + Math.round(this.score*100)/100 + "]</small>"));
        list.append($("<li/>").html(this.name));
        });

        this.renderDropdown();
        //this.markFirst();
        this.markSelected(this.picked);
        this.lastAbbreviation = abbreviation;
        //this.picked = false;
    },

    filterResults: function() {
      var abbreviation = this.input.val();
      if (abbreviation == this.lastAbbreviation) return;

      var results = [];
      $.each(this.cache, function() {
        this.score = LiquidMetal.score(this.name, abbreviation);
        if (this.score > 0.0)
            results.push(this);
      });
      this.results = results;

      this.sortResults();

      var list = this.dropdownList.html("");
      $.each(this.results, function() {
        // list.append($("<li/>").html(this.name + " <small>[" + Math.round(this.score*100)/100 + "]</small>"));
        list.append($("<li/>").html(this.name));
      });

      this.renderDropdown();
      this.markFirst();
      this.lastAbbreviation = abbreviation;
      //this.picked = false;
    },

    sortResults: function() {
      this.results.sort(function(a, b) { return b.score - a.score; });
    },

    renderDropdown: function() {
      this.position();
      //this.debug("drawing");
      this.dropdown.show();

      var zi=10;
      $('*').each(function() {
        if($(this).css("position")=="absolute"){
          var cur = parseInt($(this).css('zIndex'));
          zi = cur > zi ? parseInt($(this).css('zIndex')) : zi;
        }
      });

      this.dropdown.css('zIndex',zi+=10);
    },

    markSelected: function(n, hint) {
      //this.debug("markSelected("+n+", "+hint+")<br/>selectedIndex = "+this.selectedIndex);
      if (n > this.results.length-1) return;
      if (n < 0) return;

      var rows = this.dropdown.find("li");
      rows.removeClass(this.settings.selectedClass);
      this.selectedIndex = parseInt(n);

      if (n >= 0) {
        $(rows[n]).addClass(this.settings.selectedClass);
        if (hint == 'down') {
            if (this.dropdown.height() < ($(rows[n]).position().top + $(rows[n]).outerHeight()*1.5)) {
                this.dropdown.scrollTop(this.dropdown.scrollTop() + $(rows[n]).outerHeight()+2);
            }
        }
        else if (hint == 'up') {
            if (0 > ($(rows[n]).position().top - $(rows[n]).outerHeight()*1.5)) {
                this.dropdown.scrollTop(this.dropdown.scrollTop() - $(rows[n]).outerHeight()-2);
            }
        }
        else {
            if ($(rows[n]).position().top < 0 || $(rows[n]).position().top > this.dropdown.height()) {
                this.dropdown.scrollTop($(rows[n]).position().top);
            }
        }
      }
    },

    pickSelected: function(doOnSelect) {
      var selected = this.results[this.selectedIndex];
      if (selected) {
        this.input.val(selected.name, true);
        this.hidden.val(selected.value, true);
        for (var i in this.cache) {
            if (this.cache[i].value == selected.value) {
                //this.debug("Picked = "+i);
                this.picked = i;
                break;
            }
        }

        if (doOnSelect)
            this.settings.onSelect(this.hidden, this.input, selected.value, selected.name);

      } else if (this.settings.allowMismatch) {
        this.hidden.val("", true);
      } else {
        this.reset();
      }
    },

    hide: function() {
      //this.debug("hide()");
      //this.dropdown.hide();
      function _hide(d) {
        return function() { d.hide(); }
      }
      var fref = _hide(this.dropdown);
      window.setTimeout(fref, 0);
      this.lastAbbreviation = null;
    },

    moveSelected: function(n, hint) { this.markSelected(this.selectedIndex+n, hint); },
    markFirst:    function()  { this.markSelected(0); },
    markLast:     function()  { this.markSelected(this.results.length - 1); },
    reset:        function()  { this.input.val(this.abbreviationBeforeFocus, true); },
    focus:        function()  { this.input.focus(); },
    focusAndHide: function()  {
        //this.debug("focusAndHide()");
        this.focus();
        this.hide();
    },

    debug: function(str) {
        $("#fs-dbg").append("<p>" + str + "</p>");
        $("#fs-dbg").scrollTop($("#fs-dbg").children(":last-child").position().top);
    }
  });

  $.fn.flexselect = function(options) {
    this.each(function() {
      if (this.tagName == "SELECT") new $.flexselect(this, options);
    });
    return this;
  };
})(jQuery);

/*******************************************************************************
********************************************************************************
* END FLEXSELECT
*******************************************************************************/





/*******************************************************************************
 * BEGIN LIQUIDMETAL
 * a FlexSelect dependency
 *
 * LiquidMetal, version: 0.1 (2009-02-05)
 *
 * A mimetic poly-alloy of Quicksilver's scoring algorithm, essentially
 * LiquidMetal.
 *
 * For usage and examples, visit:
 * http://github.com/rmm5t/liquidmetal
 *
 * Licensed under the MIT:
 * http://www.opensource.org/licenses/mit-license.php
 *
 * Copyright (c) 2009, Ryan McGeary (ryanonjavascript -[at]- mcgeary [*dot*] org)
 */
var LiquidMetal = function() {
  var SCORE_NO_MATCH = 0.0;
  var SCORE_MATCH = 1.0;
  var SCORE_TRAILING = 0.8;
  var SCORE_TRAILING_BUT_STARTED = 0.9;
  var SCORE_BUFFER = 0.85;

  return {
    score: function(string, abbreviation) {
      // Short circuits
      if (abbreviation.length == 0) return SCORE_TRAILING;
      if (abbreviation.length > string.length) return SCORE_NO_MATCH;

      var scores = this.buildScoreArray(string, abbreviation);

      var sum = 0.0;
      for (var i in scores) {
        sum += scores[i];
      }

      return (sum / scores.length);
    },

    buildScoreArray: function(string, abbreviation) {
      var scores = new Array(string.length);
      var lower = string.toLowerCase();
      var chars = abbreviation.toLowerCase().split("");

      var lastIndex = -1;
      var started = false;
      for (var i in chars) {
        var c = chars[i];
        var index = lower.indexOf(c, lastIndex+1);
        if (index < 0) return fillArray(scores, SCORE_NO_MATCH);
        if (index == 0) started = true;

        if (isNewWord(string, index)) {
          scores[index-1] = 1;
          fillArray(scores, SCORE_BUFFER, lastIndex+1, index-1);
        }
        else if (isUpperCase(string, index)) {
          fillArray(scores, SCORE_BUFFER, lastIndex+1, index);
        }
        else {
          fillArray(scores, SCORE_NO_MATCH, lastIndex+1, index);
        }

        scores[index] = SCORE_MATCH;
        lastIndex = index;
      }

      var trailingScore = started ? SCORE_TRAILING_BUT_STARTED : SCORE_TRAILING;
      fillArray(scores, trailingScore, lastIndex+1);
      return scores;
    }
  };

  function isUpperCase(string, index) {
    var c = string.charAt(index);
    return ("A" <= c && c <= "Z");
  }

   function isNewWord(string, index) {
    var c = string.charAt(index-1);
    return (c == " " || c == "\t");
  }

  function fillArray(array, value, from, to) {
    from = Math.max(from || 0, 0);
    to = Math.min(to || array.length, array.length);
    for (var i = from; i < to; i++) { array[i] = value; }
    return array;
  }
}();

/*******************************************************************************
********************************************************************************
* END LIQUIDMETAL
*******************************************************************************/
