var TimePicker = new Class({
    Implements:[Events, Options],
    
    options:
    {
        makeReadonly:true,
        
        headerText:"Pick a Time",
        separatorText:":",
        amText:"AM",
        pmText:"PM",
        
        cssClasses:
        {
            popup:"timePickerPopup",
            button:"timePickerButton",
            container:"timePickerContainer",
            header:"timePickerHeader",
            hoursInput:"timePickerHours",
            minutesInput:"timePickerMinutes",
            separator:"timePickerSeparator",
            ampmInput:"timePickerAMPM",
            ampmActive:"timePickerAMPMActive"
        },
        
        offsetLeft:0, 
        offsetTop:0,
        
        onShowComplete:$empty,
        onHideComplete:$empty
    },
    
    element:null,
    container:null,
    popup:null,
    isShown:true,
    
    button:null,
    hoursInput:null, 
    minutesInput:null, 
    amInput:null, 
    pmInput:null,
    
    fx:null,
    
    value:
    {
        hour:1,
        minute:0,
        isAM:false
    },
    
    initialize:function(element, options)
    {
        this.element = $(element);
        if(!$chk(this.element)){ return; }
        
        if(options != undefined && options != null)
            this.setOptions(options);
        
        this.build();
    },
    
    build:function()
    {
        if(this.options.makeReadonly)
        {
            this.element.set("readonly", true);
        }
        
        var classes = this.options.cssClasses;
        
        var button = new Element("a", {"class":classes.button});
        button.inject(this.element, "after");
        
        var popup = new Element("div", {"class":classes.popup});
        var container = new Element("div", {"class":classes.container});
        
        var header = new Element("h1", {"class":classes.header});
        header.set("html", this.options.headerText);
        container.grab(header);
        
        var hours = new Element("input", {"type":"text", "class":classes.hoursInput});
        var separator = new Element("div", {"class":classes.separator});
        separator.set("html", this.options.separatorText);
        var minutes = new Element("input", {"type":"text", "class":classes.minutesInput});
        
        container.grab(hours);
        container.grab(separator);
        container.grab(minutes);
        
        var ampm = new Element("ul", {"class":classes.ampmInput});
        
        var amli = new Element("li");
        var am = new Element("a", {"href":"#set-am"})
        am.set("html", this.options.amText);
        
        am.addEvent("click", function(e)
        {
            e.stop();
            if(this.value.isAM){ return; }
            
            this.value.isAM = true;
            am.addClass(classes.ampmActive);
            pm.removeClass(classes.ampmActive);
            this.update();
        }.bind(this));

        amli.grab(am);
        ampm.grab(amli);
        
        var pmli = new Element("li");
        var pm = new Element("a", {"href":"#set-pm"});
        pm.set("html", this.options.pmText);
        
        pm.addEvent("click", function(e)
        {
            e.stop();
            if(!this.value.isAM){ return; }
            this.value.isAM = false;
            this.update();
        }.bind(this));
        
        pmli.grab(pm);
        ampm.grab(pmli);
        
        container.grab(ampm);
        
        container.grab(new Element("div", {"style":"clear:both"}));
        
        popup.grab(container);
        
        popup.inject(this.element, "after");
        
        this.button = button;
        this.popup = popup;
        this.container = container;
        this.hoursInput = hours;
        this.minutesInput = minutes;
        this.amInput = am;
        this.pmInput = pm;
        
        this.button.addEvent("click", function(){ this.show(); }.bind(this));
        
        this.element.addEvent("focus", function(){ this.show(); }.bind(this));
        this.hoursInput.addEvent("keyup", function(){ this.processHourInput(); }.bind(this));
        this.minutesInput.addEvent("keyup", function(){ this.processMinuteInput(); }.bind(this));
        
        this.hoursInput.set("value", this.value.hour.toString());
        this.minutesInput.set("value", this.numZeroPad(this.value.minute));
        
        this.fx = new Fx.Tween(this.popup,
        {
            onStart:function()
            {
                if(!this.isShown)
                {
                    this.fireEvent("showStart");
                }
                else
                {
                    this.fireEvent("hideStart");
                }
            }.bind(this), 
            
            onComplete:function()
            {
                if(!this.isShown)
                {
                    this.fireEvent("showComplete");
                }
                else
                {
                    this.fireEvent("hideComplete");
                }
            }.bind(this)
        });
        
        this.addEvent("showStart",    function(){ this.showStart();    }.bind(this));
        this.addEvent("showComplete", function(){ this.showComplete(); }.bind(this));
        this.addEvent("hideComplete", function(){ this.hideComplete(); }.bind(this));
        
        document.addEvent("mousedown", function(e){ this.checkClick(e); }.bind(this));
        document.addEvent("keyup",     function(e){ this.checkKey(e);   }.bind(this));
        
        this.hoursInput.addEvent("mousewheel",   function(e){ var e = new Event(e); e.stop(); this.handleHoursWheel(e.wheel > 0 ? 1 : -1); }.bind(this));
        this.minutesInput.addEvent("mousewheel", function(e){ var e = new Event(e); e.stop(); this.handleMinutesWheel(e.wheel > 0 ? 1 : -1); }.bind(this));
        
        this.popup.setStyles({
            "display":"block",
            "position":"absolute",
            "visibility":"visible",
            "z-index":1000
            });
        
        this.hide();
        //this.update();
    },
    
    processHourInput:function()
    {
        var value = this.hoursInput.get("value");
        if(value == ""){ return; }
        
        var intVal = parseInt(value);
        
        if(intVal === NaN){ intVal = this.value.hour; }
        
        if(intVal > 12){ intVal = 12; }
        if(intVal <= 0){ intVal = 1; }
        
        this.value.hour = intVal;
        
        this.hoursInput.set("value", this.value.hour.toString());
        
        this.update();
    },
    
    processMinuteInput:function()
    {
        var value = this.minutesInput.get("value");
        if(value == ""){ return; }
        
        var pad = false;
        if(value.charAt(0) == "0" && value.length > 1)
        {
            pad = true;
            value = value.substr(1);
        }
        
        var intVal = parseInt(value);
        
        if(intVal === NaN){ intVal = this.value.minute; }
        
        if(intVal > 59){ intVal = 59; }
        if(intVal < 0){ intVal = 0; }
        
        this.value.minute = intVal;
        
        var str = pad ? this.numZeroPad(this.value.minute) : this.value.minute.toString();
        this.minutesInput.set("value", str);
        
        this.update();
    },
    
    handleHoursWheel:function(direction)
    {
        this.value.hour += direction;
        
        if(this.value.hour <= 0)
        {
            this.value.hour = 12;
        }

        if(this.value.hour > 12)
        {
            this.value.hour = 1;
        }
        
        if(direction > 0 && this.value.hour == 12)
        {
            this.value.isAM = !this.value.isAM;
        }
        else if(direction < 0 && this.value.hour == 11)
        {
            this.value.isAM = !this.value.isAM;
        }
        
        this.hoursInput.set("value", this.value.hour.toString());
        this.update();
    },
    
    handleMinutesWheel:function(direction)
    {
        this.value.minute += direction;
        
        if(this.value.minute < 0)
        {
            this.handleHoursWheel(-1);
            this.value.minute = 59;
        }
        if(this.value.minute > 59)
        {
            this.handleHoursWheel(1);
            this.value.minute = 0;
        }
        
        this.minutesInput.set("value", this.numZeroPad(this.value.minute));
        this.update();
    },
    
    // Show the widget
    show:function()
    {
        if(this.isShown){ return; }
        
        this.fx.start("opacity", 0, 1);
    },
    
    showStart:function()
    {
        this.fx.set("opacity", 0);
        
        if(this.popup.getParent() != $(document.body))
            $(document.body).grab(this.popup, "top");
            
        
        var coords = this.element.getCoordinates();
        
        var left = coords.left + coords.width;
        var top  = coords.top;
        
        this.popup.setStyles({
            "left":left + this.options.offsetLeft,
            "top":top + this.options.offsetTop
        });
    },
    
    showComplete:function()
    {
        this.isShown = true;
    },
    
    // Hide the widget
    hide:function()
    {
        if(!this.isShown){ return; }
        
        this.fx.start("opacity", 1, 0);
    },
    
    hideComplete:function()
    {
        this.isShown = false;
    },
    
    checkClick:function(e)
    {
        if(!this.isShown){ return; }
        
        var e = new Event(e);
        var el = e.target;
        
        var stop = false;

        while (el != document.body && el.nodeType == 1)
        {
            if (el == this.popup || el == this.button) { stop = true; }
            
            if(this.popup.hasChild(el))
            {
                return false;
            }
            
            if (stop)
            { 
                e.stop();
                return false;
            }
            else
            {
                el = el.parentNode;
            }
        }
        
        this.hide();
    },
    
    checkKey:function(e)
    {
        if(!this.isShown){ return; }
        
        var e = new Event(e);
        
        if(e.key == "esc" || e.key == "enter")
        {
            this.hide();
        }
    },
    
    numZeroPad:function(num)
    {
        var str = num.toString();
        if(str.length <= 1)
            str = "0" + str;
        return str;
    },
    
    // Update the value shown inside this.element
    update:function()
    {
        var classes = this.options.cssClasses;
        
        if(this.value.isAM)
        {
            this.amInput.addClass(classes.ampmActive);
            this.pmInput.removeClass(classes.ampmActive);
        }
        else
        {
            this.amInput.removeClass(classes.ampmActive);
            this.pmInput.addClass(classes.ampmActive);
        }
        
        var str = "" + this.numZeroPad(this.value.hour) + this.options.separatorText + this.numZeroPad(this.value.minute);
        str += " ";
        str += this.value.isAM ? this.options.amText : this.options.pmText;
        
        this.element.set("value", str);
    }
});

// Static Functions //

TimePicker.storageKey = "$$TimePickerObject$$";

TimePicker.attachElements = function(elementClass, options)
{
    $$("." + elementClass).each(function(element)
    { 
        TimePicker.attachElement(element, options);
    });
};

TimePicker.attachElement = function(element, options)
{
    var picker = new TimePicker(element, options);
    element.store(TimePicker.storageKey, picker);
};


TimePicker.retrieveFromElement = function(element)
{
    element = $(element);
    if(!$chk(element)){ return null; }
    
    return element.retrieve(TimePicker.storageKey, null);
};

TimePicker.create = function(element, options){ return new TimePicker(element, options); };
