﻿/// <reference path="lib_core_controls.js"/>

// The ValidationResult may need to contain other ValidationResults.
// Eg when subcontrols do not validate, causing a control not to validate.
// Then need to get the fields that were not filled in correctly and show them to the user.

// Validation will get changed and upgraded a bit.

ValidationResult = function(options) {
    this.options = options;
    this.init(0);
}
var p = ValidationResult.prototype;
p.init = function(depth) {
    if (!this.options) this.options = new Object();
    this.validationResults = new Array();
}
p.add = function(/* ValidationResult */ value) {
    if (!value.isValid) {
        alert ('no isValid');
        value.dfsa.fdsaf.dfsa;
    }
    this.validationResults.push(value);
}
p.isValid = function() {
    if (this.options.isValid == false) return false;
    var res = true;
    var c = 0;
    while (c < this.validationResults.length && res == true) {
        // why would a validationResults not have an isValid() method?
        
        if (!this.validationResults[c].isValid()) res = false;
        c++;
    }
    return res;
}
p.getLeaves = function() {
    // recursive function.
    var res = new Array();
    this.getLeaves2(res);
    return res;
}
p.getLeaves2 = function(res) {
    if (this.validationResults.length == 0) res.push(this);
    for (var c = 0; c < this.validationResults.length; c++) {
        this.validationResults[c].getLeaves2(res);
    }
}

ValidationErrorsDisplay = function(container, options) {
    this.container = container;
    this.options = options;
    this.init(0);
}
var p = ValidationErrorsDisplay.prototype;
p.inheritFrom(CDiv);
p.init = function(depth) {
    this.superInit(depth);
    
    
    
    this.setClass('ValidationErrorsDisplay');
    
    //if (this.options
    // only make it visible if there are validation errors.
    
    
    this.addMyEl();
}
p.setValidationErrors = function(value) {
    // an array of validation errors.
    this.validationErrors = value;
    // then update the display.
    //this.el.innerHTML = '';
    
    var strValidationErrors = '';
    
    if (this.validationErrors.length > 0) {
        this.show();
    } else {
        this.hide();
    }
    
    for (var c = 0; c < this.validationErrors.length; c++) {
        var errorDivHtml = this.validationErrors[c].getErrorDivHtml();
        strValidationErrors = strValidationErrors + errorDivHtml;
    }
    
    //alert ('strValidationErrors ' + strValidationErrors);
    
    this.setInnerHTML(strValidationErrors);
    
}
p.setValidationResults = function(value) {
    //
    this.options.validationResults = value;
    // then display the validation results.
    // get the leaf validation results.
    
    var leaves = value.getLeaves();
    //alert ('leaves ' + leaves);
    //alert ('leaves.length ' + leaves.length);
    
    // make a ul for them
    
    var invalidLeafNames = '<ul>';
    
    for (var c = 0; c < leaves.length; c++) {
        var leaf = leaves[c];
        //alert ('leaf.options.fieldName ' + leaf.options.fieldName + ', leaf.options.isValid ' + leaf.options.isValid);
        if (!leaf.options.isValid) {
            //if (invalidLeafNames.length > 0) invalidLeafNames = invalidLeafNames + ', ';
            invalidLeafNames = invalidLeafNames + '<li>' + leaf.options.fieldName.replace(':', '') + '</li>';
        }
    }
    invalidLeafNames = invalidLeafNames + '</ul>';
    
    //alert ('invalidLeafNames ' + invalidLeafNames);
    this.setInnerHTML ('The following fields are not correct: ' + invalidLeafNames);
    
}



// options: labelText, 
// also include questionMarkText option

// Will probably use Field which includes the label.
// Will be substantially changed internally.

TextField = function(container, options) {
    this.container = container;
    this.options = options;
    //this.labelText = labelText;
    //this.rxValidation = rxValidation;
    //this.isRequired = isRequired;
    this.init(0);
}
var p = TextField.prototype;
p.inheritFrom(CDiv);
p.init = function(depth) {
    //alert('textField');
    this.superInit(depth);
    //var d = this.div;
    //var d = this.createMyDiv();
    this.value = '';
    this.uid = UID();
    
    var strVF = '';
    if (this.options.isRequired) strVF = '<span class="validationFailure">*</span>';
    
    var o = new Object();
    
    // replace labelText with fieldName
    o.text = this.options.labelText + strVF;
    //alert ('this.options.labelWidth ' + this.options.labelWidth);
    if (this.options.labelWidth) {
        o.width = this.options.labelWidth;
        
    } else {
        if (!this.options.itemPadding) {
            this.options.itemPadding = 12;
        }
        o.margin = '0 ' + toPx(this.options.itemPadding) + ' 0 0';
        //alert ('o.margin ' + o.margin);
    }
    
    o.cssFloat = 'left';
    this.cdLabel = new CDLabel(this, o);
    
//    var cdlo = new Object();
//    cdlo.text = this.options.labelText;
//    cdlo.cssFloat = 'left';
    //this.cdLabel = new CDLabel(this, o);

    this.textBox = new TextBox(this);
    this.textBox.onchange = function() {this.container.textBox_onchange(); return false; }
    
    if (this.options.questionMarkText) {
        //setFloat(this.textBox('left'));
        this.textBox.setFloat('left');
        //alert ('questionMarkText ' + this.options.questionMarkText);
        this.questionMark = new QuestionCircle(this, {'text': this.options.questionMarkText});
        this.questionMark.setFloat('left');
    }
    
    // could put the validation success / failure to left of the textbox.
    
    var spnValidationError = nS('*');
    spnValidationError.style.display = 'none';
    setClass(spnValidationError, 'validationFailure');
    this.spnValidationError = spnValidationError;
    this.el.appendChild(spnValidationError);
    
    // then include the question mark if there is a qustionMarkText option.
    
    
    
    var cdc = new CDClear(this);
    
    this.setClass('TextField');
    this.addMyDiv();
}
p.textBox_onchange = function() {
    this.value = this.textBox.value;
}
p.getValue = function() {
    return this.textBox.getValue();
}
p.setValue = function(value) {
    //alert('value ' + value);
    this.textBox.setValue(value);
}
p.validate = function() {
    // should return ValidationResult object.
    //  will include the name of the field
    
    var isValid = this.isValid();
    if (isValid) {
        //this.spnValidationError.style.display = 'none';
    } else {
        //this.spnValidationError.style.display = 'inline';
    }
    var res = new ValidationResult({'isValid': isValid, 'fieldName': this.options.labelText});
    
    return res;
}
p.isValid = function() {
    // true/false, does not return ValidationResult.
    if (this.options.isRequired) {
        var val = this.getValue()
        if (val.length > 0) {
            
        } else {
            return false;
        }
    }
    
    if (!this.rxValidation) return true;
    return this.value.match(this.rxValidation);
}
p.t_onchange = function(value) {
    this.value = value;
}

// Will do basically the same thing

SortCodeField = function(container, options) {
    this.container = container;
    this.options = options;
    this.init(0);
}
var p = SortCodeField.prototype;
p.inheritFrom(CDiv);
p.init = function() {
    this.superInit(0);
    this.setClass('SortCodeField');
    this.uid = UID();
    
    var strVF = '';
    if (this.options.isRequired) strVF = '<span class="validationFailure">*</span>';
    
    var o = new Object();
    o.text = 'Sort Code:' + strVF;
    //alert ('this.options.labelWidth ' + this.options.labelWidth);
    if (this.options.labelWidth) {
        o.width = this.options.labelWidth;
        
    } else {
        if (!this.options.itemPadding) {
            this.options.itemPadding = 12;
        }
        o.margin = '0 ' + toPx(this.options.itemPadding) + ' 0 0';
        //alert ('o.margin ' + o.margin);
    }
    
    o.cssFloat = 'left';
    this.cdLabel = new CDLabel(this, o);
    
    // __ - __ - __
    this.tb1 = new CDTextBox(this, {'cssFloat': 'left', 'width': 40, 'maxLength': 2});
    //this.tb1 = new CDTextBox(this, {'cssFloat': 'left', 'width': 40});
    this.cdSep1 = new CDiv(this, {'cssFloat': 'left', 'width': 14, 'marginLeft': '8px'});
    this.cdSep1.setInnerHTML('-');
    this.tb2 = new CDTextBox(this, {'cssFloat': 'left', 'width': 40, 'maxLength': 2});
    //this.tb2 = new CDTextBox(this, {'cssFloat': 'left', 'width': 40});
    this.cdSep2 = new CDiv(this, {'cssFloat': 'left', 'width': 14, 'marginLeft': '8px'});
    this.cdSep2.setInnerHTML('-');
    this.tb3 = new CDTextBox(this, {'cssFloat': 'left', 'width': 40, 'maxLength': 2});
    //this.tb3 = new CDTextBox(this, {'cssFloat': 'left', 'width': 40});
    
    this.tb1.options.nextControl = this.tb2;
    this.tb2.options.nextControl = this.tb3;
    
//    this.tb1 = new CDTextBox(this, {'cssFloat': 'left'});
//    //this.cdSep1 = new CDiv(this, {'cssFloat': 'left', 'width': 19, 'marginLeft': '12px'});
//    //this.cdSep1.setInnerHTML('-');
//    this.tb2 = new CDTextBox(this, {'cssFloat': 'left'});
//    //this.cdSep2 = new CDiv(this, {'cssFloat': 'left', 'width': 19, 'marginLeft': '12px'});
//    //this.cdSep2.setInnerHTML('-');
//    this.tb3 = new CDTextBox(this, {'cssFloat': 'left'});
    
    
    this.addMyEl();
}
p.getValue = function(includeDashes) {
    var res;
    if (includeDashes) {
        res = this.tb1.getValue() + '-' + this.tb2.getValue() + '-' + this.tb3.getValue();
    } else {
        res = this.tb1.getValue() + this.tb2.getValue() + this.tb3.getValue();
    }
    return res;
}

// this should have the validation of the DropDownList.
// Perhaps this could inherit from DropDownList too (even though its rendering is substantially different).
DropDownListField = function(container, options, items) {
    this.container = container;
    this.options = options;
    this.items = items;
    this.init(0);
}
var p = DropDownListField.prototype;
p.inheritFrom(CDiv);
p.init = function(depth) {
    this.superInit(depth);
    
    var strVF = '';
    if (!this.options.defaultValue) this.options.defaultValue = 0;
    if (!this.options.cssClass) this.setClass('DropDownListField');
    if (this.options.isRequired) strVF = '<span class="validationFailure">*</span>';
    
    var o = new Object();
    o.text = this.options.labelText + strVF;
    //alert ('this.options.labelWidth ' + this.options.labelWidth);
    
    // padding should only / mostly be done with the CSS classes.
    
    if (this.options.labelWidth) {
        o.width = this.options.labelWidth;
        
    } else {
        //if (!this.options.itemPadding) {
        //    this.options.itemPadding = 12;
        //}
        //o.margin = '0 ' + toPx(this.options.itemPadding) + ' 0 0';
        //alert ('o.margin ' + o.margin);
    }
    
    o.cssFloat = 'left';
    
    // then if it is mandatory, add the red *
    
    this.cdLabel = new CDLabel(this, o);
    // make it automatically float.
    
    var ddlo = new Object();
    ddlo.items = this.items;
    
    if (this.options.ddlWidth) ddlo.width = this.options.ddlWidth;
    
    this.dropDownList = new DropDownList(this, ddlo);
    //this.dropDownList.render();
    this.dropDownList.onchange = function() { this.container.dropDownList_onchange(); return false; }
    this.addMyEl();
}
p.validate = function() {
    //alert ('validate');
    
    var isValid = true;

    var res = new ValidationResult({'fieldName':this.options.labelText});
    
    
    if (this.getValue() == this.options.defaultValue) isValid = false;
    
    res.options.isValid = isValid;
    return res;
    
}
p.isValid = function() {
    var isValid = true;
    
    //alert('this.getValue() ' + this.getValue());
    //alert('this.options.defaultValue ' + this.options.defaultValue);
    
    if (this.getValue() == this.options.defaultValue) isValid = false;
    return isValid;
}

p.getValue = function() {
    return this.dropDownList.getValue();
}
p.render = function() {
    this.dropDownList.render();
}
p.dropDownList_onchange = function() {
    //alert ('dropDownListWithMore_onchange ');
    this.value = this.el.value;
    if (this.onchange) {
        this.onchange();
    }
}


// This probably will not be used.
// This needs to properly do the margins / spacing.

DropDownListWithMoreField = function(container, options) {
    this.container = container;
    this.options = options;
    this.init(0);
}
var p = DropDownListWithMoreField.prototype;
p.inheritFrom(CDiv);
p.init = function(depth) {
    this.superInit(depth);
    this.value = '';
    this.uid = UID();
    this.setClass('DropDownListWithMoreField');
    // have both a textbox and the DropDownListWithMore
    
    // calculate the right margin of the CDLabel according to the itemPadding of this.
    var sMargin = '';
    if (this.options.itemPadding) sMargin = '0 ' + toPx(this.options.itemPadding) + ' 0 0 0';
    
    var oLabel = {'text':this.options.labelText, 'margin': sMargin, 'cssFloat': 'left'};
    if (this.options.labelWidth) oLabel.width = this.options.labelWidth;
   
    
    this.cdLabel = new CDLabel(this, oLabel);

    // should not use the same options.
    var oddlm = new Object();
    // the dropdownlist needs to have a margin to its left.
    if (!this.options.itemPadding) {
        //this.options.itemPadding = 10;
        // should probably be done using external CSS.
        this.options.itemPadding = 0;
    }
    oddlm.margin =  '0 0 0 ' + toPx(this.options.itemPadding);
    oddlm.ddlWidth = 60;
    oddlm.cssFloat = 'left';
    if (this.options.editorWidth) oddlm.width = this.options.editorWidth;
    this.dropDownListWithMore = new DropDownListWithMore(this, oddlm);
    this.dropDownListWithMore.onchange = function() { this.container.dropDownListWithMore_onchange(); return false; }
    
    
    this.cdc = new CDClear(this);
}
p.validate = function() {
    // validate the DropDownListWithMore
    return this.dropDownListWithMore.validate();
}
p.clear = function() {
    this.dropDownListWithMore.clear();
}

p.getValue = function() {
    return this.dropDownListWithMore.getValue();
}
p.setValue = function(value) {
    return this.dropDownListWithMore.setValue(value);
}
p.setComboBoxWidth = function(value) {
    this.dropDownListWithMore.setComboBoxWidth(value);
}
p.dropDownListWithMore_onchange = function() {
    //alert ('dropDownListWithMore_onchange ');
    this.value = this.el.value;
    if (this.onchange) {
        this.onchange();
    }
}

// options: 
YesNoRadioField = function(container, options) {
    this.container = container;
    this.options = options;
    this.init(0);
}
var p = YesNoRadioField.prototype;
p.inheritFrom(CDiv);
p.init = function(depth) {
    this.superInit(depth);
    //this.setClass('YesNoRadioField');
    
    if (this.options.cssClass) {
        this.setClass(this.options.cssClass);
    } else {
        this.setClass('YesNoRadioField');
    }
    
    // Include a RadioButtonMenu
    
    this.cdLabel = new CDLabel(this, {'text':this.options.labelText, 'cssClass':'Label'});
    this.cdLabel.setFloat('left');
    
    // need to put a margin between the label and the radiobuttonmenu.
    // perhaps a 'virtual' spacing box could do the job - the margin-left style gets set on the RadioButonMenu.
    
    var o = new Object();
    o.repeatDirection = 'horizontal';
    o.itemPadding = 10;
    o.isRequired = this.options.isRequired;
    var items = new Array();
    // need to set the correct selected item/
    
    items.push(new AOption({'text':'Yes', 'value':true}));
    items.push(new AOption({'text':'No', 'value':false}));
    
    if (this.options.value == true) {
        //alert ('this.options.value ' + this.options.value);
        items[0].options.selected = true;
    }
    
    // the radio button menu could have 'is required' validation.
    // it would also have the span that shows the validation error (default *).
    
    // The styling should be set in a CSS file.
    
    this.rbm = new RadioButtonMenu(this, o, items);
    //this.rbm.setStyle('marginLeft', '12px');
    //this.rbm.setStyle('float', 'left');
    this.rbm.onchange = function() { return this.container.rbm_onchange(); }
    this.rbm.onclick = function() { return this.container.rbm_onclick(); }
    this.rbm.render();
    
    var ca = new CDClear(this);
    
    this.addMyEl();
}
p.render = function() {
    this.rbm.render();
}
p.validate = function() {
    var res = true;
    //if (this.options.isRequired) {
    //    res = this.hasValue();
    //}
    res = this.rbm.validate();
    
    return res;
}
p.hasValue = function() {
    var i = this.rbm.getSelectedItem();
    return (i != null);
}
p.setValue = function(value) {
    return this.rbm.setSelectedValue(value);
}
p.getValue = function() {
    // if none are selected return null
    //return this.rbm.getSelectedValue();
    var res = this.rbm.getValue()
    //alert ('res ' + res);
    return res;
}
p.rbm_onchange = function() {
    //alert ('rbm_onchange');
    
    if (this.onchange) return this.onchange();
}
p.rbm_onclick = function() {
    //alert ('rbm_onclick');
    
    //if (this.onchange) this.onchange();
    
    if (this.onclick) return this.onclick();
}
