function DateControlObject(elem, isRoot)
{
    var rootElem = elem;
    var id = "";
    if(isRoot) id = elem.id;
    else
    {
        var arr = elem.id.split("_");
        var ln = arr.length-1;
        for(var i=0; i<ln; i++)
        {
            id = id + arr[i];
            if(i<ln-1) id=id + "_";
        }
    }
 //   if(!isRoot)                     
 //       if(elem.parentNode!=null) rootElem = elem.parentNode;
    this.ctlid = id;        
    this.ctlroot = $(id); //document.getElementById(id);
    this.ctlval = $(id + "_dtVal"); //document.getElementById(id + "_dtVal");
    this.ctlday = $(id + "_dtDay"); //document.getElementById(id + "_dtDay");
    this.ctlmonth = $(id + "_dtMonth"); //document.getElementById(id + "_dtMonth");
    this.ctlyear = $(id + "_dtYear"); //document.getElementById(id + "_dtYear");
    this.appearance = this.getProp(this.ctlroot, "appearance");//this.ctlroot.readAttribute["appearance"];
    this.minimumvalue = eval(this.getProp(this.ctlroot, "minimumvalue"));//eval(this.ctlroot.readAttribute["minimumvalue"]);
    this.maximumvalue = eval(this.getProp(this.ctlroot, "maximumvalue"));//eval(this.ctlroot.readAttribute["maximumvalue"]);
    this.datemode = this.getProp(this.ctlroot, "datemode");//this.ctlroot.readAttribute["datemode"];
    this.chooseoption = false;
    this.choosetext = '';
}

function DateControl_GetValue()
{
    return this.ctlval.value;
}

function DateControl_GetDisplayValue()
{
    var d = this.getDay();
    var m = this.getMonth();
    var y = this.getYear();
    var intd = parseInt(d,10);
    if(isNaN(intd)) d="";
    var intm = parseInt(m,10);
    if(isNaN(intm)) m="";
    var inty = parseInt(y,10);
    if(isNaN(inty)) y="";
    if((d+m+y).length==0) 
    {
        return "";
    }
    if(this.datemode=="year") return y;
    else if(this.datemode=="monthyear") return (DateControl_MonthList[intm-1] + " " + y);
    else return (intd.toString() + " " + DateControl_MonthList[intm-1] + " " + y);
}

function DateControl_SetValue()
{
    var d = this.getDay();
    var m = this.getMonth();
    var y = this.getYear();
    var intd = parseInt(d,10);
    if(isNaN(intd)) d="";
    var intm = parseInt(m,10);
    if(isNaN(intm)) m="";
    else m=(intm-1).toString();
    var inty = parseInt(y,10);
    if(isNaN(inty)) y="";
    if((d+m+y).length==0) 
    {
        this.ctlval.value="";
        return;
    }
    this.ctlval.value = m + "/" + d + "/" + y;
}

function DateControl_GetDay()
{
    if(this.datemode!="daymonthyear") return "1";
    var cday = this.ctlday;
    if(this.appearance=="dropdown")
    {
        return (cday.selectedIndex==-1) ? "" : cday.options[cday.selectedIndex].value;
    }
    else return cday.value;
}

function DateControl_GetMonth()
{
    if(this.datemode=="year") return "1";

    var cmonth = this.ctlmonth;
    if(this.appearance=="dropdown")
    {
        return (cmonth.selectedIndex==-1) ? "" : cmonth.options[cmonth.selectedIndex].value;
    }
    else return cmonth.value;
}

function DateControl_GetYear()
{
    var cyear = this.ctlyear;
    if(this.appearance=="dropdown")
    {
        return (cyear.selectedIndex==-1) ? "" : cyear.options[cyear.selectedIndex].value;
    }
    else return cyear.value;
}

function DateControl_ClearValue()
{
    this.ctlval.value = "";
    if(this.appearance=="text")
    {
        this.ctlday.value = "";
        this.ctlmonth.value = "";
        this.ctlyear.value = "";
    }
    else if(this.appearance=="dropdown")
    {
        if(this.datemode!="year") {
            var len = this.ctlmonth.options.length;
            var i;
            for(i=len-1; i>=0; i--) this.ctlmonth.remove(i);
            if(this.chooseoption) {
                var optchoose = document.createElement("OPTION");
                this.ctlmonth.options.add(optchoose);
                optchoose.text = this.choosetext; 
                optchoose.value = "";
            }
            for(i=0; i<=11; i++) {
                var opt = document.createElement("OPTION");
                this.ctlmonth.options.add(opt);
                opt.text = DateControl_MonthList[i];
                opt.value = (i+1).toString();
            }
        }
        if(this.datemode!="monthyear") {
            var len = this.ctlday.options.length;
            var i;
            for(i=len-1; i>=0; i--) this.ctlday.remove(i);
            if(this.chooseoption) {
                var optchoose = document.createElement("OPTION");
                this.ctlmonth.options.add(optchoose);
                optchoose.text = this.choosetext; 
                optchoose.value = "";  
            }          
            for(i=1; i<=31; i++) {
                var opt = document.createElement("OPTION");
                this.ctlday.options.add(opt);
                opt.text = i.toString();
                opt.value = i.toString();
            }
        }    
        this.ctlday.selectedIndex = 0;
        this.ctlmonth.selectedIndex = 0;
        this.ctlyear.selectedIndex = 0;        
    }
}

function DateControl_SetFocus() {
    if(this.datemode=="daymonthyear") this.ctlday.focus();
    else if(this.datemode=="monthyear") this.ctlmonth.focus();
    else this.ctlyear.focus();
}

function DateControl_EnableDisableRecursive(control, newval){
	if(typeof(control)=="undefined" || control==null) return;
	try {
		if (typeof(control.disabled) != "undefined") control.disabled = newval;
	} catch(ex) {}
    
    var i, val;
    var elements = control.childNodes;
    
    if(typeof(elements)=="undefined") return;
    for(var key in elements){
        var node = elements[key];
		try {
			if (typeof(node.disabled) != "undefined") node.disabled = newval;
		} catch(ex) {}
        DateControl_EnableDisableRecursive(node, newval);
    }
}

function DateControl_Enable(){
    DateControl_EnableDisableRecursive(this.ctlroot, false);
}

function DateControl_Disable(){
    DateControl_EnableDisableRecursive(this.ctlroot, true);   
}


function DateControl_UpdateControls(ctlType){
    if( this.appearance == "text") return;
    var minDay = 1;
    var maxDay = 31;
    var minMonth = 0;
    var maxMonth = 11;
    var mchange = false;
    var dchange = false;

    var d = this.getDay();
    var m = this.getMonth();
    var y = this.getYear();
    var intd = parseInt(d,10);
    if(isNaN(intd)) d="";
    var intm = parseInt(m,10);
    if(isNaN(intm)) m="";
    var inty = parseInt(y,10);
    if(isNaN(inty)) y="";

    intm--;
    
    if(ctlType == "year")
    {
        if(isNaN(inty)) return;
        mchange=true;
        if(inty==this.minimumvalue.getFullYear()) minMonth = this.minimumvalue.getMonth();
        if(inty==this.maximumvalue.getFullYear()) maxMonth = this.maximumvalue.getMonth();

        if(!isNaN(intm))
        {
            if(intm<=maxMonth && intm>=minMonth)
            {
                if(mchange) ctlType = "month";
                if(intm==1) /* leap year and february month*/
                {
                    var isleap = ((inty%4)==0);
                    if(isleap && (this.ctlday.options.length==28))
                    {
                        var opt = document.createElement("OPTION");
                        this.ctlday.options.add(opt);
                        opt.text = "29";
                        opt.value = "29";
                    }
                    else if(!isleap && (this.ctlday.options.length==29))
                    {
                        this.ctlday.remove(28);
                    }
                }
            }
        }
        
    }

    if(ctlType == "month")
    {
        if(isNaN(inty)) return;
        if(isNaN(intm)) return;
        dchange=true;
        if(intm==3 || intm==5 || intm==8 || intm==10) /* April, June, September, November has 30 days */
        {    maxDay = 30; }
        else if(intm==1) /* February */
        {
            if((inty%4)==0) maxDay = 29;
            else maxDay = 28;
        }

        if((inty==this.minimumvalue.getFullYear()) && (intm==this.minimumvalue.getMonth()))   minDay = this.minimumvalue.getDate();  
        if((inty==this.maximumvalue.getFullYear()) && (intm==this.maximumvalue.getMonth()))   maxDay = this.maximumvalue.getDate(); 
    }


    if(mchange)
    {
        var len = this.ctlmonth.options.length;
        var i;
        for(i=len-1; i>=0; i--) this.ctlmonth.remove(i);
        for(i=minMonth; i<=maxMonth; i++)
        {
            var opt = document.createElement("OPTION");
            this.ctlmonth.options.add(opt);
            opt.text = DateControl_MonthList[i];
            opt.value = (i+1).toString();
            if(opt.value==m) opt.selected = true;

        }

    }
    if(dchange)
    {
        var len = this.ctlday.options.length;
        var i;
        for(i=len-1; i>=0; i--) this.ctlday.remove(i);
        for(i=minDay; i<=maxDay; i++)
        {
            var opt = document.createElement("OPTION");
            this.ctlday.options.add(opt);
            opt.text = i.toString();
            opt.value = i.toString();
            if(opt.value==d) opt.selected = true;

        }

    }
}


DateControlObject.prototype.getValue = DateControl_GetValue;
DateControlObject.prototype.getDisplayValue = DateControl_GetDisplayValue;
DateControlObject.prototype.setValue = DateControl_SetValue;
DateControlObject.prototype.getDay = DateControl_GetDay;
DateControlObject.prototype.getMonth = DateControl_GetMonth;
DateControlObject.prototype.getYear = DateControl_GetYear;
DateControlObject.prototype.updateControls = DateControl_UpdateControls;
DateControlObject.prototype.clear = DateControl_ClearValue;
DateControlObject.prototype.focus = DateControl_SetFocus;
DateControlObject.prototype.enable = DateControl_Enable;
DateControlObject.prototype.disable = DateControl_Disable;
DateControlObject.prototype.getProp = function(elem, propname)
    {
        var val;
        eval("val=elem." +  propname + ";");
        if(typeof(val)=="undefined") 
            val = elem.readAttribute(propname);
        return val;        
    } ;

function DateControl_ValueChanged(source, ctlType)
{
    var dtctl = new DateControlObject(source, false);
    if(dtctl.ctlval==null) return;

    dtctl.setValue();
    dtctl.updateControls(ctlType);
    if(dtctl.appearance == "dropdown") DateControl_DdlBlur(source);
    return;
}

function DateControl_CheckNumericIE(source)
{
    var keyCode = window.event.keyCode;
    if((keyCode == 13) || (keyCode == 27)) return true;
    if( keyCode>57 || keyCode<48 ) return false;
    else return true;
}

function DateControl_CheckNumericFirefox(e, source)
{
    var keyCode = e.charCode;
    if(keyCode != 0)
        if( keyCode>57 || keyCode<48 ) e.preventDefault();
}

function DateControl_CheckMaxlength(source, maxl)
{
    if(source.value.length>=maxl) 
        if(maxl==2) source.nextSibling.focus();
        else source.blur();
}

function DateControl_Focus(source)
{
    source.value = "";
    if(source.id.toLowerCase().indexOf("day")>-1) {
        source.nextSibling.value = "";
        source.nextSibling.nextSibling.value = "";
    }
    if(source.id.toLowerCase().indexOf("month")>-1) {
        source.nextSibling.value = "";
    }
    DateControl_ValueChanged(source, "");
    //DateControl_RunValidators(source);
    DateControl_ResetValidators(source);
}

function DateControl_DdlBlur(source)
{
    if(source.id.toLowerCase().indexOf("day")>-1) {
        source.nextSibling.focus();
    }
    else if(source.id.toLowerCase().indexOf("month")>-1) {
        source.nextSibling.focus();
    }
    else if(source.id.toLowerCase().indexOf("year")>-1) {
        source.blur();
    }
    //DateControl_ValueChanged(source, "");
    //DateControl_ResetValidators(source);
}

function DateControl_RunValidators(targetedControl){
    var validators;
    if (typeof(targetedControl.Validators) != "undefined") {
        validators = targetedControl.Validators;
    }
    else {
        if (targetedControl.tagName.toLowerCase() == "label") {
            targetedControl = document.getElementById(targetedControl.htmlFor);
            validators = targetedControl.Validators;
        }
    }
    if ((typeof(validators) != "undefined") && (validators != null)) {
		var ev = window.event;
		if(typeof(ev)=="undefined"){
			ev = document.createEvent("UIEvents");
			ev.initUIEvent("change", true, true, window, 1);
		}
        for (var i = 0; i < validators.length; i++) {
            ValidatorValidate(validators[i], null, ev);
        }
        ValidatorUpdateIsValid();
    }
    return validators;
}

function DateControl_ResetValidators(targetedControl){
    var validators;
    if (typeof(targetedControl.Validators) != "undefined") {
        validators = targetedControl.Validators;
    }
    else {
        if (targetedControl.tagName.toLowerCase() == "label") {
            targetedControl = document.getElementById(targetedControl.htmlFor);
            validators = targetedControl.Validators;
        }
    }
    if ((typeof(validators) != "undefined") && (validators != null)) {
        for (var i = 0; i < validators.length; i++) {
            validators[i].isvalid = true;
            ValidatorUpdateDisplay(validators[i])
        }
    }
    return validators;
}

function DateControl_LoadFromId(controlId){

    if ((typeof(controlId) == "undefined") || (controlId=="")) return;

    var control = document.getElementById(controlId);
    
    if ((typeof(control) == "undefined") || (control == null)) return;
    
    return new DateControlObject(control, true);
}

// Validate date
function RegisterDateFieldValidator(validatorId){
    var validator = document.getElementById(validatorId);
    if(typeof(validator)=="undefined" || validator==null) return;
    if(typeof(validator.altcontroltovalidate)!="string") return;
    var control = document.getElementById(validator.altcontroltovalidate);
    if(control==null) return;
    // TODO: check tagName
    if(typeof(control.addEventListener)=="function") {
        control.addEventListener("blur", DateFieldValidatorHookupEvent(control, "onblur", "DateFieldValidatorValidate(event); "), true); 
        control.addEventListener("focus", DateFieldValidatorHookupEvent(control, "onfocus", "DateFieldValidatorReset(event); "), true); 
    }
    else {
        control.attachEvent("onfocusout", DateFieldValidatorHookupEvent(control, "onblur", "DateFieldValidatorValidate(event); "));
        control.attachEvent("onfocusin", DateFieldValidatorHookupEvent(control, "onfocus", "DateFieldValidatorReset(event); "));
    }
    if (typeof(control.Validators) == "undefined") control.Validators = new Array; 
    control.DtValIdx = control.Validators.length;      
    control.Validators[control.Validators.length] = validator;
    // for compatibility with .NET validation  
    var child = null;
    for (var i = 0; i < control.childNodes.length; i++) {
        var ctl = control.childNodes[i];
        if (typeof(ctl.tagName) != "string") continue;  
        if (ctl.tagName == "INPUT" || ctl.tagName == "TEXTAREA" || ctl.tagName == "SELECT") {
            child = ctl;
            break;
        }    
    }    
    if(child != null) {
        if (typeof(child.Validators) == "undefined") child.Validators = new Array; 
        child.Validators[child.Validators.length] = validator; 
    }   
}

function DateFieldValidatorHookupEvent(control, eventType, functionPrefix) {
    var ev;
    eval("ev = control." + eventType + ";");
    if (typeof(ev) == "function") {
        ev = ev.toString();
        ev = ev.substring(ev.indexOf("{") + 1, ev.lastIndexOf("}"));
    }
    else {
        ev = "";
    }
    var func;
    if (navigator.appName.toLowerCase().indexOf('explorer') > -1) {
        func = new Function(functionPrefix + " " + ev);
    }
    else {
        func = new Function("event", functionPrefix + " " + ev);
    }
   return func;
}

function DateFieldValidatorValidate(event) {
    if (!event) event = window.event;
    Page_InvalidControlToBeFocused = null;
    var targetedControl;
    if ((typeof(event.srcElement) != "undefined") && (event.srcElement != null)) {
        targetedControl = event.srcElement.parentNode;
    }
    else {
        targetedControl = event.target.parentNode;
    }
    var vals;
    if (typeof(targetedControl.Validators) != "undefined") {
        vals = targetedControl.Validators;
    }
    else {
        if (targetedControl.tagName.toLowerCase() == "label") {
            targetedControl = document.getElementById(targetedControl.htmlFor);
            vals = targetedControl.Validators;
        }
    }
    var val = vals[targetedControl.DtValIdx];
    ValidatorValidate(val, null, event);
    ValidatorUpdateDisplay(val);
    ValidatorUpdateIsValid();
}

function DateFieldValidatorReset(event) {
    if (!event) event = window.event;
    Page_InvalidControlToBeFocused = null;
    var targetedControl;
    if ((typeof(event.srcElement) != "undefined") && (event.srcElement != null)) {
        targetedControl = event.srcElement.parentNode;
    }
    else {
        targetedControl = event.target.parentNode;
    }
    var vals;
    if (typeof(targetedControl.Validators) != "undefined") {
        vals = targetedControl.Validators;
    }
    else {
        if (targetedControl.tagName.toLowerCase() == "label") {
            targetedControl = document.getElementById(targetedControl.htmlFor);
            vals = targetedControl.Validators;
        }
    }
    var val = vals[targetedControl.DtValIdx];
    DisplayDateFieldError(val, { IsValid:true });
}

function ExtendedDateFieldValidate(source, clientside_arguments)
{
    clientside_arguments.displayError = false;
    clientside_arguments.IsValid = true;
    
    var initialValue = (typeof(source.initialvalue) == "string") ? source.initialvalue : "";
    var isRequired = (typeof(source.isrequired) == "string") ? source.isrequired.toLowerCase() : "false";
    var ctltovalidate = "";
    if(typeof(source.controltovalidate) == "string") ctltovalidate = source.controltovalidate; 
    if(typeof(source.altcontroltovalidate) == "string") ctltovalidate = source.altcontroltovalidate;
    if(ctltovalidate=="" && clientside_arguments.Value=="") return;
    var req = (isRequired=="true");
    // retrieve value
    var dtctl = null;
    if(ctltovalidate!="") {
        if(ctltovalidate.indexOf("dtYear")>-1) 
            dtctl = new DateControlObject($(ctltovalidate), false);
        else
            dtctl = new DateControlObject($(ctltovalidate), true);
        if(dtctl!=null) { dtctl.setValue(); clientside_arguments.Value = dtctl.getValue(); }
    }
   
    // validate if field is empty
    if(req)
        clientside_arguments.IsValid = (ValidatorTrim(clientside_arguments.Value) != ValidatorTrim(initialValue));
    // date is empty    
    if(!clientside_arguments.IsValid) {DisplayDateFieldError(source, clientside_arguments); return;}
    var arr = clientside_arguments.Value.split("/");
    clientside_arguments.IsValid = (arr.length==3);
    // date is not completed
    if(!clientside_arguments.IsValid) {DisplayDateFieldError(source, clientside_arguments); return;}
    var day = parseInt(arr[1],10);
    clientside_arguments.IsValid = clientside_arguments.IsValid && !isNaN(day);
    var month = parseInt(arr[0],10);
    clientside_arguments.IsValid = clientside_arguments.IsValid && !isNaN(month);
    var year = parseInt(arr[2],10);
    clientside_arguments.IsValid = clientside_arguments.IsValid && !isNaN(year);
    // date input is not valid
    if(!clientside_arguments.IsValid) {DisplayDateFieldError(source, clientside_arguments); return;}
                
    var date = new Date(year, month, day);
    clientside_arguments.IsValid = (typeof(date) == "object" && year == date.getFullYear() && month == date.getMonth() && day == date.getDate());
    // value is not valid date
    if(!clientside_arguments.IsValid) {DisplayDateFieldError(source, clientside_arguments); return;}
    // validate if date is in min-max date range
    var minDate = eval(source.minimumvalue);
    var maxDate = eval(source.maximumvalue);
    if(typeof(minDate)=="object" && typeof(maxDate)=="object") {   
        clientside_arguments.IsValid = (minDate <= date && date <= maxDate);
        clientside_arguments.displayError = !clientside_arguments.IsValid;
    }

    DisplayDateFieldError(source, clientside_arguments);
}

function ExtendedDateFieldValidate2(source, clientside_arguments)
{
    clientside_arguments.displayError = false;
    var initialValue = (typeof(source.initialvalue) == "string") ? source.initialvalue : "";
    var isRequired = (typeof(source.isrequired) == "string") ? source.isrequired.toLowerCase() : "false";
    var req = (isRequired=="true");
    // retrieve value
    var dtctl = null;
    if(source.controltovalidate.indexOf("dtYear")>-1) 
        dtctl = new DateControlObject($(source.controltovalidate), false);
    else
        dtctl = new DateControlObject($(source.controltovalidate), true);
    if(dtctl!=null) { dtctl.setValue(); clientside_arguments.Value = dtctl.getValue(); }
   
    // validate if field is empty
    if(req)
        clientside_arguments.IsValid = (ValidatorTrim(clientside_arguments.Value) != ValidatorTrim(initialValue));
    // date is empty    
    if(!clientside_arguments.IsValid) {DisplayDateFieldError(source, clientside_arguments); return;}
    var arr = clientside_arguments.Value.split("/");
    clientside_arguments.IsValid = (arr.length==3);
    // date is not completed
    if(!clientside_arguments.IsValid) {DisplayDateFieldError(source, clientside_arguments); return;}
    var day = parseInt(arr[1],10);
    clientside_arguments.IsValid = clientside_arguments.IsValid && !isNaN(day);
    var month = parseInt(arr[0],10);
    clientside_arguments.IsValid = clientside_arguments.IsValid && !isNaN(month);
    var year = parseInt(arr[2],10);
    clientside_arguments.IsValid = clientside_arguments.IsValid && !isNaN(year);
    // date input is not valid
    if(!clientside_arguments.IsValid) {DisplayDateFieldError(source, clientside_arguments); return;}
                
    var date = new Date(year, month, day);
    clientside_arguments.IsValid = (typeof(date) == "object" && year == date.getFullYear() && month == date.getMonth() && day == date.getDate());
    // value is not valid date
    if(!clientside_arguments.IsValid) {DisplayDateFieldError(source, clientside_arguments); return;}
    // validate if date is in min-max date range
    var minDate = eval(source.minimumvalue);
    var maxDate = eval(source.maximumvalue);
    if(typeof(minDate)=="object" && typeof(maxDate)=="object") {   
        clientside_arguments.IsValid = (minDate <= date && date <= maxDate);
        clientside_arguments.displayError = !clientside_arguments.IsValid;
    }

    DisplayDateFieldError(source, clientside_arguments);
}

function DisplayDateFieldError(source, clientside_arguments)
{
    var displayError = ((typeof(clientside_arguments.displayError)!="undefined") && (clientside_arguments.displayError==true));
    source.display = (clientside_arguments.displayError && (typeof(source.errormessage)=="string" && source.errormessage.length>0)) ? "Dynamic" : "Hide";
    var labelID = (typeof(source.labelid) == "string") ? source.labelid : "";
    var labelErrorCss = (typeof(source.labelerrorcss) == "string") ? source.labelerrorcss : "";
    var lbl = document.getElementById(labelID);
    if(lbl) 
        clientside_arguments.IsValid ? RemoveCSSClass(lbl, labelErrorCss) : AddCSSClass(lbl, labelErrorCss);
    return;
}
