package simulator;

import java.util.HashMap;
import java.util.Map;

import models.algebra.Constant;
import models.algebra.Expression;
import models.dataConstraintModel.ResourceHierarchy;
import models.dataConstraintModel.ResourcePath;
import models.dataConstraintModel.Selector;

public class ResourceIdentifier extends ResourcePath {

	public ResourceIdentifier(String fullResourceName, ResourceHierarchy resourceHierarchy) {
		super(fullResourceName, resourceHierarchy);
	}

	public ResourceIdentifier(ResourceIdentifier parentResId, String leafResourceName, ResourceHierarchy resourceHierarchy) {
		super(parentResId, leafResourceName, resourceHierarchy);
	}

	public ResourceIdentifier(ResourceIdentifier parentResId, Expression exp, ResourceHierarchy resourceHierarchy) {
		super(parentResId, exp, resourceHierarchy);
	}

	public void setPathParam(int paramIdx, Constant param) {
		if (paramIdx < pathParams.size()) {
			pathParams.set(paramIdx, param);
			if (parent != null) {
				((ResourceIdentifier) parent).setPathParam(paramIdx, param);
			}
		}
	}
	
	public boolean equals(ResourceIdentifier another) {
		if (!this.getResourceHierarchy().toString().equals(another.getResourceHierarchy().toString())) return false;
		ResourceIdentifier resId = this;
		while (resId != null && another != null) {
			if (resId.getResourceHierarchy().getNumParameters() == 0) {
				if (!another.getResourceHierarchy().getResourceName().equals(resId.getResourceHierarchy().getResourceName())) {
					return false;
				}
			} else {
				if (!another.getLastParam().equals(resId.getLastParam())) {
					return false;
				}
			}
			resId = (ResourceIdentifier) resId.getParent();
			another = (ResourceIdentifier) another.getParent();
		}
		return true;
	}
	
	public boolean startsWith(ResourceIdentifier another) {
		if (this.length() > another.length()) {
			return ((ResourceIdentifier) parent).startsWith(another);
		}
		return this.equals(another);
	}
	
	public int length() {
		if (parent == null) {
			return 1;
		}
		return ((ResourceIdentifier) parent).length() + 1;
	}
	
	public String toString() {
		String resId = "";
		if (parent != null) {
			resId += parent.toString() + ".";
		}
		if (!this.endsWithParam()) {
			resId += getLeafResourceName();
		} else {
			resId += getLastParam().toString().replace("\"", "");
		}
		return resId;
	}
	
	public boolean isInstanceOf(ResourcePath resPath) {
		ResourcePath resId = this;
		while (resId != null && resPath != null) {
			if (resId.getResourceHierarchy().getNumParameters() == 0) {
				if (!resPath.getResourceHierarchy().getResourceName().equals(resId.getResourceHierarchy().getResourceName())) {
					return false;
				}
			} else if (resId.getResourceHierarchy().getNumParameters() != resPath.getResourceHierarchy().getNumParameters()) {
				return false;
			}
			resId = resId.getParent();
			resPath = resPath.getParent();
		}
		return true;
	}
	
	public Map<Expression, Constant> extractParameters(ResourcePath resPath) {
		ResourcePath resId = this;
		Map<Expression, Constant> paramMap = new HashMap<>();
		while (resId != null && resPath != null) {
			if (resId.getResourceHierarchy().getNumParameters() > 0) {
				paramMap.put(resPath.getLastParam(), (Constant) resId.getLastParam());
			} else {
				if (!resPath.getName().equals(resId.getName())) {
					return null;
				}
			}
			resId = resId.getParent();
			resPath = resPath.getParent();
		}
		return paramMap;
	}

	public static ResourceIdentifier createFrom(ResourcePath resPath) {
		ResourceIdentifier parent = null;
		if (resPath.getParent() != null) {
			parent = createFrom(resPath.getParent());
		}
		ResourceHierarchy res = resPath.getResourceHierarchy();
		if (res.getNumParameters() == 0) {
			if (parent == null) {
				return new ResourceIdentifier(resPath.getLeafResourceName(), res);
			} else {
				return new ResourceIdentifier(parent, resPath.getLeafResourceName(), res);
			}
		} else {
			return new ResourceIdentifier(parent, resPath.getLastParam(), res);
		}
	}

}
