﻿//Fields
var IsPageLoaded        = false;
var _Validators         = new Array();
var _ActiveObjects		= new Array();
var _DelayedPostbackIds = new Array();

window.attachEvent("onload", _Init);

function _Init() {
	IsPageLoaded = true;

	_SelectLastItem();
	_SetAlternateTableRows();
	_InitializeValidators();
	_InitializeDelayedPostbacks();
	
	//DOM Updates after AJAX calls may orphan the inputs associated with Validators.
	// We need to reInitializr our validators after each request is completed.
	try{
	    Sys.WebForms.PageRequestManager.getInstance().add_endRequest(_InitializeClientObjects);
	    }
	catch(err){}
}

function _InitializeClientObjects()
{
	_InitializeValidators();
	_InitializeActiveObjects();
}

function _InitializeActiveObjects()
{
    _ActiveObjects.each(function(item) { item.BindEvents(); });
}

// Set a table's CSS class to include the class "AlternateRowTable" if you would like
// to set an alternate row style... This is used instead of the cluncky use of 
// <alternate Item Template> in some list controls when all you want to do 
// is set an alternate BG color.
function _SetAlternateTableRows() {
	var i = 0;
	$$('.AlternateRowTable tr').each(function(tr) {
		if (i % 2 == 0)
			tr.addClass('alternateRow');
		i++;
	});
}

// Some dropdownlist that are automatically generated require the last item to be selected.
// lets to this by selecting all DOM elements with the apropriate class name and do just that.
function _SelectLastItem() {
	$$('.SelectLastItem').each(function(list) { list.selectedIndex = list.options.length - 1; });
}

// This function creates custom Validator objects from all DOM elements 
// marked with a "Validate[type]" Css class name.
function _InitializeValidators() {
    // Lets start by releasing all the existing validators. This will only happen on
    // return from an AJAX call.  On the initial page load, _Validators will be empty.
    _Validators.each(function(item){item = null}); 
    _Validators = new Array();

    //Ok, lets start making Validators!
    $$('.ValidateAreaCodeOrRange').each(function(input) {_Validators.push(new Validator(input, '^[0-9]{1,3}-?[0-9]{0,3}?$')); });
	$$('.ValidateSicOrRange').each(function(input)      {_Validators.push(new Validator(input, '^[0-9]{1,6}-?[0-9]{0,6}?$')); });
	$$('.ValidateNaicsOrRange').each(function(input) { _Validators.push(new Validator(input, '^[0-9]{1,8}-?[0-9]{0,8}?$')); });
	$$('.ValidateZipOrRange').each(function(input) { _Validators.push(new Validator(input, '^[0-9]{1,5}[-?]{0,1}[0-9]{0,5}?$')); });
	$$('.ValidateRoute').each(function(input)           {_Validators.push(new Validator(input, '^[cCrRbBhH]{1}[0-9]{0,3}?$')); });
	$$('.ValidateText').each(function(input)            {_Validators.push(new Validator(input, '^[0-9a-zA-Z _-]*$')); });
	$$('.ValidateNumber').each(function(input)          {_Validators.push(new Validator(input, '^[0-9]*$')); });
	$$('.ValidateZip4').each(function(input)            {_Validators.push(new Validator(input, '^[0-9]{0,4}?$')); }); // Variant of number.
	$$('.ValidateDecimal').each(function(input)         {_Validators.push(new Validator(input, '^[0-9.]*$')); }); //TODO: fix this regex expresion it blows!
	$$('.ValidatePhone').each(function(input)			{_Validators.push(new Validator(input, '^[0-9.()-]*$', { blurExpression: '^[(]{0,1}(\d{3})[)]{0,1}[ -]{0,1}(\d{3}([ -]{0,1}))(\d{4}|[A-Z]{4})$' })); }); 
	
	//the following are useful for From/To cases where the To input allows "ALL" to be entered in addition to number/decimal
	$$('.ValidateDecimalOrAll').each(function(input) { _Validators.push(new Validator(input, '^[0-9.]*$|^A*$|^AL*$|^ALL*|^a*$|^al*$|^all*$')); });
	$$('.ValidateNumberOrAll').each(function(input) { _Validators.push(new Validator(input, '^[0-9.]*$|^A*$|^AL*$|^ALL*|^a*$|^al*$|^all*$')); });
	
	//Validate Currency input such as: $40,000,000
	$$('.ValidateCurrency').each(function(input)        {_Validators.push(new Validator(input, '^[\$]?[0-9,]*$')); });
}


//grab all controls marked with class="DelayedPostback" and store their ids in a global array
function _InitializeDelayedPostbacks() {

    //re initialize the array
    _DelayedPostbackIds.each(function(item) { item = null });
    _DelayedPostbackIds = new Array();

    //add the ids
    $$('.DelayedPostback').each(function(input) { _DelayedPostbackIds.push(input.id); });
}


// **********************************
// CLASSES
// **********************************

// Any object that wants to persist its events over AJAX DOM updates should
// inherit form this class.  All that is needed is the implementation of the abstract
// method BindEvents.  This method will be called after the completion of any AJAX request.
var Persister = new Class({
    initialize: function() {
        _ActiveObjects.push(this);
    },

    BindEvents: function() {
        alert('Objects extending this class are required to implement this "BindEvents" method.');
    }
});

// This object forces the keystrokes and blur event of a text input to follow specific RegEx patters.
var Validator = new Class({
	initialize: function(input, expression, options) {
		this.keyExpression = expression;
		this.blurExpression = expression;
		this.errorColor = '#f33';

		if ($type(input) == 'element') {
			this.inputId = input.id; // an element was passed

			if (input.id.length == 0)
				this.input = input;
		}
		else {
			this.inputId = input; // a element id was passed.
		}

		// override default options if provided.
		if (options) {
			if (options.errorColor)
				this.errorColor = options.errorColor;

			if (options.blurExpression)
				this.blurExpression = options.blurExpression;
		}

		this.BindEvents();
	},

	BindEvents: function() {
		if (this.inputId.length > 0 && !$defined(this.input))
			this.input = $(this.inputId);

		if (!$defined(this.input))
			return;
		
		this.input.addEvent('blur', this.validateBlur.bind(this));
		this.input.addEvent('keyup', this.validateKey.bind(this));
		this.oldValue = this.input.value;
	},

	validateKey: function(ev) {
		return this.validate(ev, this.keyExpression);
	},

	validateBlur: function(ev) {
		return this.validate(ev, this.blurExpression);
	},

	validate: function(ev, expression) {
		var myRegX = new RegExp(expression);

		if (this.input.value.length == 0 || myRegX.test(this.input.value)) {
			this.oldValue = this.input.value;
			return true;
		}

		this.input.highlight(this.errorColor);
		this.input.value = this.oldValue; // todo: learn how to chain this to the END of the highlight call.
		return false;
	}
});

// This object allows for toggling of a set of checkboxes by clicking a "toggler" element.
var CheckBoxToggler = new Class({
    Extends: Persister,

    initialize: function(togglerId, checkboxSelector, options) {
        this.checkText = "Check all";
        this.clearText = "Clear all";
        this.checkState = true;
        this.togglerId = togglerId;
        this.checkboxSelector = checkboxSelector;

        // check if any options were seleted:
        if (options) {
            if (options.clearText)
                this.clearText = options.clearText;

            if (options.checkText)
                this.checkText = options.checkText;

            this.checkState = options.checkState == true;
        }

        this.BindEvents();
        this.parent(); // call the constructor of base class
    },

    BindEvents: function() {
        this.checkboxes = $$(this.checkboxSelector);
        this.toggler = $(this.togglerId);

        if (!$defined(this.toggler))
            return;

        this.toggler.addEvent('click', this.toggle.bind(this));
        this.toggler.setStyle('cursor', 'pointer'); // make the mouseover a pointer...
    },

    toggle: function(ev) {
        var newState = this.checkState = !this.checkState;

        // toggle the link text if such an option was
        // specified

        if (this.checkState)
            this.toggler.set('text', this.clearText);
        else
            this.toggler.set('text', this.checkText);

        // toggle the checkboxes
        this.checkboxes.each(function(input) {
            if (input.type == "checkbox") // just to be safe!
                input.checked = newState;
        });
    }
});


// This object allows for toggling of a set of checkboxes by clicking a "toggler" checkbox.
// It does not change the checkbox text.
var CheckBoxToggler2 = new Class({
    Extends: Persister,

    initialize: function(togglerId, checkboxSelector, inverse) {

        this.togglerId = togglerId;
        this.checkboxSelector = checkboxSelector;
        this.inverse = inverse; // check all makes other checkboxes blank

        this.BindEvents();
        this.parent(); // call the constructor of base class
    },

    BindEvents: function() {
        this.checkboxes = $$(this.checkboxSelector);
        this.toggler = $(this.togglerId);

        if (!$defined(this.toggler))
            return;

        this.toggler.addEvent('click', this.toggle.bind(this));
        this.toggler.setStyle('cursor', 'pointer'); // make the mouseover a pointer...

        for (i = 0; i < this.checkboxes.length; i++)
            this.checkboxes[i].addEvent('click', this.toggleMain.bind(this));
    },

    toggleMain: function(event) {

        // uncheck the main checkbox if any of the individual 
        // children have been selected

        if (event.target) {
            if (event.target.type == "checkbox") {
                if (this.inverse) {
                    if (event.target.checked) {
                        var inputs = this.toggler.getElementsByTagName("INPUT");
                        if (inputs[0].type == "checkbox") {
                            inputs[0].checked = false;
                        }

                    }
                }
                else {
                    if (!event.target.checked) {
                        var inputs = this.toggler.getElementsByTagName("INPUT");
                        if (inputs[0].type == "checkbox") {
                            inputs[0].checked = false;
                        }

                    }
                }
            }
        }
    },

    toggle: function(ev) {

        // toggle the child checkboxes

        var inputs = this.toggler.getElementsByTagName("INPUT");
        var newState = false;

        if (inputs[0].type == "checkbox")
            newState = inputs[0].checked;
        if (this.inverse)
            newState = !newState;

        // if inverse, only 'unchecks' the subordinate buttons
        // if normal, then both checks and unchecks them
        if (!this.inverse || newState == false) {
            this.checkboxes.each(function(input) {
                if (input.type == "checkbox") // just to be safe!
                    input.checked = newState;
            });
        }
    }
});

var RegionToggler = new Class({
	initialize: function(toggler, region, options) {
        this.openIcon   = "plus.gif";
        this.closeIcon  = "minus.gif";
        this.checkState = true;
		this.region = $(region);
		this.toggler = $(toggler).addEvent('click', this.toggle.bind(this));
		this.icon = this.toggler.getElements('img')[0];
		this.toggler.setStyle('cursor', 'pointer'); // make the mouseover a pointer...
		
		// check if any options were seleted:
		if (options) {
	        if (options.openIcon)
	            this.openIcon = options.openIcon;
    	        
	        if (options.closeIcon)
	            this.closeIcon = options.closeIcon;

            this.checkState = options.checkState == true;
		}
    },    
    
    toggle: function(ev) {
		var newState = this.checkState = !this.checkState;
            
		//toggle the link text
		if (this.checkState)
            this.icon.src = this.icon.src.replace(this.closeIcon, this.openIcon);
        else
            this.icon.src = this.icon.src.replace(this.openIcon, this.closeIcon);

		// toggle the checkboxes
		this.region.toggleDisplay();
    }
});

var HobbiesRegionToggler = new Class({
    initialize: function(toggler, region, options) {
        this.openIcon = "plus.gif";
        this.closeIcon = "minus.gif";          
        this.region = $(region);
        this.toggler = $(toggler).addEvent('click', this.toggle.bind(this));
        this.icon = this.toggler.getElements('img')[0];
        this.toggler.setStyle('cursor', 'pointer'); // make the mouseover a pointer...        
    },

    toggle: function(ev) {   
        
        //toggle the link text
        if (this.icon.src.contains(this.closeIcon))
            this.icon.src = this.icon.src.replace(this.closeIcon, this.openIcon);
        else
            this.icon.src = this.icon.src.replace(this.openIcon, this.closeIcon);

        // toggle the checkboxes
        this.region.toggleDisplay();
    }
});

// Allows for matching of list items with the text being types into an associated textbox.
var TypeAheadObject = new Class({
    Extends: Persister,

    initialize: function(tbId, lbId, options) {
        this.textBoxId = tbId;
        this.listBoxId = lbId;
        this.isNumeric = false; // default is text.

        // check for optional parameters.
        if (options) {
            if (options.isNumeric)
                this.isNumeric = true;
        }

        this.BindEvents();
        this.parent(); // call the constructor of base class
    },

    BindEvents: function() {
        this.ListBox = $(this.listBoxId);
        this.TextBox = $(this.textBoxId);

        if (this.ListBox)
            this.ListBox.addEvent('change', this.ListBoxChange.bind(this));

        if (this.TextBox)
            this.TextBox.addEvent('keypress', this.TextBoxKeyPress.bind(this));
    },

    ListBoxChange: function(e) {
        this.TextBox.value = this.ListBox.options[this.ListBox.selectedIndex].text;
    },

    TextBoxKeyPress: function(e) {
        // if form input field & it is a printable character
        if (e.target.nodeName.toUpperCase() != 'INPUT' || e.code < 32 || e.code > 126)
            return;

        var numOptions = this.ListBox.options.length;
        var strEntry = this.TextBox.value.toUpperCase() + e.key.toUpperCase();

        // cycle through options
        for (var i = 0; i < numOptions; i++) {
            // get compare string from value same length as entered string
            var strCompare;

            if (this.isNumeric)
                strCompare = this.ListBox.options[i].value.substring(0, strEntry.length).toUpperCase();
            else
                strCompare = this.ListBox.options[i].text.substring(0, strEntry.length).toUpperCase();

            // if value matches what is entered
            if (strEntry == strCompare) {
                this.ListBox.selectedIndex = numOptions - 1;
                this.ListBox.selectedIndex = i; // select this option
                break;
            }
        }
    }
});


//This class is useful for image button controls which have popups to display
//See Location.ascx
var PopupHandler = new Class({
    Extends: Persister,

    initialize: function(ctrlId, popupId, options) {
		this.ControlId = ctrlId;
		this.PopupID = popupId;
		
		this.BindEvents();
        this.parent(); // call the constructor of base class
	},
	
    BindEvents: function() {
        this.Control = $(this.ControlId);

        if (this.Control)
            this.Control.addEvent('click', this.AddPopupHandler.bind(this));

    },
    
    AddPopupHandler: function(e){
		$find(this.PopupID).show();
    }
	

});

// END CLASSES


//MooTools "Element" class extensions.
Element.implement({
	toggleDisplay: function() {
		if (this.getStyle('display') == 'none')
			this.setStyle('display', 'block');
		else
			this.setStyle('display', 'none');

		return this;
	}
});

//handles the doubleclick-to-add functionality on the listbox controls
function selectorListBox_DoubleClick(objid) {

}


//move options from one listbox to another
//also sort the listboxes
function moveSelectedOptions(fromListbox, toListbox, hdnSelections, hdnSelectionsRemoved,removeFlag) {
    // Move them over
    if (!hasOptions(fromListbox)) { return; }
    for (var i = 0; i < fromListbox.options.length; i++) {
        var o = fromListbox.options[i];
        if (o.selected) {
            if (!hasOptions(fromListbox)) { var index = 0; } else { var index = toListbox.options.length; }
            toListbox.options[index] = new Option(o.text, o.value, false, false);
            if (removeFlag == true) {
                hdnSelections.value = hdnSelections.value.replace(o.value + "\x03" + o.text + "\x1F", "");
                hdnSelectionsRemoved.value = hdnSelectionsRemoved.value + o.value + "\x03" + o.text + "\x1F";
            }
            else {
                hdnSelections.value = hdnSelections.value + o.value + "\x03" + o.text + "\x1F";
                hdnSelectionsRemoved.value = "";
            }
        }
    }
    // Delete them from original
    for (var i = (fromListbox.options.length - 1); i >= 0; i--) {
        var o = fromListbox.options[i];
        if (o.selected) {
            fromListbox.options[i] = null;
        }
    }

    if (arguments < 4)
        sortListbox(fromListbox);
    else
        sortListbox(toListbox);
    
    fromListbox.selectedIndex = -1;
    toListbox.selectedIndex = -1;
}

//move options from one listbox to another for Business Expense control
//also sort the listboxes
function BusinessExpenseMoveSelected(ListItems, fromListbox, toListbox, hdnSelections, hdnSelectionsRemoved,removeFlag) {
    // Move them over
    if (!hasOptions(fromListbox)) { return; }
    for (var i = 0; i < fromListbox.options.length; i++) {
        var o = fromListbox.options[i];
        if (o.selected) {
            if (!hasOptions(fromListbox)) { var index = 0; } else { var index = toListbox.options.length; }
            toListbox.options[index] = new Option(o.text, o.value, false, false);
            if (removeFlag == true) {
                hdnSelections.value = hdnSelections.value.replace(o.value + "\x03" + o.text + "\x1F", "");
                hdnSelectionsRemoved.value = hdnSelectionsRemoved.value + o.value + "\x03" + o.text + "\x1F";
            }
            else {
                hdnSelections.value = hdnSelections.value + o.value + "\x03" + o.text + "\x1F";
                hdnSelectionsRemoved.value = "";
            }
        }
    }
    // Delete them from original
    for (var i = (fromListbox.options.length - 1); i >= 0; i--) {
        var o = fromListbox.options[i];
        if (o.selected) {
            fromListbox.options[i] = null;
        }
    }

    if (arguments < 4)
        BusinessExpenseSortListbox(fromListbox, ListItems);
    else
        BusinessExpenseSortListbox(toListbox, ListItems);

    fromListbox.selectedIndex = -1;
    toListbox.selectedIndex = -1;
}

//find if the listbox has items
function hasOptions(obj) {
    if (obj != null && obj.options != null) { return true; }
    return false;
}


//sort listbox items
function sortListbox(lb) {
    arrTexts = new Array();
    arrValues = new Array();
    arrOldTexts = new Array();

    for (i = 0; i < lb.length; i++) {
        arrTexts[i] = lb.options[i].text;
        arrValues[i] = lb.options[i].value;

        arrOldTexts[i] = lb.options[i].text;
    }   
    
    arrTexts.sort();   

    for (i = 0; i < lb.length; i++) {
        lb.options[i].text = arrTexts[i];
        for (j = 0; j < lb.length; j++) {
            if (arrTexts[i] == arrOldTexts[j]) {
                lb.options[i].value = arrValues[j];
                j = lb.length;
            }
        }
    }
}

function BusinessExpenseSortListbox(lb, ListItems) {
    arrTexts = new Array();
    arrValues = new Array();
    arrOldTexts = new Array();

    for (i = 0; i < lb.length; i++) {
        arrTexts[i] = lb.options[i].text;
        arrValues[i] = lb.options[i].value;

        arrOldTexts[i] = lb.options[i].text;
    } 
      
    //Sort the list items for Business Expense control
    if (ListItems != null) {
        arrTexts = BusinessExpenseSort(arrTexts, ListItems);
    }

    for (i = 0; i < lb.length; i++) {
        lb.options[i].text = arrTexts[i];
        for (j = 0; j < lb.length; j++) {
            if (arrTexts[i] == arrOldTexts[j]) {
                lb.options[i].value = arrValues[j];
                j = lb.length;
            }
        }
    }
}
function BusinessExpenseSort(arrTexts, ListItems) {
    arrNewTexts = new Array();

    for (i = 0; i < ListItems.length; i++) {
        for (j = 0; j < arrTexts.length; j++) {
            if (ListItems.options[i].text == arrTexts[j]) {
                arrNewTexts.push(arrTexts[j]);
            }
        }
    }
    return arrNewTexts;
}

//checkbox controls with "Select all"
    function Cb_Click(allCbId, cblId, count)
    {
        var allChecked = true;
        
        for (var i=0; i<count; i++)
        {
            var cbid = cblId + "_" + i; //checkbox ids are numbered.
            var cb = document.getElementById(cbid);
            
            if (cb) // if its valid, set the state to follow the "All" checkbox.
                if (!cb.checked)
                    allChecked = false;
        }
        
        var all = document.getElementById(allCbId);
        
        if (all)
            all.checked = allChecked;
    }
    
    function SelectAll_Click(allCb, cblId, count)
    {
        for (var i=0; i<count; i++)
        {
            var cbid = cblId + "_" + i; //checkbox ids are numbered.
            var cb = document.getElementById(cbid);
            
            if (cb) // if its valid, set the state to follow the "All" checkbox.
                cb.checked = allCb.checked;
        }
    }

    function SelectorListBox_Click(objid) {
        var underscore = objid.lastIndexOf('_');
        var appendid = objid.substring(0, underscore) + "_selectorHiddenField";

        var hiddenid = $get(appendid);
        if (hiddenid != null) {
            hiddenid.value = "selectorclicked";
        }

        var btnId = objid.substring(0, underscore) + "_btnAdd";
        __doPostBack(btnId, '');
    }  