/**
 * The emptyText function will take care of 
 * specialized "Enter something here" behavior 
 * for form fields.  It will make sure the text 
 * is displaying when the field is empty and 
 * gone when the user clicks on it to enter 
 * something.  
 * 
 * Here's how to use this function:
 * 
 * <input 
 *    id="date"                  [optional]
 *    name="date"                [optional]
 *    value="{$date}"            [optional]
 *    class="normalclass"        [optional]
 *    emptyvalue="Enter date"    [required]
 *    emptyclass="grayedout"     [optional]
 *  />
 * <script>emptyText()</script>
 * 
 * Notice the two extra non-standard attributes,
 * emptyvalue and emptyclass.  These specify the 
 * text and class that will be given to the 
 * field when it is empty.  Like the class 
 * attribute, emptyclass may include more than 
 * one class.  If emptyclass is not specified, 
 * the class will not change when the field is 
 * empty.
 * 
 * You can optionally pass an argument to the 
 * emptyText function that is an id or a 
 * reference to the element you wish to effect.  
 * This can be useful for dynamically created 
 * elements or to avoid ambiguity.  If you don't 
 * pass any arguments to the emptyText function, 
 * it will search backward from the <script> 
 * element for an <input> element.  It is 
 * recommended keep the  <script> element close 
 * to the <input> element.  
 * 
 * It has the added benefit that if a field 
 * contains the empty text when the 
 * form is submitted, the empty text won't get 
 * sent to the server. This  relieves the form 
 * handling code from having to check for the 
 * empty text.
 * 
 * This should almost always "just work".  One 
 * exception is if you want to clear the input 
 * element from javascript.  Instead of setting 
 * input.value = '', use input.clear().  That 
 * will ensure the empty text is  showing after 
 * the input is cleared.
 * 
 * Requires prototype.js
 * 
 * @author Russ Black
 * 
 */

 // Use a function to create a namespace to prevent name collisions 
 // with other libraries
(function() {

// define it with bouncyCase and lowercase.
emptyText = emptytext = function(input)
{
    if (!input)
    {
        input = findLastInput()
    }
    input = $(input)
    if (input.emptytext) 
    {
        // this element has already been styled.
        return 
    }
    
    // make a new input element to hold the empty text. Leave it anonymous
    // (no "name" attribute) so it won't get submitted with the form.
    var emptytext = document.createElement('input')
    
    // give it the appropriate class
    if (input.hasAttribute('emptyclass')) 
    {
        emptytext.className = input.getAttribute('emptyclass')
    }
    else 
    {
        emptytext.className = input.className
    }
    
    if (input.hasAttribute("id"))
    {
        emptytext.id=input.id+'-emptytext'
    }
    
    // copy size attribute
    if (input.hasAttribute('size'))
    {
        emptytext.size=input.getAttribute('size')
    }
    
    // populate it an empty value
    if (input.hasAttribute('emptyvalue'))
    {
        emptytext.value=input.getAttribute('emptyvalue')
    }

    // insert emptytext before input
    input.parentNode.insertBefore(emptytext,input)
    
    // give input a reference to its emptytext
    input.emptytext = emptytext
    
    // assume it doesn't currently have focus
    input.hasFocus = false 
    
    // wrap prototype's clear function so we can catch this event and treat it like an empty blur
    input.oldclear=input.clear
    input.clear = function() {
        var r = input.oldclear();
        if (!input.hasFocus) onBlur(input);
        return r
    }
    
    // wrap focus function so we can trap the event
    input.oldfocus = input.focus
    input.focus = function() {
        onFocus(input)
        input.oldfocus()
    }
    
    // add focus listeners
    Event.observe(input,'blur',function() {onBlur(input)})
    Event.observe(input,'focus',function() {onFocus(input)})
    Event.observe(emptytext,'focus',function() {input.focus()})
    
    emptyTextFields.push(input)
    var len = emptyTextFields.length
    
    // set initial state
    onBlur(input)

    // schedule a css scan
    setTimeout(function(){
        if (len == emptyTextFields.length) 
        {
            scanAllCss()
        }
    },500)
}

Event.observe(window, 'load', scanAllCss)
var emptyTextFields = new Array()

/**
 * Called when focus leaves the input field.  Shows the empty text if the input 
 * field is empty
 */
function onBlur(input)
{
    if (input.value.length == 0)
    {
        input.emptytext.style.display=''
        input.style.display='none'
    }
    else
    {
        input.emptytext.style.display='none'
        input.style.display=''
    }
    input.hasFocus=false
}

/**
 * Called when the input field receives focus.  Hides the empty text, shows input field
 */
function onFocus(input)
{
    input.emptytext.style.display='none'
    input.style.display=''
    input.hasFocus=true
}

/**
 * This function looks for any id-specific css selectors on the emptytext 
 * fields and adds corresponding css rules for the emptytext fields.
 * This allows css designers to style at the ID level and still have the 
 * emptytext field look right.  
 */
function scanAllCss()
{   
    // see if any of our fields have an id.  If not, we can 
    // skip this step.
    var hasId = false
    for(var j=0; j<emptyTextFields.length; j++)
    {
        var field = emptyTextFields[j]
        if (field.hasAttribute("id"))
        {
            hasId = true
            break
        }
    }
    if (hasId)
    {
        for (var i=0; i<document.styleSheets.length; i++)
        {
            var ss=document.styleSheets[i]
            scanCss(ss)
        }
    }
}

function scanCss(ss)
{
    try
    {
        // scan imports
        if (ss.imports)
        {
            for(var i=0; i<ss.imports.length; i++)
            {
                scanCss(ss.imports[i])
            }
        }
        
        var rules;
        if (typeof(ss.cssRules) != "undefined") rules = ss.cssRules; // ff and safari
        else if (typeof(ss.rules) != "undefined") rules = ss.rules; // ID
        if (typeof(rules) != "undefined") 
        {
            for(var i=0; i<rules.length; i++)
            {
                var rule = rules[i]
                
                if (rule.styleSheet) // imported style sheet
                {
                    scanCss(rule.styleSheet)
                }
                else
                {
                    for(var j=0; j<emptyTextFields.length; j++)
                    {
                        var field = emptyTextFields[j]
                        if (field.hasAttribute("id"))
                        {
                            var id=field.id
                            var rex = new RegExp("#"+id+"([^a-zA-Z0-9_-]|$)")
                            
                            if (rule.selectorText && rule.selectorText.search(rex)>=0 && rule.selectorText.indexOf("-emptytext") == -1)
                            {
                                var newRule = rule.selectorText.replace(rex,"#"+id+"-emptytext") + '{' + rule.style.cssText + '}'

                                addCss(newRule)
                            }
                        }
                    }
                }
            }
        }
    }
    catch(e)
    {
        //console.log("Caught " + e)
    }
}

function addCss(cssCode) {
    var styleElement = document.createElement("style");
    styleElement.type = "text/css";
    if (styleElement.styleSheet) {
        styleElement.styleSheet.cssText = cssCode;
    } else {
        styleElement.appendChild(document.createTextNode(cssCode));
    }
    document.getElementsByTagName("head")[0].appendChild(styleElement);
}

function findLastInput()
{
    var elem = document.body.lastChild
    while (elem)
    {
        if (elem.tagName.toLowerCase() == "script")
        {
            return findPreviousEmptyTextInput(elem)
        }
        elem = elem.lastChild
    }
    return null
}

function findPreviousTerminalNode(node)
{
    if (node.previousSibling)
    {
        node = node.previousSibling
        while (node.lastChild) node = node.lastChild
        return node
    }
    else if (node.parentNode) return findPreviousTerminalNode(node.parentNode)
    else return null
}

function findPreviousEmptyTextInput(elem)
{
    var node = $(findPreviousTerminalNode(elem))
    while (node && !(node.tagName && node.tagName.toLowerCase() == "input" && node.hasAttribute("emptyvalue")))
    {
        node = $(findPreviousTerminalNode(node))
    }
    return node
}

})() // end wrap