/*
 * Delivered to the U.S. Government in Accordance with Contract FA8650-10-C-7080.
 *
 * EXPORT CONTROLLED
 * ECCN#   EAR99
 * Warning: This document contains technical data which is controlled under the
 * Bureau of Industry & Security's Export Administration Regulations and may not be
 * exported or re-exported without authorization by the Bureau of Industry & Security.
 * Diversion contrary to US law is prohibited.
 *
 * (c) 2011 United Technologies Corp.
 * Developed with the sponsorship of the Defense Advanced Research Projects Agency (DARPA).
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this data,
 * including any software or models in source or binary form, as well as any drawings, 
 * specifications, and documentation (collectively "the Data"), to deal in the Data without 
 * restriction, including without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Data, and to permit persons to whom the Data
 * is furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all copies or
 * substantial portions of the Data.
 *
 * THE DATA IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS, SPONSORS, DEVELOPERS, CONTRIBUTORS, OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE DATA OR THE
 * USE OR OTHER DEALINGS IN THE DATA.
*/

package aee.engine;

import java.util.List;

import org.jdom.Attribute;
import org.jdom.Element;

import aee.engine.rule.OperType;
import aee.engine.rule.Operation;
import aee.exception.AeeException;

/**
 * A design rule
 */
public class Rule extends IDedObject {
	private boolean   active;
	private String    comment;
	private Operation operation;
	private static final String ElementName = "rule";

	/**
	 * Constructor builds a design rule from XML 
	 * @param root The root element
	 * @throws AeeException if any unexpected XML errors detected
	 */
	@SuppressWarnings("unchecked")
	public Rule(Element root) throws AeeException {
		super(root, ElementName);

		active   = false;
		comment   = "";
		operation = null;
		
		// All attributes are optional
		String attrName = "active";
		Attribute attr  = root.getAttribute(attrName);
		if (attr != null) {
			active = (getAttrValue(attr).equalsIgnoreCase("y"));
		}
			
		attrName = "comment";
		attr     = root.getAttribute(attrName);
		if (attr != null) {
			comment = getAttrValue(attr);
		}

		// There must be a single child operation
		List<Element> children = root.getChildren();
		for (Element child : children) {
			if (operation != null)
				throw new AeeException("Multiple operations were defined for rule %d",
						                    getId());
			operation = new Operation(child);
		}
	
		if (operation == null)
			throw new AeeException("Rule %d is missing an operation", getId());
	}
	
	/**
	 * Report whether or not the rule is active
	 * @return true if active
	 */
	public boolean isActive() {
		return active;
	}
	
	/**
	 * Report the comment
	 * @return The comment. Never null
	 */
	public String getComment() {
		return comment;
	}
	
	/**
	 * Report the rule's operation
	 * @return The operation. Never null
	 */
	public Operation getOperation() {
		return operation;
	}
	
	/**
	 * Report the rule's category. This is either
	 * 	DefinePremise
	 * 	DefineQuantity
	 *  DefineRule
	 * @return The category
	 */
	public String getRuleCategory() {
		String    category = null;
		Operation o        = getOperation();
		OperType  ot       = o.getType();
		String    primVal  = o.getPrimaryTerm()
		                      .getValue();
		if (ot == OperType.Assign  &&
				(primVal.equalsIgnoreCase("true") || primVal.equalsIgnoreCase("false"))
		|| (ot == OperType.Compare &&
				o.getResult() != null)
		|| (ot == OperType.BoolFn)
		|| (ot == OperType.Not)
		|| (ot == OperType.PVPremise))
			category = "DefinePremise";
		
		else if (ot == OperType.Assign  
				 ||  ot == OperType.Function
				 ||  ot == OperType.PVQuantity)
			category = "DefineQuantity";
		
		else
			category = "DefineRule";
				
		return category;
	}
}
