package be.jeffcheasey88.peeratcode.parser.java.operations;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;

import be.jeffcheasey88.peeratcode.parser.java.CleanerPool;
import be.jeffcheasey88.peeratcode.parser.java.JavaElement;
import be.jeffcheasey88.peeratcode.parser.java.Variable;
import be.jeffcheasey88.peeratcode.parser.java.CleanerPool.Cleaner;

public class OperationFactory{
	
	private static final OperationFactory SINGLETON = new OperationFactory();
	
	public static OperationFactory getFactory(){
		return SINGLETON;
	}
	
	private Map<Pattern, Class<? extends JavaElement>> patterns;
	
	private OperationFactory(){
		this.patterns = new LinkedHashMap<>();

		this.patterns.put(Pattern.compile("^\\s*return\\s*[^;]*;.*$"), ReturnOperation.class);
		this.patterns.put(Pattern.compile("^\\s*if\\s*\\^GENERIC_PARENTHESIS\\d+.*$"), IfOperation.class);
		this.patterns.put(Pattern.compile("^\\s*else\\s*.*$"), ElseOperation.class);
		
		this.patterns.put(Pattern.compile("^\\s*([^;=]+;).*$"), MethodCallOperation.class);
		
		this.patterns.put(Pattern.compile("^\\s*[^\\s]+\\s+[^\\s]+\\s*=\\s*[^;]+;.*$"), Variable.class);
		this.patterns.put(Pattern.compile("^\\s*[^\\s]+\\s*=\\s*[^;]+;.*$"), AssigmentOperation.class);
	}
	
	/*
	 * variable										OK
	 * assignation									OK
	 * exec method									OK
	 * for
	 * do while
	 * while
	 * if
	 * switch case
	 * return										OK (without just return)
	 * continue
	 * break
	 * try catch finally
	 * throw
	 * else
	 * synchronized
	 * instance of
	 * 
	 * native operation style i++
	 * 
	 * assert ??
	 * Goto ??
	 * Const ??
	 */

	public JavaElement buildOperation(String content) throws Exception{
		CleanerPool generic = new CleanerPool(
				new Cleaner("GENERIC_FUNCTION", '{','}'),
				new Cleaner("GENERIC_PARENTHESIS",'(',')'),
				new Cleaner("GENERIC_ARRAY",'[',']'),
				new Cleaner("GENERIC_TYPE_",'<','>'));
		content = generic.clean(content);
		generiqueTypes(content, generic);
		
		for(Entry<Pattern, Class<? extends JavaElement>> entries : this.patterns.entrySet()){
			if(entries.getKey().matcher(content).matches()) return entries.getValue().newInstance();
		}
		return null;
	}
	
	
	private static Pattern UNZIP_STICK = Pattern.compile("\\s+(?<e>[<|(|\\[|\"|'])");
	private static Pattern UNZIP_MAJ = Pattern.compile(">(?<e>[^>\\d,;(])");
	private static Pattern UNZIP_ARRAY = Pattern.compile("](?<e>[^\\[\\d,;])");
	private static Pattern UNZIP_EQUALS_LEFT = Pattern.compile("(?<e>[^=\\s])=");
	private static Pattern UNZIP_EQUALS_RIGHT = Pattern.compile("=(?<e>[^=\\s])");
	
	private String generiqueTypes(String content, CleanerPool cleaner){
		String unzip = cleaner.unzip(content, (value, pattern) -> {
				if(pattern.equals("^GENERIC_FUNCTION")) return null;
				if(pattern.equals("^GENERIC_PARENTHESIS")) return value.replace("\\s+", " ");
				return value.replaceAll("\\s+", "");
			});
		unzip = UNZIP_STICK.matcher(unzip).replaceAll("${e}");
		unzip = UNZIP_MAJ.matcher(unzip).replaceAll("> ${e}");
		unzip = UNZIP_ARRAY.matcher(unzip).replaceAll("] ${e}");
		unzip = UNZIP_EQUALS_LEFT.matcher(unzip).replaceAll("${e} =");
		unzip = UNZIP_EQUALS_RIGHT.matcher(unzip).replaceAll("= ${e}");
		return unzip;
	}
}
