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.Variable;

public class Channel {
	protected String channelName;
	protected Channel parent = null;
	protected List<Channel> children = null;
	protected List<Selector> selectors = null;
	protected Set<ChannelMember> channelMembers = null;
	protected String sourceText = null;
	protected boolean isNative = false;
	
	public Channel(String channelName) {
		this.channelName = channelName;
		this.parent = null;
		this.children = new ArrayList<>();
		selectors = new ArrayList<>();
		channelMembers = new HashSet<>();
	}
	
	public Channel(String channelName, Variable variable) {
		this.channelName = channelName;
		this.parent = null;
		this.children = new ArrayList<>();
		selectors = new ArrayList<>();
		selectors.add(new Selector(variable));
		channelMembers = new HashSet<>();
	}
	
	public Channel(String channelName, List<Variable> variables) {
		this.channelName = channelName;
		this.parent = null;
		this.children = new ArrayList<>();
		selectors = new ArrayList<>();
		for (Variable var: variables) {
			selectors.add(new Selector(var));
		}
		channelMembers = new HashSet<>();
	}

	public String getChannelName() {
		return channelName;
	}

	public Channel getParent() {
		return parent;
	}
	
	public List<Channel> getChildren() {
		return children;
	}

	public void addChild(Channel child) {
		children.add(child);
		child.parent = this;
	}

	public List<Selector> getSelectors() {
		return selectors;
	}

	public List<Selector> getAllSelectors() {
		List<Selector> allSelectors = new ArrayList<>();
		if (parent != null) allSelectors.addAll(parent.getAllSelectors());
		allSelectors.addAll(selectors);
		return allSelectors;
	}

	public void setSelectors(List<Selector> selectors) {
		this.selectors = selectors;
	}

	public void addSelector(Variable var) {
		selectors.add(new Selector(var));
	}

	public void addSelector(Selector selector) {
		selectors.add(selector);
	}

	public Set<ChannelMember> getChannelMembers() {
		return channelMembers;
	}

	public void setChannelMembers(Set<ChannelMember> channelMembers) {
		this.channelMembers = channelMembers;
	}
	
	public void addChannelMember(ChannelMember channelMember) {
		channelMembers.add(channelMember);
		if (getAllSelectors().size() > 0) {
			Set<Expression> params = new HashSet<>();
			for (Selector s: getAllSelectors()) {
				params.add(s.getExpression());
			}
			if (!params.containsAll(channelMember.getResource().getPathParams())) {
				channelMember.setOutside(true);
			}
		} else {
			if (channelMember.getResource().getPathParams().size() == 0) {
				channelMember.setOutside(false);
			} else {
				channelMember.setOutside(true);
			}
		}
	}
	
	public void removeChannelMember(ResourcePath res) {
		for (ChannelMember cm: channelMembers) {
			if (cm.getResource() == res) {
				channelMembers.remove(cm);
				break;
			}
		}
	}

	public Set<ResourcePath> getResources() {
		Set<ResourcePath> resources = new HashSet<>();
		for (ChannelMember member: channelMembers) {
			resources.add(member.getResource());
		}
		return resources;
	}
	
	public String toString() {
		return channelName;
	}
	
	public void setSourceText(String sourceText) {
		this.sourceText = sourceText;
	}
	
	public String getSourceText() {
		if (sourceText == null) {
			return toString();
		}
		return sourceText;
	}

	public boolean isNative() {
		return isNative;
	}

	public void setNative(boolean isNative) {
		this.isNative = isNative;
	}
}
