﻿var GROUP_MEMBERSHIP = "Group Membership";
//  <DefinitionRules name="Basic Application">
//    <operator name="AND">
//      <attribute DefinitionAttributeID="c4c7ef37-761c-4add-8019-bc244001c9d4">
//        <criteria operator="AdHoc">
//          <values>
//            <value type="System.DateTime">6/23/2006 12:00:00 AM</value>
//            <value type="System.DateTime">6/23/2006 11:59:59 PM</value>
//          </values>
//        </criteria>
//      </attribute>
//      <group GroupID="c4c7ef37-761c-4add-8019-bc244001c9d4">
//      </group>
//    </operator>
//  </DefinitionRules>
//  <DefinitionRuleActions>
//    <DefinitionRuleAction propertyName='Enabled' propertyValue='true' />
//  </DefinitionRuleActions>
//</DefinitionRuleSet>


function RuleSet()
{
    this.ruleLogicalNode = null;
    this.ruleActions = new Array();
    this.activeRuleAction = null;

}
RuleSet.prototype.getFieldValues = function(definitionDisplayLayoutControl)
{
    var existingValues = [];
    var neededKeys = [];
    this.ruleLogicalNode.getFieldValues(definitionDisplayLayoutControl, existingValues, neededKeys);
    return { existingValues: existingValues, neededKeys: neededKeys };
}
RuleSet.prototype.evaluate = function(definitionDisplayLayoutControl, processErrors)
{
    var fieldValues = this.getFieldValues(definitionDisplayLayoutControl);

    if(fieldValues.neededKeys.length > 0)
    {
        var context = { fieldValues: fieldValues, definitionDisplayLayoutControl: definitionDisplayLayoutControl, processErrors: processErrors, ruleSet: this }
        Datatel.ActiveCampus.Services.EntityRetrievalService.RetrieveEntityValues(definitionDisplayLayoutControl.extendedObjectVersionID, fieldValues.neededKeys, this.retrieveEntityValuesCallback, this.retireveEntityValuesErrorCallback, context);
    }
    else
    {
        this.evaluateWithFieldValues(fieldValues, definitionDisplayLayoutControl, processErrors);
    }
}
RuleSet.prototype.retrieveEntityValuesCallback = function(result, userContext)
{
    for(p in result)
    {
        userContext.fieldValues.existingValues[result[p].Key] = result[p].Value;
    }

    userContext.ruleSet.evaluateWithFieldValues(userContext.fieldValues, userContext.definitionDisplayLayoutControl, userContext.processErrors);
}
RuleSet.prototype.retireveEntityValuesErrorCallback = function FailedCallback(error, userContext)
{
}
RuleSet.prototype.evaluateWithFieldValues = function(fieldValues, definitionDisplayLayoutControl, processErrors)
{
    var result = this.ruleLogicalNode.evaluate(definitionDisplayLayoutControl, fieldValues);

    definitionDisplayLayoutControl.formRuleLogger.log('Rule set evaluated to ' + result);

    for(var index = 0;index < this.ruleActions.length;index++)
    {
        var logText = 'Running rule action ' + index + ': ';
        if(this.ruleActions[index] != undefined)
        {
            logText = logText + 'Target: ' + this.ruleActions[index].propertyTarget + '  Property: ' + this.ruleActions[index].propertyName + '  Value: ' + this.ruleActions[index].propertyValue;
        }
        definitionDisplayLayoutControl.formRuleLogger.log(logText);
        this.ruleActions[index].executeRuleAction(definitionDisplayLayoutControl, !result, processErrors);
    }
}
RuleSet.prototype.validate = function(formView)
{
    formView.htmlPageErrors.length = 0;
    if(this.ruleActions.length == 0)
        formView.addHtmlError("Please apply atleast one action.")
    else
    {
        for(var index = 0;index < this.ruleActions.length;index++)
            this.ruleActions[index].validate(formView);
    }
    if(this.ruleLogicalNode == null)
        formView.addHtmlError("Please specify a rule.");
    this.ruleLogicalNode.validate(formView);
}
RuleSet.prototype.buildFromXml = function(rulesetXml, evaluateRules)
{
    var xmlDoc = GetXmlParser();
    LoadXml(xmlDoc, unescape(rulesetXml));
    this.buildFromXmlNode(xmlDoc, evaluateRules);
}
RuleSet.prototype.buildFromXmlNode = function(xmlDoc)
{
    var ruleNodes = xmlDoc.getElementsByTagName("DefinitionRules");
    if(ruleNodes.length > 0)
    {
        var ruleNode = ruleNodes[0];
        var logicalNode = ruleNode.childNodes[0];
        this.ruleLogicalNode = new RuleLogicalNode(GetAttributeValue(logicalNode, 'name'), this);
        this.ruleLogicalNode.buildFromXml(logicalNode);
    }
    var actionNodes = xmlDoc.getElementsByTagName("DefinitionRuleAction");

    for(var index = 0;index < actionNodes.length;index++)
    {
        this.ruleActions.push(new RuleAction(GetAttributeValue(actionNodes[index], 'propertyName'), GetAttributeValue(actionNodes[index], 'propertyValue'), unescape(GetAttributeValue(actionNodes[index], 'propertyTarget'))));
    }
}
RuleSet.prototype.buildRuleString = function()
{
    var ruleString = "If <br> &nbsp;&nbsp;"
    ruleString += this.ruleLogicalNode.buildRuleString();
    ruleString += "<br>"
    ruleString += "Then "
    for(var index = 0;index < this.ruleActions.length;index++)
    {
        ruleString += "<li>" + this.ruleActions[index].buildRuleString() + "</li>";
    }
    +""
    return ruleString;
}
RuleSet.prototype.wireEventHandlers = function(definitionDisplayLayoutControl)
{
    this.ruleLogicalNode.wireEventHandler(definitionDisplayLayoutControl);
}
RuleSet.prototype.buildXml = function()
{
    var markup = "<DefinitionRuleSet>";
    markup += "<DefinitionRules>"
    if(this.ruleLogicalNode)
        markup += this.ruleLogicalNode.buildXml();
    markup += "</DefinitionRules>";
    markup += "<DefinitionRuleActions>";
    for(var index = 0;index < this.ruleActions.length;index++)
        markup += this.ruleActions[index].buildXml();
    markup += "</DefinitionRuleActions>";
    markup += "</DefinitionRuleSet>";
    return markup;
}

function ParenthesesNode(parent)
{
    this.parent = parent;
    this.children = new Array();
    this.isParenthesesNode = true;
}
ParenthesesNode.prototype.swapConditionalNodes = function()
{
    if(this.children.length == 1 && this.children[0].isConditionalNode)
    {
        var myIndex = GetIndex(this.parent.children, this);
        this.parent.children[myIndex] = this.children[0];
        var me = this;
        me = null;
    }
    else
    {
        for(var index = 0;index < this.children.length;index++)
        {
            if(this.children[index].isParenthesesNode)
                this.children[index].swapConditionalNodes();
        }
    }
}
ParenthesesNode.prototype.swapLogicalNodes = function()
{
    var newParent = null;
    for(var index = 0;index < this.children.length;index++)
    {
        if(this.children[index].isLogicalNode)
        {
            if(!newParent)
                newParent = this.children.splice(index, 1)[0];
            else
            {
                if(this.children[index].operator != newParent.operator)
                    alert("Warning : You have more than 1 logical operators (AND/OR) at the same level. Only the first logical opeartor has been used. Please enclose your expressions in parentheses appropriately. For example, (X AND Y OR Z) cannot be deterministically evaluated, but ((X AND Y) OR Z) can.")
                this.children.splice(index, 1);
            }
        }
    }
    if(!newParent)
        newParent = new RuleLogicalNode("AND", this);
    if(this.parent && this.parent.children)
    {
        var myIndex = GetIndex(this.parent.children, this);
        this.parent.children[myIndex] = newParent;
    }

    for(var index = 0;index < this.children.length;index++)
        if(this.children[index].isParenthesesNode)
            newParent.logicalNodes.push(this.children[index].swapLogicalNodes());

    for(var index = 0;index < this.children.length;index++)
        if(this.children[index].isConditionalNode)
            newParent.conditionalNodes.push(this.children[index]);
    return newParent;
}
function RuleLogicalNode(operator, parent)
{
    this.parent = parent;
    this.operator = operator;
    this.conditionalNodes = new Array();
    this.logicalNodes = new Array();
    this.isLogicalNode = true;
}
RuleLogicalNode.prototype.validate = function(formView)
{
    var nodes = this.logicalNodes.concat(this.conditionalNodes);
    for(var index = 0;index < nodes.length;index++)
        nodes[index].validate(formView);
    if(this.conditionalNodes.concat(this.logicalNodes).length == 0)
        formView.addHtmlError("Please enter a rule.");
}
RuleLogicalNode.prototype.buildFromXml = function(parentNode)
{
    for(var nodeIndex = 0;nodeIndex < parentNode.childNodes.length;nodeIndex++)
    {
        var xmlNode = parentNode.childNodes[nodeIndex];
        if(xmlNode.tagName == "attribute") //conditional node
        {
            var fieldName = GetAttributeValue(xmlNode, 'name');
            var criteriaNodes = xmlNode.getElementsByTagName("criteria")
            var ruleOperator = unescape(GetAttributeValue(criteriaNodes[0], 'operator'));
            var subField = GetAttributeValue(criteriaNodes[0], 'field');

            var valueNodes = xmlNode.getElementsByTagName("value");
            var values = new Array();
            for(var index = 0;index < valueNodes.length;index++)
                values.push(GetInnerText(valueNodes[index]));

            var conditionalLogicalNode = new RuleConditionalNode(fieldName, ruleOperator, values, subField);
            this.conditionalNodes.push(conditionalLogicalNode);
        }
        else if(xmlNode.tagName == "operator")
        {
            var ruleLogicalNode = new RuleLogicalNode(GetAttributeValue(xmlNode, 'name'), this);
            this.logicalNodes.push(ruleLogicalNode);
            ruleLogicalNode.buildFromXml(xmlNode);
        }
    }
}
RuleLogicalNode.prototype.buildRuleString = function()
{
    var nodes = this.logicalNodes.concat(this.conditionalNodes);
    var ruleString = " (";
    for(var index = 0;index < nodes.length;index++)
    {
        ruleString += nodes[index].buildRuleString();
        if(index != (nodes.length - 1))
            ruleString += " " + this.operator + " ";
    }
    ruleString += ") ";
    return ruleString;
}
RuleLogicalNode.prototype.wireEventHandler = function(definitionDisplayLayoutControl)
{
    for(var index = 0;index < this.conditionalNodes.length;index++)
        this.conditionalNodes[index].wireEventHandler(definitionDisplayLayoutControl);

    for(index = 0;index < this.logicalNodes.length;index++)
        this.logicalNodes[index].wireEventHandler(definitionDisplayLayoutControl);
}

RuleLogicalNode.prototype.buildXml = function()
{
    var markup = "<operator name='" + this.operator + "'>";
    var nodes = this.logicalNodes.concat(this.conditionalNodes);
    for(var index = 0;index < nodes.length;index++)
        markup += nodes[index].buildXml();
    markup += "</operator>";
    return markup;
}
RuleLogicalNode.prototype.getFieldValues = function(definitionDisplayLayoutControl, existingValues, neededKeys)
{
    var nodes = this.logicalNodes.concat(this.conditionalNodes);
    for(var index = 0;index < nodes.length;index++)
    {
        nodes[index].getFieldValues(definitionDisplayLayoutControl, existingValues, neededKeys);
    }
}
RuleLogicalNode.prototype.evaluate = function(definitionDisplayLayoutControl, fieldValues)
{
    var nodes = this.logicalNodes.concat(this.conditionalNodes);
    if(this.operator == 'AND')
    {
        for(var index = 0;index < nodes.length;index++)
            if(!nodes[index].evaluate(definitionDisplayLayoutControl, fieldValues))
                return false;
        return true;
    }
    else if(this.operator == "OR")
    {
        for(var index = 0;index < nodes.length;index++)
            if(nodes[index].evaluate(definitionDisplayLayoutControl, fieldValues))
                return true;
        return false;
    }
}
function RuleConditionalNode(fieldName, operator, values, subField)
{
    this.isConditionalNode = true;
    this.fieldName = fieldName;
    this.subField = (subField ? subField : "");
    this.ruleOperator = new RuleOperator(operator, values);
}
RuleConditionalNode.prototype.buildRuleString = function()
{
    var htmlDocument;
    if(window.opener.currentHtmlDocument)
        htmlDocument = window.opener.currentHtmlDocument;
    else
        htmlDocument = currentHtmlDocument;

    var ruleString = "";
    ruleString += "[" + this.fieldName + ((this.subField != "") ? "." + this.subField : "") + "]";
    ruleString += " " + this.ruleOperator.operator + " \"";
    var isList = false;

    var listID = currentDefinitions[0].getFieldbyName(this.fieldName).listID;
    if(listID && listID.length > 0 && htmlDocument.loadedLists[listID])
    {
        isList = true;
    }

    for(var index = 0;index < this.ruleOperator.values.length;index++)
    {
        if(isList)
        {
            var listMember = htmlDocument.loadedLists[listID].findListMember(this.ruleOperator.values[index]);
            if(listMember)
            {
                ruleString += htmlDocument.loadedLists[listID].findListMember(this.ruleOperator.values[index]).text;
            }
            else
            {
                ruleString += this.ruleOperator.values[index].replace(",", "\\,");
            }
        }
        else
        {
            ruleString += this.ruleOperator.values[index].replace(",", "\\,");
        }
        if(index != (this.ruleOperator.values.length - 1))
            ruleString += ", ";
    }
    ruleString += "\""
    return ruleString;
}
RuleConditionalNode.prototype.buildXml = function()
{
    var markup = "<attribute name='" + this.fieldName + "'>"
    markup += "<criteria operator='" + escape(this.ruleOperator.operator) + "' " + ((this.subField != "") ? "field='" + this.subField + "'" : "") + ">"
    markup += "<values>"
    for(var index = 0;index < this.ruleOperator.values.length;index++)
        markup += "<value>" + this.ruleOperator.values[index] + "</value>"
    markup += "</values>"
    markup += "</criteria>"
    markup += "</attribute>"
    return markup;
}
RuleConditionalNode.prototype.validate = function(formView)
{
    if(this.fieldName != GROUP_MEMBERSHIP && formView.getControlCountByName(this.fieldName, true) != 1)
        formView.addHtmlError("Form rule references field '" + this.fieldName + "' that does not exist on the form.");
}

RuleConditionalNode.prototype.wireEventHandler = function(definitionDisplayLayoutControl)
{
    if(this.fieldName != GROUP_MEMBERSHIP)
    {
        var field = definitionDisplayLayoutControl.getField(this.fieldName);
        if(field != null)
            definitionDisplayLayoutControl.getField(this.fieldName).wireEventHandler(this.subField);
    }
}
RuleConditionalNode.prototype.getFieldValues = function(definitionDisplayLayoutControl, existingValues, neededKeys)
{
    if(this.fieldName == GROUP_MEMBERSHIP)
    {
        existingValues[this.fieldName] = definitionDisplayLayoutControl.groups;
    }
    else
    {
        var field = definitionDisplayLayoutControl.getField(this.fieldName);
        if(field == null)
        {
            neededKeys.push(this.fieldName);
        }
        else
        {
            existingValues[this.fieldName] = field.getFieldValue(this.subField);
        }
    }
}
RuleConditionalNode.prototype.evaluate = function(definitionDisplayLayoutControl, fieldValues)
{
    var fieldValue = "";
    var result = null;

    if(this.fieldName == GROUP_MEMBERSHIP)
    {
        fieldValue = definitionDisplayLayoutControl.groups;
    }
    else if(fieldValues)
    {
        fieldValue = fieldValues.existingValues[this.fieldName];
    }
    else
    {
        var field = definitionDisplayLayoutControl.getField(this.fieldName);
        fieldValue = field.getFieldValue(this.subField);
    }

    result = this.ruleOperator.evaluate(fieldValue);

    definitionDisplayLayoutControl.formRuleLogger.log('Result ' + result + ' for field ' + this.fieldName + ' value ' + fieldValue + ' ' + this.ruleOperator.operator + ' ' + this.ruleOperator.values);

    return result;
}

function RuleOperator(operator, values)
{
    this.operator = operator.toUpperCase();
    this.values = new Array();
    for(var index = 0;index < values.length;index++)
        this.values.push(values[index])
}

RuleOperator.prototype.evaluate = function(obj)
{
    //checkbox with multiples -  just do in for equals
    var operator = this.operator;
    if(operator == "MEMBER OF") operator = "IN";
    if(operator == "NOT MEMBER OF") operator = "NOT IN";
    if(obj)
    {
        if(obj.push && operator == "=") operator = "IN";
        if(!obj.push && (operator == "NOT IN" || operator == "IN"))
        {
            var newObj = new Array();
            newObj.push(obj);
            obj = newObj;
        }
    }
    if(operator == "=")
        return (obj == this.values[0])
    else if(operator == "<>" || operator == "!=")
        return (obj != this.values[0])
    else if(operator == "<" || operator == "LESS THAN")
        return (obj < this.values[0])
    else if(operator == ">" || operator == "GREATER THAN")
        return (obj > this.values[0])
    else if(operator == "<=" || operator == "LESS THAN EQUALS")
        return (obj <= this.values[0])
    else if(operator == ">=" || operator == "GREATER THAN EQUALS")
        return (obj >= this.values[0])
    else if(operator == "LIKE")
        return (obj.toLowerCase().substring(this.values[0].toLowerCase()) == 0)
    else if(operator == "IN")
    {
        if(obj && obj.push)
        {
            for(var index = 0;index < this.values.length;index++)
                for(var index1 = 0;index1 < obj.length;index1++)
                    if(Trim(this.values[index]) == Trim(obj[index1].toString()))
                        return true;
        }
        return false;
    }
    else if(operator == "NOT IN")
    {
        if(obj && obj.push)
        {
            for(var index = 0;index < this.values.length;index++)
                for(var index1 = 0;index1 < obj.length;index1++)
                    if(Trim(this.values[index]) == Trim(obj[index1].toString()))
                        return false;
        }
        return true;
    }
    else if(operator == "BETWEEN")
        return (this.values[0] <= obj) && (obj <= this.values[1]);
    else
    {
        return new DateSpan(operator).evaluate(obj, this.values)
    }
}
/*

*/
function RuleAction(propertyName, propertyValue, propertyTarget)
{
    this.propertyName = propertyName;
    this.propertyValue = propertyValue;
    this.propertyTarget = propertyTarget;
}
RuleAction.prototype.buildRuleString = function()
{
    return "Set '" + this.propertyName + "' of " + this.propertyTarget + " to '" + this.propertyValue + "'";
}
RuleAction.prototype.validate = function(formView)
{
    if(!formView.getControlCountByName(this.propertyTarget, true))
        formView.addHtmlError("Invalid target name '" + this.propertyTarget + "' referenced in action : '" + this.buildRuleString() + "'");
}

RuleAction.prototype.buildXml = function()
{
    return "<DefinitionRuleAction propertyName='" + this.propertyName + "' propertyTarget='" + escape(this.propertyTarget) + "' propertyValue='" + this.propertyValue + "' />";
}


RuleAction.prototype.executeRuleAction = function(definitionDisplayLayoutControl, reverseAction, processError)
{
    /* TODO - this method, getField, takes a good second in IE for WIU */
    var field = definitionDisplayLayoutControl.getField(this.propertyTarget);
    if(!field)
        return; // field not found, probably on another page.

    var targetDiv = field.domField;

    definitionDisplayLayoutControl.formRuleLogger.log('Rule action for ' + this.propertyTarget + '  DOM id: ' + targetDiv.id + '  Property: ' + this.propertyName + '  Value: ' + !reverseAction);
    if(this.propertyName == "Visible")
    {
        var visibility = reverseAction ? this.propertyValue != "true" : this.propertyValue == "true";
        targetDiv.style.display = visibility ? "block" : "none";
        definitionDisplayLayoutControl.formRuleLogger.log('Result for ' + this.propertyTarget + ' is that property ' + this.propertyName + ' is now Display=' + targetDiv.style.display);
    }
    else if(this.propertyName == "Required")
    {
        targetDiv.required = reverseAction ? !(this.propertyValue == "true") : (this.propertyValue == "true");
        definitionDisplayLayoutControl.formRuleLogger.log('Result for ' + this.propertyTarget + ' is that property ' + this.propertyName + ' is now Required=' + targetDiv.required);
    }
    else if(this.propertyName == "Enabled")
    {
        EnableDisableRecursive(targetDiv, reverseAction ? (this.propertyValue == "true") : !(this.propertyValue == "true"));
        definitionDisplayLayoutControl.formRuleLogger.log('Result for ' + this.propertyTarget + ' is that property ' + this.propertyName + ' is now Enabled=' + (reverseAction ? (this.propertyValue == "true") : !(this.propertyValue == "true")));
    }
    else if(this.propertyName == "Error" && !reverseAction)
    {
        /*
        // This code will add an error to the error list, but currently we only want errors to occur on postback so leave this commented out
        var errorDiv = document.getElementById("acErrorDiv");
        if(errorDiv != undefined)
        {
        var onclickstring = "DefinitionDisplayLayoutControl_" + definitionDisplayLayoutControl.id + ".focus('" + this.propertyName + "');return false;";
        var anchor = document.createElement('a');
        anchor.setAttribute('onclick', onclickstring);
        anchor.setAttribute('href', '#');
        anchor.innerHTML = this.propertyValue;
        var li = document.createElement('li');
        li.appendChild(anchor);
        var ul = document.getElementById("ac-errorul");
        ul.appendChild(li);
            
        // Haven't tested this, but we need to set the field to have the error class
        targetDiv.className += " AC-Error";
        }
        */
    }
    else if(this.propertyName == "CssClass")
    {
        // Important - Any class added to the string must have an extra space appended to it so that the string replace can find it.
        //  We don't want to have any problems with similar named classes.

        var currentClass = targetDiv.className;
        var classEmpty = currentClass.length == 0;
        // Add a space to the beginning and end if necessary
        if(!classEmpty && currentClass.substr(0, 1) != ' ')
            currentClass = ' ' + currentClass;
        if(!classEmpty && currentClass.substr(currentClass.length - 1, 1) != ' ')
            currentClass = currentClass + ' ';
        
        // Is the class already on the control
        var classExists = currentClass.indexOf(' ' + this.propertyValue + ' ') >= 0;
        if(reverseAction && classExists)
        {
            // Remove the css class
            currentClass = currentClass.replace(' ' + this.propertyValue + ' ', "");
        }
        else if(!reverseAction && !classExists)
        {
            // Append the css class
            currentClass = currentClass + ' ' + this.propertyValue + ' ';
        }
        if(!classEmpty || currentClass.length > 0)
            targetDiv.className = currentClass;
        definitionDisplayLayoutControl.formRuleLogger.log('Result for ' + this.propertyTarget + ' is that property ' + this.propertyName + ' is now Class Name=' + targetDiv.className);
    }
}
function PropertyNameChanged(actionDropdown)
{
    var propertyValueCell = document.getElementById("propertyValueCell");
    var propertyName = actionDropdown.options[actionDropdown.selectedIndex].value;
    if(propertyName == "Error" || propertyName == "CssClass")
        propertyValueCell.innerHTML = "<input type='text'>";
    else
        propertyValueCell.innerHTML = "<input type='checkbox' checked>";
}


function DateSpan(dateSpan)
{
    this.dateSpan = dateSpan.toUpperCase();
}
DateSpan.prototype.evaluate = function(objDate, values)
{
    var dateToEvaluate = new Date(objDate);
    var now = new Date();
    if(this.dateSpan == "SINGLEDAY")
        return this.isSameDay(dateToEvaluate, new Date(values[0]))
    else if(this.dateSpan == "ADHOC")
        return (new Date(values[0]) <= dateToEvaluate) && (dateToEvaluate <= new Date(values[1]));
    else if(this.dateSpan == "YESTERDAY")
        return this.isSameDay(dateToEvaluate, new Date(now.getYear(), now.getMonth(), now.getDay() - 1));
    else if(this.dateSpan == "LASTMONTH")
        return this.isSameMonth(dateToEvaluate, new Date(now.getYear(), now.getMonth() - 1, 1));
    else if(this.dateSpan == "LASTYEAR")
        return dateToEvaluate.getFullYear() == (now.getFullYear() - 1);
    else if(this.dateSpan == "LASTSEVENDAYS")
        return (new Date(now.getYear(), now.getMonth(), now.getDay() - 7, 0, 0, 0) <= dateToEvaluate) && (dateToEvaluate <= now);
    else if(this.dateSpan == "LAST30DAYS")
        return (new Date(now.getYear(), now.getMonth(), now.getDay() - 30, 0, 0, 0) <= dateToEvaluate) && (dateToEvaluate <= now);
    else if(this.dateSpan == "LAST60DAYS")
        return (new Date(now.getYear(), now.getMonth(), now.getDay() - 60, 0, 0, 0) <= dateToEvaluate) && (dateToEvaluate <= now);
    else if(this.dateSpan == "LAST90DAYS")
        return (new Date(now.getYear(), now.getMonth(), now.getDay() - 90, 0, 0, 0) <= dateToEvaluate) && (dateToEvaluate <= now);
    else if(this.dateSpan == "TODAY")
        return this.isSameDay(dateToEvaluate, now)
    else if(this.dateSpan == "THISMONTH")
        return this.isSameMonth(dateToEvaluate, now);
    else if(this.dateSpan == "THISYEAR")
        return dateToEvaluate.getFullYear() == now.getFullYear();
    else if(this.dateSpan == "TOMORROW")
        return this.isSameDay(dateToEvaluate, new Date(now.getYear(), now.getMonth(), now.getDay() + 1));
    else if(this.dateSpan == "NEXTMONTH")
        return this.isSameMonth(dateToEvaluate, new Date(now.getYear(), now.getMonth() + 1, 1));
    else if(this.dateSpan == "NEXTYEAR")
        return dateToEvaluate.getFullYear() == (now.getFullYear() + 1);
    else if(this.dateSpan == "NEXTSEVENDAYS")
        return ((now < dateToEvaluate) || (this.isSameDay(dateToEvaluate, now))) && (dateToEvaluate <= new Date(now.getYear(), now.getMonth(), now.getDay() + 7, 0, 0, 0));
    else if(this.dateSpan == "NEXT30DAYS")
        return ((now < dateToEvaluate) || (this.isSameDay(dateToEvaluate, now))) && (dateToEvaluate <= new Date(now.getYear(), now.getMonth(), now.getDay() + 30, 0, 0, 0));
    else if(this.dateSpan == "NEXT60DAYS")
        return ((now < dateToEvaluate) || (this.isSameDay(dateToEvaluate, now))) && (dateToEvaluate <= new Date(now.getYear(), now.getMonth(), now.getDay() + 60, 0, 0, 0));
    else if(this.dateSpan == "NEXT90DAYS")
        return ((now < dateToEvaluate) || (this.isSameDay(dateToEvaluate, now))) && (dateToEvaluate <= new Date(now.getYear(), now.getMonth(), now.getDay() + 90, 0, 0, 0));
    else if(this.dateSpan == "FUTURE")
        return dateToEvaluate > now;
    else
        alert("Not implemented:" + this.dateSpan);
    return false;
}
DateSpan.prototype.isSameDay = function(date1, date2)
{
    return (date1.getDay() == date2.getDay()
                && date1.getMonth() == date2.getMonth()
                && date1.getFullYear() == date2.getFullYear())

}
DateSpan.prototype.isSameMonth = function(date1, date2)
{
    return (date1.getMonth() == date2.getMonth()
                && date1.getFullYear() == date2.getFullYear())

}
DateSpan.prototype.unitTest = function()
{
}


function FormRuleLogger(definitionDisplayLayoutControl, active)
{
    this.text = '';
    this.id = definitionDisplayLayoutControl.id + 'formRuleLogger';
    this.definitionDisplayLayoutControl = definitionDisplayLayoutControl;
    this.active = active;

}

FormRuleLogger.prototype.show = function()
{
    if(this.active)
    {
        var element = document.getElementById(this.id);

        if(element != null)
        {
            element.parentNode.removeChild(element);
        }

        element = document.createElement('DIV');
        element.id = this.id;
        var bodyRef = document.getElementsByTagName("body").item(0);
        bodyRef.appendChild(element);

        this.text = '<br>' + Date().toLocaleString() + '<br>' + this.text;
        element.innerHTML = this.text;
    }
}

FormRuleLogger.prototype.log = function(text)
{
    if(this.active)
        this.text = this.text + '<br>' + this.definitionDisplayLayoutControl.id + ' - ' + text;

}
if(typeof(Sys)!=='undefined')Sys.Application.notifyScriptLoaded();