package org.exist.client.xacml;

import com.sun.xacml.Policy;
import com.sun.xacml.PolicyTreeElement;
import com.sun.xacml.Rule;
import com.sun.xacml.Target;
import com.sun.xacml.combine.RuleCombiningAlgorithm;

import java.net.URI;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class PolicyNode extends AbstractPolicyNode
{
	private List rules;
	private List originalRules;
	
	public PolicyNode(NodeContainer parent, Policy policy)
	{
		this(parent, null, policy);
	}
	public PolicyNode(NodeContainer parent, String documentName, Policy policy)
	{
		super(parent, documentName, policy);
		
		List children = policy.getChildren();
		rules = new ArrayList(children.size());
		for(Iterator it = children.iterator(); it.hasNext();)
			rules.add(new RuleNode(this, (Rule)it.next()));
		originalRules = new ArrayList(rules);
	}

	public PolicyTreeElement create()
	{
		return createPolicy();
	}
	public PolicyTreeElement create(URI id)
	{
		return createPolicy(id);
	}
	public Policy createPolicy()
	{
		return createPolicy(null);
	}
	public Policy createPolicy(URI id)
	{
		Target target = getTarget().getTarget();
		RuleCombiningAlgorithm algorithm = (RuleCombiningAlgorithm)getCombiningAlgorithm();
		List rawRules = new ArrayList(rules.size());
		for(Iterator it = rules.iterator(); it.hasNext();)
			rawRules.add(((RuleNode)it.next()).createRule());
		URI useId = (id == null) ? getId() : id;
		return new Policy(useId, algorithm, getDescription(), target, rawRules);
	}

	public void add(PolicyTreeElement element)
	{
		add(-1, element);
	}
	public void add(int index, PolicyTreeElement element)
	{
		if(element == null)
			return;
		if(element instanceof Rule)
			add(index, new RuleNode(this, (Rule)element));
		else
			throw new IllegalArgumentException("Policies can only contain rules.");
	}
	public void add(PolicyElementNode node)
	{
		add(-1, node);
	}
	public void add(int index, PolicyElementNode node)
	{
		if(node == null)
			return;
		if(node instanceof RuleNode)
		{
			if(index < 0)
				index = rules.size()+1;
			if(index == 0)
				throw new IllegalArgumentException("Cannot insert Rule before Target");
			rules.add(index-1, node);
			setModified(true);
			nodeAdded(node, index);
		}
		else
			throw new IllegalArgumentException("PolicyNodes can only contain RuleNodes.");
	}
	public void remove(PolicyElementNode node)
	{
		if(node == null)
			return;
		int index = rules.indexOf(node);
		if(index < 0)
			return;
		rules.remove(index);
		setModified(true);
		nodeRemoved(node, index+1);
	}

	public boolean containsId(String id)
	{
		for(Iterator it = rules.iterator();it.hasNext();)
		{
			if(((RuleNode)it.next()).getId().toString().equals(id))
				return true;
		}
		return false;
	}
	public int getChildCount()
	{
		return rules.size() + 1; //+1 for the target
	}

	public XACMLTreeNode getChild(int index)
	{
		return (index == 0) ? getTarget() : (XACMLTreeNode)rules.get(index-1);
	}

	public int indexOfChild(Object child)
	{
		if(child == getTarget())
			return 0;
		int ret = rules.indexOf(child);
		return (ret >= 0) ? ret + 1 : -1;
	}
	public boolean isModified(boolean deep)
	{
		if(super.isModified(deep))
			return true;
		if(deep)
		{
			for(Iterator it = rules.iterator(); it.hasNext();)
			{
				if(((RuleNode)it.next()).isModified(true))
					return true;
			}
		}
		return false;
	}
	public void revert(boolean deep)
	{
		rules = new ArrayList(originalRules);
		if(deep)
		{
			for(Iterator it = rules.iterator(); it.hasNext();)
				((RuleNode)it.next()).revert(true);
		}
		super.revert(deep);
	}
	public void commit(boolean deep)
	{
		originalRules = new ArrayList(rules);
		if(deep)
		{
			for(Iterator it = rules.iterator(); it.hasNext();)
				((RuleNode)it.next()).commit(true);
		}
		super.commit(deep);
	}
}
