﻿// JScript File

/**
Author: Steven Becker
Created: 11/21/2006
Description: This file contains commonly used UI/javascript functionality.
    Primary use is to wrap normal HTML elements with Javascript ones so that event handling is much easier.
*/

UI = {
    AddJSControlPrototypes : function(obj)
    {
        obj.prototype.AppendObj = function(o) {
            this.element.appendChild(o.element);
        };
        obj.prototype.Append = function(element) {
            this.element.appendChild(element);
        };
        obj.prototype.Show = function () {
            if(!this.visible)
                Events.StandardEvent(this, "OnShow");
        };
        obj.prototype.Hide = function () {
            if(this.visible)
                Events.StandardEvent(this, "OnHide");
        };
        obj.prototype.ToggleShowHide = function() {
            if(this.visible)
                this.Hide();
            else
                this.Show();
        };
        obj.prototype.OnShow = function(element) {
            this.visible = true;
            this.element.style.display = "";
        };
        obj.prototype.OnHide = function(element) {
            this.visible = false;
            this.element.style.display = "none";
        };
        //this is used to work with the style and other aspects of the element at the html level
        obj.prototype.GetHtmlElement = function() { return this.element; };
    },
    InitializeHtmlWrapper : function(obj, element) {
        var e = element;
        obj.element = e;
        obj.id = e.id;
        obj.visible = ( obj.element.style.display != "none" );
        Events.RegisterObject(obj);
        Events.Register(obj, "OnShow", Bind(obj, obj.OnShow));
        Events.Register(obj, "OnHide", Bind(obj, obj.OnHide));
    },
    AddStandardEvent : function(obj, elementEvent, eventName)
    {
        Events.Register(obj, eventName);
        if(obj.element[elementEvent])
            Events.RegisterHandler(obj, eventName, function() { eval( obj.element[elementEvent] ) });
            
        obj.element[elementEvent] = function() { Events.StandardEvent(Events.GetObject(obj.id), eventName); };
    },
    CreateTable : function(numRows) {
        var hTable = document.createElement("table");
        var htBody = document.createElement("tBody");
        hTable.appendChild(htBody);
        
        var rows = [];
        
        for(var i = 0; i < numRows; i++)
        {
            rows[i] = document.createElement("tr");
            htBody.appendChild(rows[i]);
        }
        
        return { table: hTable, tBody: htBody, rows: rows };
    }
            
}

/**
Type: Class
Description: Wraps an HTML Div element and provides event driven interfaces for show and hide functionality.
Constructor (htmlDiv): Accepts an existing div.
*/
Layer = function(htmlDiv)
{
    UI.InitializeHtmlWrapper(this, htmlDiv);
}
UI.AddJSControlPrototypes(Layer);

Button = function(htmlButton)
{
    UI.InitializeHtmlWrapper(this, htmlButton);
    UI.AddStandardEvent(this, "onclick", "OnClick");
}
UI.AddJSControlPrototypes(Button);

Link = function(htmlLink)
{
    UI.InitializeHtmlWrapper(this, htmlLink);
    UI.AddStandardEvent(this, "onmouseover", "OnMouseOver");
    UI.AddStandardEvent(this, "onmouseout", "OnMouseOut");
    UI.AddStandardEvent(this, "onfocus", "OnMouseOver");
    UI.AddStandardEvent(this, "onblur", "OnMouseOut");
    UI.AddStandardEvent(this, "onclick", "OnClick");
}
UI.AddJSControlPrototypes(Link);

TableCell = function(htmlTd) //good for tds and ths
{
    UI.InitializeHtmlWrapper(this, htmlTd);
    UI.AddStandardEvent(this, "onmouseover", "OnMouseOver");
    UI.AddStandardEvent(this, "onmouseout", "OnMouseOut");
    UI.AddStandardEvent(this, "onclick", "OnClick");
}
UI.AddJSControlPrototypes(TableCell);

Table = function(htmlTable)
{
    UI.InitializeHtmlWrapper(this, htmlTable);
}
UI.AddJSControlPrototypes(TableCell);

//Input types
TextBox = function(htmlTextBox) //good for input type=text and textareas
{
    UI.InitializeHtmlWrapper(this, htmlTextBox);
    UI.AddStandardEvent(this, "onmouseover", "OnMouseOver");
    UI.AddStandardEvent(this, "onmouseout", "OnMouseOut");
    UI.AddStandardEvent(this, "onclick", "OnClick");
    UI.AddStandardEvent(this, "onfocus", "OnFocus");
    UI.AddStandardEvent(this, "onblur", "OnBlur");
    UI.AddStandardEvent(this, "onchange", "OnChange");
}
UI.AddJSControlPrototypes(TextBox);

TextBox.prototype.SetText = function(v)
{
    this.element.value = v;
    Events.StandardEvent(this, "OnChange");
}

TextBox.prototype.GetText = function(v)
{
    return this.element.value;
}

//Radio Button
CheckBox = function(htmlCheckbox) //good for both checkboxes and for radio buttons.
//not sensitive to other radio buttons changing my value.  Use a radio button list for that.
{
    UI.InitializeHtmlWrapper(this, htmlCheckbox);
    UI.AddStandardEvent(this, "onmouseover", "OnMouseOver");
    UI.AddStandardEvent(this, "onmouseout", "OnMouseOut");
    
    Events.Register(this, "OnChecked");
    Events.Register(this, "OnUnchecked");
    this.element.onclick = function() { Events.GetObject(this.id).Click(); };
}
UI.AddJSControlPrototypes(CheckBox);

CheckBox.prototype.GetValue = function() {
    return this.element.value;
}

CheckBox.prototype.IsChecked = function() {
    return this.element.checked;
}

CheckBox.prototype.Click = function() {
    if(this.element.checked)
        Events.StandardEvent(this, "OnChecked");
    else
        Events.StandardEvent(this, "OnUnchecked");
}

CheckBox.prototype.Check = function() {
    if(!this.element.checked)
    {
        this.element.checked = true;
        Events.StandardEvent(this, "OnChecked");
    }
}

CheckBox.prototype.UnCheck = function() {
    if(this.element.checked)
    {
        this.element.checked = false;
        Events.StandardEvent(this, "OnUnchecked");
    }
}

/** Used for both Checkbox lists and radio button lists. 
Parameter: exclusive - indicates whether or not one item being checked causes all others to be unchecked (such as radio buttons)
*/
CheckBoxList = function(exclusive, checkboxes) {
    var ex = exclusive;
    this.exclusive = exclusive;
    var cbs = checkboxes;
    this.checkboxes = cbs;
    
    for(var i = 0; i < this.checkboxes.length; i++)
    {
        this["v" + this.checkboxes[i].GetValue()] = i;
    }
    this.value = this.GetValue();
    
    Events.Register(this, "OnChange");
    
    for(var i = 0; i < this.checkboxes.length; i++)
    {
        Events.RegisterHandler(this.checkboxes[i], "OnChecked", Bind(this, this.OnOneChecked));
        Events.RegisterHandler(this.checkboxes[i], "OnUnchecked", Bind(this, this.OnOneUnchecked));
    }
        
        
}

UI.AddJSControlPrototypes(CheckBoxList);

CheckBoxList.prototype.OnOneChecked = function(checkbox) {
    if(this.exclusive) {
        for(var i = 0; i < this.checkboxes.length; i++)
        {
            if(this.checkboxes[i].id != checkbox.id && this.checkboxes[i].IsChecked)
                this.checkboxes[i].UnCheck();
        }
    }
    
    if(this.value != this.GetValue())
    {
        this.value = this.GetValue();
        var _dispatch = Events.GetHandlers(this, "OnChange");
        for(var i = 0; i < _dispatch.length; i++)
            _dispatch[i](this.value);
    }
}

CheckBoxList.prototype.OnOneUnchecked = function(checkbox) {
    if(this.value != this.GetValue())
    {
        this.value = this.GetValue();
        var _dispatch = Events.GetHandlers(this, "OnChange");
        for(var i = 0; i < _dispatch.length; i++)
            _dispatch[i](this.value);
    }
}

//override default onhide and onshow functionality, since we are a collection of elements.
CheckBoxList.prototype.OnShow = function(element) {
    for(var i = 0; i < this.checkboxes.length; i++)
        this.checkboxes[i].Show();
}

CheckBoxList.prototype.OnHide = function(element) {
    for(var i = 0; i < this.checkboxes.length; i++)
        this.checkboxes[i].Hide();
}

CheckBoxList.prototype.Check = function(value) {
    this.checkboxes[this["v" + value]].Check();
}

CheckBoxList.prototype.UnCheck = function(value) {
    this.checkboxes[this["v" + value]].UnCheck();
}

CheckBoxList.prototype.IsChecked = function(value) {
    this.checkboxes[this["v" + value]].IsChecked();
}

CheckBoxList.prototype.GetValue = function(value) {
    var ret = "";
    for(var i = 0; i < this.checkboxes.length; i++)
    {
        if(this.checkboxes[i].IsChecked())
        {
            if(this.exclusive)
                return this.checkboxes[i].GetValue();
            else
                if(ret != "")
                    ret = ret + ","
            ret = ret + this.checkboxes[i].GetValue();
        }
    }
    return ret;
}

DropDown = function(htmlDropDown)
{
    UI.InitializeHtmlWrapper(this, htmlDropDown);
    UI.AddStandardEvent(this, "onmouseover", "OnMouseOver");
    UI.AddStandardEvent(this, "onmouseout", "OnMouseOut");
    UI.AddStandardEvent(this, "onchange", "OnChange");
}
UI.AddJSControlPrototypes(DropDown);

DropDown.prototype.GetSelectedText = function() {
    return this.element.options[this.element.options.selectedIndex].text;
}

DropDown.prototype.GetSelectedValue = function() {
    return this.element.options[this.element.options.selectedIndex].value;
}

DropDown.prototype.GetSelectedIndex = function() {
    return this.element.options.selectedIndex;
}

DropDown.prototype.GetByIndex = function(i) {
    if( i < this.element.options.length)
    {
        var t = this.element.options[i].text;
        var v = this.element.options[i].text;
        return { index: i, text: t, value: v };
    }
    else
        return null;
}

DropDown.prototype.GetByValue = function(v) {
    
    var found = false;
    for(var i = 0; i < this.element.options.length; i++)
        if(this.element.options[i].value == v)
        {
            found = true;
            break;
        }
    
    if(!found) {
        return null;
    }
    
    return { index: i, text: this.element.options[i].text, value: v };
}

DropDown.prototype.GetByText = function(t) {
    
    var found = false;
    for(var i = 0; i < this.element.options.length; i++)
        if(this.element.options[i].text == t)
        {
            found = true;
            break;
        }
    
    if(!found) {
        return null;
    }
    
    return { index: i, text: t, value: this.element.options[i].value };
}

DropDown.prototype.SelectText = function(text) {
    for(var i = 0; i < this.element.options.length; i++)
        if(this.element.options[i].text == text)
            return this.SelectIndex(i);
            
    return false;
}

DropDown.prototype.SelectIndex = function(index) {
    var found = index < this.element.options.length && index >= 0;
    if(found) {
        if(index != this.element.options.selectedIndex)
        {
            this.element.options.selectedIndex = index;
            Events.StandardEvent(this, "OnChange");
        }
        return true;
    }
    return false;
    
}

DropDown.prototype.SelectValue = function(value) {
    for(var i = 0; i < this.element.options.length; i++)
        if(this.element.options[i].value == value)
            return this.SelectIndex(i);
            
    return false;
}

Span = function(htmlSpan)
{
    UI.InitializeHtmlWrapper(this, htmlSpan);
    
    this.textNode = document.createTextNode("");
    
    this.element.appendChild(this.textNode);
}

Span.prototype.SetText = function(t)
{
    this.textNode.nodeValue = t;
}

Span.prototype.GetText = function()
{
    return this.textNode.nodeValue;
}
UI.AddJSControlPrototypes(Span);


ExclusiveLayers = function(layers, visibleLayerId)
{
    var l = layers;
    this.layers = l;
    
    for(var i = 0; i < this.layers.length; i++)
    {
        this["v" + this.layers[i].id] = i;
        if(this.layers[i].id != visibleLayerId)
            this.layers[i].Hide();
            
        Events.RegisterHandler(this.layers[i], "OnShow", Bind(this, function(layer) {
            for(var i = 0; i < this.layers.length; i++)
                if(this.layers[i].id != layer.id)
                    this.layers[i].Hide();
        }));
        
        if(this["v" + visibleLayerId])
            this.layers[this["v" + visibleLayerId]].Show();
    }
}

ExclusiveLayers.prototype.GetLayer = function(layerId)
{
    return this.layers[this["v" + layerId]];
}

ExclusiveLayers.prototype.ShowLayer = function(layerId)
{
    this.layers[this["v" + layerId]].Show();
}


DefaultCalendarDropDownOptions = function () {
    return { 
        minDate : null,
        maxDate : null,
        DateFormat : null,
        ChangeYearEnabled : true,
        ChangeMonthEnabled : true,
        GetLinkContents : function() { return document.createTextNode("Change"); } 
    };
}

CalendarDropDown = function(htmldiv, start, selectedDay, opt) {
    UI.InitializeHtmlWrapper(this, htmldiv);
    
    this.options = DefaultCalendarDropDownOptions();
    if(opt)
        for(field in opt)
            this.options[field] = opt[field];
    
    Events.RegisterObject(this);
    
    if(this.options.DateFormat && this.options.DateFormat != null)
        this.format = this.options.DateFormat;
    else
        this.format = Dates.ShortDateFormat;   
    
    var table = document.createElement("table");
    table.cellSpacing = 0;
    table.cellPadding = 0;
    table.style.height = "18px";
    var tBody = document.createElement("tbody");
    table.appendChild(tBody);
    table.className = "calDDTable";
    var row = document.createElement("tr");
    tBody.appendChild(row);
    temp = document.createElement("td");
    temp.style.width = "100%";
    temp.className = "calDDOuterCell";
    row.appendChild(temp);
    temp2 = document.createElement("table");
    temp2.className = "calDDOuterTable";
    temp2.style.width = "100%";
    temp2.cellSpacing = 0;
    temp2.cellPadding = 0;
    temp.appendChild(temp2);
    temp = document.createElement("tbody");
    temp2.appendChild(temp);
    row = document.createElement("tr");
    temp.appendChild(row);
    
    var c1 = document.createElement("td");
    c1.className = "calDDDateCell";
    row.appendChild(c1);
    
    var c2 = document.createElement("td");
    c2.className = "calDDButtonCell";
    row.appendChild(c2);

    row = document.createElement("tr");
    tBody.appendChild(row);
    var c = document.createElement("td");
    c.colSpan = "2";
    row.appendChild(c);
    this.calRow = new TableCell(row);
    
    var dText = document.createElement("a");
    dText.className = "calDDDateLink";
    dText.href = "javascript:nothing()";
    this.textNode = document.createTextNode(start.Format(this.format));
    dText.appendChild(this.textNode);
    c1.appendChild(dText);
    
    this.link = this.options.GetLinkContents();
    this.link.element.href = "javascript:nothing()";
    c2.appendChild(this.link.element);
    
    this.cal = document.createElement("div");
    this.cal.id = Text.Format("{0}{1}", this.id, "cal")
    c.appendChild(this.cal);    
    this.currentDate = start.Format(this.format);
    this.cal = new Calendar(this.cal, start, selectedDay, this.options);
    this.cal.Hide();
    
    this.element.appendChild(table);
    
    c1 = new TableCell(c1);
    Events.RegisterHandler(c1, "OnClick", Bind(this, function(obj) {
        this.cal.ToggleShowHide();
        this.link.Toggled(this.link);
    }));
    Events.Register(this, "OnChange");
    
    Events.RegisterHandler(this.link, "OnClick", Bind(this, function(obj) {
        this.cal.ToggleShowHide();
    }));
    
    Events.RegisterHandler(this.cal, "DaySelected", Bind(this, function(date) {
        this.cal.Hide();
        if(this.currentDate != date.Format(this.format))
            this.TriggerOnChange(date);
    }));
    
    Events.RegisterHandler(this.cal, "OnShow", Bind(this, function(obj) {
        this.calRow.Show();
    }));
    
    Events.RegisterHandler(this.cal, "OnHide", Bind(this, function(obj) {
        this.calRow.Hide();
    }));
}

UI.AddJSControlPrototypes(CalendarDropDown);

CalendarDropDown.prototype.OnShow = function() {
    this.cal.Show();
}

CalendarDropDown.prototype.OnHide = function() {
    this.cal.Hide();
}

CalendarDropDown.prototype.ToggleShowHide = function() {
    if(this.cal.visible)
        this.cal.Hide();
    else
        this.cal.Show();
};
        
CalendarDropDown.prototype.TriggerOnChange = function(date) {
    this.textNode.nodeValue = date.Format(this.format);
    this.currentDate = date.Format(this.format);
    var _dispatch = Events.GetHandlers(this, "OnChange");
    for(var i = 0; i < _dispatch.length; i++)
        _dispatch[i](date);
}

CalendarDropDown.prototype.GetDate = function() {
    return this.cal.GetDate();
}

CalendarDropDown.prototype.SetDate = function(date) {
    this.cal.SetDate(date);
    this.TriggerOnChange(date);
}


Tab = function(name, area, tabLink) {
    this._name = name;
    this._area = area;
    this._link = tabLink;
    
    Events.Register(this, "OnSelect");
    Events.RegisterHandler(this._link, "OnClick", Bind(this, this.OnClick));
    Events.RegisterHandler(this._link, "OnMouseOver", Bind(this, this.OnMouseOver));
    Events.RegisterHandler(this._link, "OnMouseOut", Bind(this, this.OnMouseOut));

};

Tab.prototype.Select = function() {
    this._area.Show();
    this._link.element.className = "tabHeadSelected";
    this._selected = true;
    
    var _dispatch = Events.GetHandlers(this, "OnSelect");
    for(var i = 0; i < _dispatch.length; i++)
        _dispatch[i](this);
}

Tab.prototype.OnClick = function() {
    this.Select();
};

Tab.prototype.OnMouseOver = function() {
    if(this._selected != true) {
        this._link.element.className = "tabHeadOver";
    }
};

Tab.prototype.OnMouseOut = function() {
    if(this._selected != true) {
        this._link.element.className = "tabHead";
    }
};

Tab.prototype.Deselect = function() {
    if(this._selected)
    {
        this._selected = false;
        this._link.element.className = "tabHead";
    }
}


TabControl = function(tabs) {
    var layers = [];
    this.Tabs = [];
    this.TabIndex = { };
    for(var i = 0; i < tabs.length; i++)
    {
        this.Tabs[i] = tabs[i];
        this.TabIndex[tabs[i]._name] = i;
        
        Events.RegisterHandler(this.Tabs[i], "OnSelect", Bind(this, this.TabSelected));
        
        
        layers.push(tabs[i]._area);
    }
    
    //set up the layers to auto show/hide
    this._exl = new ExclusiveLayers(layers, layers[0].id);
    this.Tabs[0].Select();
};

TabControl.prototype.TabSelected = function (tab) {
    for(var i = 0; i < this.Tabs.length; i++)
        if(tab._name != this.Tabs[i]._name)
            this.Tabs[i].Deselect();
};