package models.dataConstraintModel;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import models.algebra.Expression;
import models.algebra.Type;
import models.algebra.Symbol;
import models.algebra.Term;

public class ResourcePath extends Symbol {
	protected ResourcePath parent = null;
	protected ResourceHierarchy resourceHierarchy = null;
	protected List<Expression> pathParams = null;

	public ResourcePath(String fullResourceName) {
		super(fullResourceName);
		this.parent = null;
		this.resourceHierarchy = new ResourceHierarchy(null, fullResourceName);		
		this.pathParams = new ArrayList<>();
	}
	
	public ResourcePath(String fullResourceName, ResourceHierarchy resourceHierarchy) {
		super(fullResourceName);
		this.parent = null;
		this.resourceHierarchy = resourceHierarchy;		
		this.pathParams = new ArrayList<>();
	}
	
	public ResourcePath(ResourcePath parent, String leafResourceName) {
		super(parent.toString() + "." + leafResourceName);
		this.parent = parent;
		this.resourceHierarchy = new ResourceHierarchy(parent.getResourceHierarchy(), leafResourceName);		
		this.pathParams = parent.getPathParams();
	}
	
	public ResourcePath(ResourcePath parent, String leafResourceName, ResourceHierarchy resourceHierarchy) {
		super(parent.toString() + "." + leafResourceName);
		this.parent = parent;
		this.resourceHierarchy = resourceHierarchy;		
		this.pathParams = parent.getPathParams();
	}
	
	public ResourcePath(ResourcePath parent, Expression exp) {
		super(parent.toString() + ".{" + exp + "}");
		this.parent = parent;
		this.resourceHierarchy = new ResourceHierarchy(parent.getResourceHierarchy(), exp);
		this.pathParams = new ArrayList<>(parent.getPathParams());
		this.pathParams.add(exp);
	}
	
	public ResourcePath(ResourcePath parent, Expression exp, ResourceHierarchy resourceHierarchy) {
		super(parent.toString() + ".{" + exp + "}");
		this.parent = parent;
		this.resourceHierarchy = resourceHierarchy;
		this.pathParams = new ArrayList<>(parent.getPathParams());
		this.pathParams.add(exp);
	}
	
	public ResourcePath(ResourcePath another) {
		super(another.name);
		this.parent = another.parent;
		this.resourceHierarchy = another.resourceHierarchy;		
		this.pathParams = new ArrayList<>(another.getPathParams());
	}

	public ResourceHierarchy getResourceHierarchy() {
		return resourceHierarchy;
	}

	public void setResourceHierarchy(ResourceHierarchy resourceHierarchy) {
		this.resourceHierarchy = resourceHierarchy;
	}

	public String getLeafResourceName() {
		return resourceHierarchy.getResourceName();
	}
	
	public int getNumberOfParameters() {
		return resourceHierarchy.getTotalNumParameters();
	}

	public models.algebra.Type getResourceStateType() {
		return resourceHierarchy.getResourceStateType();
	}

	public void setResourceStateType(models.algebra.Type resourceStateType) {
		this.resourceHierarchy.setResourceStateType(resourceStateType);
	}
	
	public List<Expression> getPathParams() {
		return pathParams;
	}

	public void setPathParams(List<Expression> pathParams) {
		this.pathParams = pathParams;
	}

	public void addPathParam(Expression pathParam) {
		pathParams.add(pathParam);
	}
	
	public boolean endsWithParam() {
		if (resourceHierarchy.getNumParameters() > 0) return true;
		return false;
	}
	
	public Expression getLastParam() {
		if (endsWithParam()) {
			return pathParams.get(pathParams.size() - 1);
		}
		return null;
	}
	
	public ResourcePath getParent() {
		return parent;
	}

	public ResourcePath getRoot() {
		if (parent == null) return this;
		return parent.getRoot();
	}
	
	public ResourcePath getCommonPrefix(ResourcePath another) {
		Set<ResourcePath> ancestors = new HashSet<>();
		while (another != null) {
			ancestors.add(another);
			another = another.getParent();
		}
		ResourcePath curPath = this;
		while (!ancestors.contains(curPath)) {
			curPath = curPath.getParent();
			if (curPath == null) return null;
		}
		return curPath;
	}
	
	public String toString() {
		return resourceHierarchy.toString(pathParams);
	}
}
