package background.expressions;

import background.VariableManager;
import background.systemVariables.SimpleVariable;

public class MathTree extends EvaluationTree<Integer> {

	private final String mathOperators = "+-*/%";
	
	public MathTree(String s, VariableManager vm) {		
		super(s, vm);	
	}
	
	
	public static Boolean hasOperator(String s) {		
		String[] math = {"+", "-", "*", "/", "%"};
		
		for (int i=0; i<math.length; i++) {
			if (s.contains(math[i])) return true;
		}
		return false;
	}
	
	@Override
	public ETreeNode decompose(String s) {
		if ((s.startsWith("(")) && (s.endsWith(")"))) s = s.substring(1, s.length()-1); else return null;
		// odobrali sme vonkajsie zatvorky, ak nenajdeme ziadnu matematicku operaciu, sme pri simplecase		
		
		ETreeNode result = new ETreeNode();			
		
		String ss = s.replace("][", ":");
			
		if (s.matches("[a-zA-Z0-9]*") || (s.contains("]") && (ss.indexOf("]") == ss.lastIndexOf("]")))) {					// simplecase - ak s to len cislice alebo premenne alebo hranate zatvorky, cize pole
			result.value = s;						
		} else { 											// osetrenie binarnych operacii			
			String done = "";
			String toprocess = "";
			String operation = "";
			Boolean inArrayIndex = false;
			int counter = 0;			
			char c;
			
			for (int i=0; i<s.length(); i++) {
				c = s.charAt(i);
				
				if (c=='[') inArrayIndex=true;
				if (c==']') inArrayIndex=false;
				if (c=='(') {
					counter++; 
					toprocess += c; 
					if (!operation.isEmpty()) {
						result.value = operation.trim(); 
						operation = "";
					}
				} else if (c==')') {
					counter--; 
					toprocess += c; 
					if (counter==0) {
						result.children.add(decompose(new String(toprocess.trim())));
						toprocess = "";
						operation = " "; 														// hack na to, ze riesim operaciu
					} 
				} else if (counter>0) { toprocess += c; } 
				else if (!operation.isEmpty() && (mathOperators+" ").contains(Character.toString(c))) { operation += c; } 
				else if (!inArrayIndex && (mathOperators+" ").contains(Character.toString(c))) {				// to znamena ze zacinam riesit operaciu po tom, ako som riesila samostatne nezatvorkove
					ETreeNode node = new ETreeNode();
					node.value = done.trim();
					result.children.add(node);
					done = "";
					operation = Character.toString(c); 														// hack na to, ze riesim operaciu					
				} else if (counter==0) {					// pretoze viem ze operaciu aktualne nenacitavam, a ani nenacitavam do vnutra zatvorky, takze nacitavam do samostatneho nezatvorkoveho
					done +=c;					
					if (!operation.isEmpty()) {
						result.value = operation.trim(); 
						operation = "";
					}
				}				
			}				
				
			if (!done.isEmpty()) {
				ETreeNode n = new ETreeNode();
				n.value = done.trim();
				result.children.add(n);				
			}
			if (!toprocess.isEmpty()) result.children.add(decompose(new String(toprocess.trim())));			
		} 
		
		return result;
	}
	
		
	@Override
	public Integer getValueOf(ETreeNode n) {
		if (n.children.isEmpty()) return this.parseSimpleCase(n.value);
		else {		
			if (n.children.size()<2) { return 0; }
			else { 
				Integer result = this.getValueOf(n.children.get(0));				
				for (ETreeNode child: n.children) {
					if (n.children.indexOf(child)!=0) {
						result = this.processVariables(result, this.getValueOf(child), n.value);						
					}
				}
			return result;
			}
		}
	}
	
	@Override
	public Integer parseSimpleCase(String s) {				
		if (s.matches("[0-9]*")) {				// ak je iba z cisel, je to cislo
			return Integer.parseInt(s); 
		} else if (s.matches("[a-zA-Z]*") || (s.contains("[") && s.contains("]"))) {				// ak su tam len pismena tak je to premenna
			SimpleVariable sim = variableManager.getVariableByName(s); 
			if (!sim.initialized) {
				variableManager.errorHandler.errorHappened("Initialized"); 
				return 0;
			} else return sim.getValue(0);			
		} else return 0; 		
	}
	
	private int processVariables(Integer a, Integer b, String operation) {		
		switch (operation) {
			case "+": return a + b;
			case "-": return a - b;
			case "*": return a * b;
			case "/": return Math.round(a / b);
			case "%": return a % b;
		}					
		return 0;
	}
	
}
