/********************************************************************
 * Copyright © 2006 VHA. All rights reserved
 ********************************************************************/

package gov.va.med.fw.model;

import java.util.Set;

import gov.va.med.fw.service.AbstractComponent;

/**
 * Generic object that encapsulates configurable model properties (can be used
 * for any need). Examples are properties that are used for identities,
 * properties that are used for copying, etc.
 * 
 * <p>
 * No-args constructor allows all properties to be used in
 * ModelPropertiesManager.
 * 
 * Created Mar 13, 2006 2:22:51 PM
 * 
 * @author DNS   BOHMEG
 */
public class ConfigurableModelProperties extends AbstractComponent {
	private Set inclusions;

	private Set exclusions;

	private ConfigurableModelProperties globalProperties;

	private boolean inheritAncestorsProperties = true; // default

	public ConfigurableModelProperties() {
		super();
	}

	public ConfigurableModelProperties(ConfigurableModelProperties globalProperties) {
		setGlobalProperties(globalProperties);
	}

	public void addInclusions(Set in) {
		if (in == null || in.isEmpty())
			return;

		if (this.inclusions != null)
			this.inclusions.addAll(in);
		else
			this.inclusions = in;
	}

	public void addExclusions(Set in) {
		if (in == null || in.isEmpty())
			return;

		if (this.exclusions != null)
			this.exclusions.addAll(in);
		else
			this.exclusions = in;
	}

	/**
	 * @return Returns the exclusions.
	 */
	public Set getExclusions() {
		return exclusions;
	}

	/**
	 * @param exclusions
	 *            The exclusions to set.
	 */
	public void setExclusions(Set exclusions) {
		this.exclusions = exclusions;
	}

	/**
	 * @return Returns the inclusions.
	 */
	public Set getInclusions() {
		return inclusions;
	}

	/**
	 * @param inclusions
	 *            The inclusions to set.
	 */
	public void setInclusions(Set inclusions) {
		this.inclusions = inclusions;
	}

	public boolean containsInclusions() {
		return inclusions == null || inclusions.size() == 0 ? false : true;
	}

	public boolean containsExclusions() {
		return exclusions == null || exclusions.size() == 0 ? false : true;
	}

	public boolean isPropertySpecified(String propertyName) {
		return isPropertySpecifiedForInclusion(propertyName)
				|| isPropertySpecifiedForExclusion(propertyName);
	}

	public void allowAllProperties() {
		inclusions = null;
		exclusions = null;
		globalProperties = new ConfigurableModelProperties();
	}

	public void rejectAllProperties() {
		inclusions = null;
		exclusions = null;
		globalProperties = null;
	}

	public boolean isPropertySpecifiedForInclusion(String propertyName) {
		boolean wasSpecified = false;
		if (containsInclusions())
			wasSpecified = inclusions.contains(propertyName);
		return wasSpecified;
	}

	public boolean isPropertySpecifiedForExclusion(String propertyName) {
		boolean wasSpecified = false;
		if (containsExclusions())
			wasSpecified = exclusions.contains(propertyName);
		return wasSpecified;
	}

	/**
	 * If at least one item is specified for inclusions, then it is by default
	 * explicit mode. Same goes for exclusions.
	 * 
	 * <p>
	 * Configured Inclusions take priority over configured Exclusions.
	 */
	public boolean shouldInclude(String propertyName) {
		if (containsInclusions())
			if (isPropertySpecifiedForInclusion(propertyName))
				return true;

		if (containsExclusions())
			if (isPropertySpecifiedForExclusion(propertyName))
				return false;

		// if there is no one else to defer to....
		if (globalProperties == null)
			return false;

		// only deal with global if did not override or act explitictly
		boolean result = true;
		if (!isPropertySpecified(propertyName)) {
			boolean globalDecision = globalProperties.shouldInclude(propertyName);
			result = globalDecision;
			// if global decided because it did not know about this...then go
			// back to this class's decision
			if (!globalDecision && !globalProperties.isPropertySpecified(propertyName)) {
				if (containsInclusions() && !isPropertySpecifiedForInclusion(propertyName))
					result = false;
				else if (containsExclusions() && !isPropertySpecifiedForExclusion(propertyName))
					result = true;
				else
					result = true; // the overall default if nothing is
				// specified
			}
		}

		return result;
	}

	/**
	 * @return Returns the globalProperties.
	 */
	public ConfigurableModelProperties getGlobalProperties() {
		return globalProperties;
	}

	/**
	 * @param globalProperties
	 *            The globalProperties to set.
	 */
	public void setGlobalProperties(ConfigurableModelProperties globalProperties) {
		this.globalProperties = globalProperties;
	}

	/**
	 * @return Returns the inheritAncestorsProperties.
	 */
	public boolean isInheritAncestorsProperties() {
		return inheritAncestorsProperties;
	}

	/**
	 * @param inheritAncestorsProperties
	 *            The inheritAncestorsProperties to set.
	 */
	public void setInheritAncestorsProperties(boolean inheritAncestorsProperties) {
		this.inheritAncestorsProperties = inheritAncestorsProperties;
	}

	/**
	 * @return Returns the inheritAncestorsProperties.
	 */
	public boolean isInheritAncestorsConfiguration(String propertyName) {
		return inheritAncestorsProperties && !isPropertySpecified(propertyName);
	}
}
