package dfatool.expressions;

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

import dfatool.operations.SetOperations;
import dfatool.strategy.elements.Context;
import dfatool.values.SetValue;
import dfatool.values.StringValue;
import dfatool.values.ListValue;
import dfatool.values.Value;

public class ExtensionExpression extends Expression{
	SetExpression setExp;
	public ExtensionExpression(SetExpression set) {
		this.setExp = set;
	}

	@Override
	public Value evaluate(Context c) {
		SetValue result = new SetValue();
		Set<Value> s = (Set<Value>) setExp.evaluate(c);
		for(Value v : s){
			ListValue t = toTuple(v);
			String channelName = ((StringValue) t.getValue().get(0)).getValue();
			List<Value> referenceTuple = getTail(t);
			List<Set<Value>> allPossibleExtensions = toListSetValue(c.getChannelMap().get(channelName));
			List<Set<Value>> extensionTuple = getExtensionsTuple(referenceTuple, allPossibleExtensions);
			Set<List<Value>> extensions = SetOperations.caculateCartesianProduct(extensionTuple);
			for(List<Value> ext : extensions){
				ListValue tuple = new ListValue();
				tuple.addAll(t);
				tuple.addAll(ext);
				result.add(tuple);
			}
		}
		return result;
	}
	
	public List<Set<Value>> getExtensionsTuple(List<Value> reference, List<Set<Value>> channelType){
		Iterator<Value> referenceIt = reference.iterator();
		List<Set<Value>> listRet = new ArrayList<Set<Value>>(channelType);
		while(referenceIt.hasNext()){
			Set<Value> values = listRet.get(0);
			Value value = referenceIt.next();
			if(values.contains(value)){
				listRet.remove(0);
			}else{
				throw new UnsupportedOperationException("Wrong channel value!");
			}
		}
		return listRet;
	}
	
	public List<Set<Value>> toListSetValue(List<Value> list){
		List<Set<Value>> listRet = new ArrayList<Set<Value>>();
		for(Value v : list){
			listRet.add((Set<Value>) v);
		}
		return listRet;
	}
	
	public ListValue getTail(ListValue t){
		ListValue tv = new ListValue(t);
		tv.remove(0);
		return tv;
	}
	
	public ListValue toTuple(Value v){
		ListValue t = new ListValue();
		if(v instanceof StringValue){
			t.add(v);
		}else{
			t = (ListValue) v;
		}
		return t;
	}
	private boolean prefix(ListValue t1, ListValue t2){
		Iterator<Value> it1 = t1.getValue().iterator();
		Iterator<Value> it2 = t2.getValue().iterator();
		boolean isPrefix = true;
		while(it1.hasNext() && isPrefix) isPrefix = isPrefix && it1.next().equals(it2.next());
		return isPrefix;
	}

	@Override
	public boolean checkType(Context c) {
		return setExp.checkType(c);
	}

	@Override
	public String toConcreteSyntax() {
		// TODO Auto-generated method stub
		return null;
	}

}
