if (typeof(Prototype) == "undefined") throw("Form Controls module requires prototype.js");
if (typeof(Scriptaculous) == "undefined") throw("Form Controls module requires builder modeule from scriptaculous.js");
if (typeof(Common) == "undefined") throw("Form Controls module requires common.js");

var Icon = {

    create: function(id, src, alt, title, w, h){
        var img = Element.extend(new Image(w, h));
        img.id = id;
        img.src = src;
        img.altText = alt;
        img.title = title;
        img.observe("mouseover", Cursor.pointer.bindAsEventListener(Cursor));
        img.observe("mouseout", Cursor.normal.bindAsEventListener(Cursor));

        return img;
    }
}

var CalendarControl = {

    previous: function(){
        var p = Icon.create("previous", "/common/scripts/modules/images/prev.png", "Previous", "Previous Month", 5, 9);
        Event.observe(p, "click", CalendarControl.previous_clk.bindAsEventListener(CalendarControl));
        return p;
    },

    next: function(){
        var n = Icon.create("next", "/common/scripts/modules/images/next.png", "Next", "Next Month", 5, 9);
        Event.observe(n, "click", CalendarControl.next_clk.bindAsEventListener(CalendarControl));
        return n;
    },

    previous_clk: function(){
        document.body.removeChild($("calendarControl"));
        CalendarControl.calendar = null;
        CalendarControl.isDisplayed = false;
        CalendarControl.show("",
                             CalendarControl.position,
                             CalendarControl.date.lastMonth(),
                             CalendarControl.duration,
                             CalendarControl.maxYear,
                             CalendarControl.update,
                             CalendarControl.callback);
    },

    next_clk: function(event){
        document.body.removeChild($("calendarControl"));
        CalendarControl.calendar = null;
        CalendarControl.isDisplayed = false;
        CalendarControl.show("",
                             CalendarControl.position,
                             CalendarControl.date.nextMonth(),
                             CalendarControl.duration,
                             CalendarControl.maxYear,
                             CalendarControl.update,
                             CalendarControl.callback);
    },

    over: function(event){
        Cursor.pointer(event);
        CalendarControl.bgStyle = Event.element(event).getStyle("backgroundColor");
        Event.element(event).setStyle({backgroundColor:"#efefef"});
    },

    out: function(event){
        Cursor.normal(event);
        Event.element(event).setStyle({backgroundColor:CalendarControl.bgStyle});
    },

    click: function(event, data){
        CalendarControl.callback(data.month+1, parseInt(Event.element(event).innerHTML),
                                 data.year);
        $("calendarControl").hide();
    },

    create: function(){
        CalendarControl.calData = new Calendar(parseInt(CalendarControl.date.getFullYear(), 10), CalendarControl.date.getMonth());

        var table = Builder.node('table');
        Element.setStyle(table, {borderCollapse:"collapse",
                                 borderSpacing:0,
                                 border:"1px solid #3d3d54",
                                 fontSize:".7em",
                                 color: "black",
                                 background:"#b8b8fc"});
        var thead = Builder.node('thead');
        var lft = Builder.node('td', [CalendarControl.previous()]);
        var ctr = Builder.node('td', {colSpan:5}, [CalendarControl.calData.title]);
        Element.setStyle(ctr, {textAlign:"center"});
        var rgt = Builder.node('td', [CalendarControl.next()]);
        Element.setStyle(rgt, {textAlign:"right", width:20+"px"});
        var controls = Builder.node('tr', {id:"controls"}, [lft, ctr, rgt]);
        var headings = $A([]);
        $A(CalendarControl.calData.dow).each(function(day){
            var td = Builder.node('td', [day.slice(0,2)]);
            Element.setStyle(td, {backgroundColor:"#7b7ba8",textAlign:"center",border:"1px solid #3d3d54"});
            headings.push(td);
        });
        var dow = Builder.node('tr', {id:"dow"}, [headings]);
        thead.appendChild(controls);
        thead.appendChild(dow);
        table.appendChild(thead);


        var body = Builder.node('tbody');
        $A(CalendarControl.calData.monthCalendar).each(function(row){
            var cells = $A([]);
            row.each(function(cell){
                var c = Builder.node('td');
                Element.setStyle(c, {backgroundColor:"#b8b8fc",
                                     width:"20px",
                                     height:"20px",
                                     textAlign:"center",
                                     border:"1px solid #3d3d54"});
                var calDate = new Date((CalendarControl.calData.month+1)+"/"+cell+"/"+CalendarControl.calData.year).valueOf();
                var newDate = new Date(new Date().toDateString()).valueOf();
                var controlDate = new Date($F(CalendarControl.update)).valueOf();
                if (calDate == newDate) c.setStyle({background:"#f2f2f2"});
                if (calDate == controlDate) c.setStyle({background:"#8f8f8f"});
                c.innerHTML = (cell!=0)?cell:'';
                Event.observe(c, "mouseover", CalendarControl.over.bindAsEventListener(CalendarControl));
                Event.observe(c, "mouseout", CalendarControl.out.bindAsEventListener(CalendarControl));
                Event.observe(c, "click", CalendarControl.click.bindAsEventListener(CalendarControl, CalendarControl.calData));
                cells.push(c);
            });
            body.appendChild(Builder.node('tr', [cells]));
            table.appendChild(body);
        });
        CalendarControl.calendar = Builder.node('div', {id:"calendarControl"}, [table]);
        Element.setStyle(CalendarControl.calendar, {width:"154px",
                                                    height:"176px",
                                                    position:"absolute",
                                                    top:CalendarControl.position.top+"px",
                                                    left:CalendarControl.position.left+30+"px",
                                                    zIndex:100});

        return CalendarControl.calendar;

    },

    show:function(event, position, date, duration, maxYear, fieldToUpdate, callback){
        CalendarControl.isDisplayed = false;
        CalendarControl.position = (event)?Position.get(Event.element(event)):position;
        CalendarControl.callback = callback;
        CalendarControl.update = fieldToUpdate;
        CalendarControl.date = (date && typeof(date)=="object")?date:new Date($F(CalendarControl.update));
        CalendarControl.duration = duration;
        CalendarControl.maxYear = maxYear;

        if (CalendarControl.duration){
            if (CalendarControl.timer){
                CalendarControl.timer.stop();
                CalendarControl.timer=null;
            }
            CalendarControl.timer = new PeriodicalExecuter(function(){
                CalendarControl.hide();
            }, CalendarControl.duration);
        }

        if (!CalendarControl.isDisplayed){
            var cal = CalendarControl.create();
            if ($("calendarControl")){
                document.body.replaceChild(cal, $("calendarControl"));
            }else{
                document.body.appendChild(cal);
            }

            CalendarControl.isDisplayed = true;


            var wHeight = getWindowHeight();
            var wWidth = getWindowWidth();
            var dim = Element.getDimensions(CalendarControl.calendar);
            var scrolledOffset = Position.realOffset(CalendarControl.calendar);
            var l = CalendarControl.position.left;
            var t = CalendarControl.position.top;
            l = (scrolledOffset[0]>dim.width)?l+(scrolledOffset[0]-dim.width):l+scrolledOffset[0];
            t = (scrolledOffset[1]>dim.height)?t+(scrolledOffset[1]-dim.height):t+scrolledOffset[1];
            if ((l + dim.width) > wWidth){
                l = l-dim.width;
            }
            if ( (t + dim.height) > wHeight ){
                t = t-dim.height;
            }
            Position.set(CalendarControl.calendar, l+30, t-10);

            CalendarControl.isDisplayed = true;
        }else{
            $("calendarControl").show();
            CalendarControl.isDisplayed = true;
        }
    },

    hide:function(){
        $("calendarControl").hide();
        if (CalendarControl.timer){
            CalendarControl.timer.stop();
            CalendarControl.timer = null;
        }
    }
}


var DateControl = {
    create:function(id, requestName, defaultDate, minYear, maxYear){
        DateControl.id = id;
        DateControl.requestName = requestName;
        DateControl.date = (typeof(defaultDate) == 'object')?defaultDate:new Date(defaultDate);
        DateControl.requestedDate = DateControl.date;
        DateControl.minYear = (minYear)?parseInt(minYear, 10):parseInt(new Date().getFullYear(),10);
        DateControl.maxYear = (maxYear)?parseInt(maxYear, 10):DateControl.minYear+10;


        var dateStr = "";
        var controls = $A([]);

        DateControl.monthSelect = FormControls.select_one("month", "month", {"size":1, "style":"margin:0;padding:0;"}, function(){
            var options = $A([]);
            $A(DateControl.date.MONTHS).each(function(m, i){
                i += 1;
                options.push(FormControls.option( m, i, (i == DateControl.date.getMonth()+1) ));
            });
            return options;
        }.call());
        dateStr += DateControl.monthSelect.value;
        Event.observe(DateControl.monthSelect, "change", DateControl.updateOnChange.bindAsEventListener(DateControl));
        controls.push(DateControl.monthSelect);

        DateControl.daySelect = FormControls.select_one("day", "day", {"size":1, "style":"margin:0;padding:0;"}, function(){
            var options = $A([]);
            $R(1, DateControl.date.monthLength()).each(function(x){
                options.push(FormControls.option( x, x, (x == DateControl.date.getDate()) ));
            });
            return options;
        }.call());
        dateStr += "/"+DateControl.daySelect.value;
        Event.observe(DateControl.daySelect, "change", DateControl.updateOnChange.bindAsEventListener(DateControl));
        controls.push(DateControl.daySelect);

        DateControl.yearSelect = FormControls.select_one("year", "year", {"size":1, "style":"margin:0;padding:0;"}, function(){
            var options = $A([]);
            $R(DateControl.minYear, DateControl.maxYear).each(function(x){
                options.push(FormControls.option(x, x, (x == parseInt(DateControl.date.getFullYear(), 10)) ));
            });
            return options;
        }.call());
        dateStr += "/"+DateControl.yearSelect.value;
        Event.observe(DateControl.yearSelect, "change", DateControl.updateOnChange.bindAsEventListener(DateControl));
        controls.push(this.yearSelect);

        if (DateControl.update){
            DateControl.requestedDate = dateStr;
            controls.push(FormControls.hidden(DateControl.requestName, DateControl.requestName, DateControl.requestedDate));
        }

        var calendar = Icon.create("calendar", "/common/scripts/modules/images/calendar.png", "Calendar", "Choose a Date", 18, 17);
        calendar.observe("mouseover", Cursor.pointer.bindAsEventListener(Cursor));
        calendar.observe("mouseout", Cursor.normal.bindAsEventListener(Cursor));
        calendar.observe("click", CalendarControl.show.bindAsEventListener(CalendarControl, "", "", 7, DateControl.maxYear, DateControl.requestName, DateControl.update));
        controls.push(calendar);

        return Builder.node('div', controls);
    },

    update:function(month, day, year){
        $("month").value = month;
        $("day").value = day;
        $("year").value = year;
        $(DateControl.requestName).value = month+"/"+day+"/"+year;
    },

    updateOnChange: function(event){
        var dy = $F("day");
        var dt = new Date(($F('month'))+"/1/"+$F("year"));
        if (dt.monthLength() < dy) dy = dt.monthLength();
        var e = Event.element(event);
        if (e.id == 'month'){
            var newDaySelect = FormControls.select_one("day", "day", {"size":1, "style":"margin:0;padding:0;"}, function(){
                var options = $A([]);
                $R(1, dt.monthLength()).each(function(x){
                    options.push(FormControls.option( x, x, (x == dy) ));
                });
                return options;
            }.call());
            e.parentNode.replaceChild(newDaySelect, $("day"));
        }

        DateControl.date = new Date($F('month')+"/"+$F('day')+"/"+$F("year")).toLocaleDateString();
        $(DateControl.requestName).value = DateControl.date;
    }
};

var phoneNumber = {
    create:function(intl, type){
        this.type = (type)?type:"phone";
        return (intl)?this.intlPhoneWidget():this.phoneWidget();
    },

    phoneWidget:function(){
        var container = document.createElement("div")

        var ac = document.createElement("input");
        ac.name = this.type+"_areacode";
        ac.id = ac.name;
        ac.title = "Your Area Code";
        ac.size = 4;
        ac.maxLength = 3;
        ac.onkeyup = function(){return FormControls.autoTab(this, "n");}
        container.appendChild(ac);

        var ex = document.createElement("input");
        ex.name = this.type+"_exchange";
        ex.id = ex.name;
        ex.title = "Your Local Exchange";
        ex.size = 4;
        ex.maxLength = 3;
        ex.onkeyup = function(){return FormControls.autoTab(this, "n");}
        container.appendChild(ex);

        var nu = document.createElement("input");
        nu.name = this.type+"_number";
        nu.id = nu.name;
        nu.title = "Your Local Number";
        nu.size = 5;
        nu.maxLength = 4;
        nu.onkeyup = function(){return FormControls.autoTab(this, "n");}
        container.appendChild(nu);

        container.appendChild(document.createTextNode("x"));

        var x = document.createElement("input");
        x.name = this.type+"_extension";
        x.id = x.name;
        x.title = "Your Extension (Optional)";
        x.size = 6;
        x.maxLength = 5;
        container.appendChild(x);

        return container;
    },

    intlPhoneWidget:function(){
        var container = this.phoneWidget();

        var cc = document.createElement("input");
        cc.name = this.type+"_countrycode";
        cc.id = cc.name;
        cc.title = "Your Country Code (For numbers outside of the US/Canada)";
        cc.size = 4;
        cc.maxLength = 3;
        cc.onkeyup = function(){return FormControls.autoTab(this, "n");}
        container.insertBefore(cc, container.firstChild);

        return container;
    }
}

FormControls = {

    _assignAttr:function(o, attributes){
        for (var attr in attributes){
            o.setAttribute(attr, attributes[attr]);
        }
        return o;
    },

    _input:function(id, name, value, type, attributes){
        var e = document.createElement('input');
        e.id = id;
        e.name = name;
        e.type = type;
        if (value) e.value = value;
        return this._assignAttr(e, attributes);
    },

    _select:function(id, name, type, attributes, options){
        var e = document.createElement('select');
        e.id = id;
        e.name = name;
        if (type != null) e.setAttribute(type, type);
        for(var x=0;x<options.length;x++){
            if (Client.ie_all()){
                e.add(options[x]);
            }else{
                e.add(options[x], null);
            }
        }
        return this._assignAttr(e, attributes);
    },

    autoTab:function(e, filter){
        var msg, pattern;

        if (!e.value.empty()){
            switch (filter){
                case "n":
                    msg = new String("Entered value must be made up of numbers in the range [0-9].");
                    pattern = /^([0-9]+)$/;
                    break;
                case "a":
                    msg = new String("Entered value must be made up of alphas in the range [a-zA-Z].");
                    pattern = /^([a-zA-Z]+)$/;
                    break;
                case "an":
                    msg = new String("Entered value must be made up of alpha-numerics in the range [a-zA-Z0-9].");
                    pattern = /^([a-zA-Z0-9]+)$/;
                    break;
                default:
                    break;
            }
            (!new RegExp(pattern).test($w(e.value).pop()))?alert(msg):null;
        }
        if (e.value.length == e.maxLength){
            while (e = e.nextSibling){
                if (e.type == "text"){break;}
                continue;
            }
            (e)?e.focus():null;
            return true;
        }
        return false;
    },

    form:function(action, method, controls, block, attributes){
        var f = document.createElement('form');
        f.action = action;
        f.method = method;
        for (var control in controls){
            if (block){
              var l = this.label(control, {"style":"display:block"})
              f.appendChild(l);
            }else{
              f.appendChild(this.label(control));
            }
            f.appendChild(controls[control]);
        }
        return this._assignAttr(f, attributes);
    },

    hidden:function(id, name, value){
        return this._input(id, name, value, "hidden");
    },

    text:function(id, name, value, attributes){
        return this._input(id, name, value, "text", attributes);
    },

    password:function(id, name, value, attributes){
        return this._input(id, name, value, "password", attributes);
    },

    radio:function(id, name, value, attributes){
        return this._input(id, name, value, "radio", attributes);
    },

    checkbox:function(id, name, value, attributes){
        return this._input(id, name, value, "checkbox", attributes);
    },

    button:function(id, name, value, attributes){
        return this._input(id, name, value, "button", attributes);
    },

    submit:function(id, name, value, attributes){
        return this._input(id, name, value, "submit", attributes);
    },

    reset:function(id, name, value, attributes){
        return this._input(id, name, value, "reset", attributes);
    },

    textarea:function(id, name, value, attributes){
        var e = document.createElement('textarea');
        e.id = id;
        e.name = name;
        if (value) e.value = value;
        return this._assignAttr(e, attributes);
    },

    select_one:function(id, name, attributes, options){
        return this._select(id, name, null, attributes, options);
    },

    select_multiple:function(id, name, attributes, options){
        return this._select(id, name, "multiple", attributes, options);
    },

    option:function(text, value, selected){
        return new Option(text, value, null, selected);
    },

    label:function(id, value, attributes){
        var l = document.createElement("label");
        l.id = (id)?id:null;
        l.innerHTML = value;
        return this._assignAttr(l, attributes);
    },

    fieldset:function(id, legend, attributes){
        var fs = document.createElement("fieldset");
        fs.id = id;
        var lgnd = document.createElement("legend");
        lgnd.innerHTML = legend;
        fs.appendChild(lgnd);
        return this._assignAttr(fs, attributes);
    },

    dateSelect:function(id, requestName, defaultDate, minYear, maxYear){
        return DateControl.create(id, requestName, defaultDate, minYear, maxYear);
    },

    phoneNumber:function(intl, type){
        return phoneNumber.create(intl, type);
    }
}
