package be.jeffcheasey88.peeratcode.parser.java;

import java.lang.reflect.Modifier;
import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

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

public class Variable {
	
	private static Pattern PATTERN = Pattern.compile("^(\\s*)(.*)$");
	
	private int modifier;
	private String name;
	private String type;
	private Variable value;
	
	public Variable(){}
	
	public Variable(int modifier, String type){
		this.modifier = modifier;
		this.type = type;
	}
	
	public int parse(String content, CleanerPool cleaner) throws Exception{
		System.out.println("parse "+content);
		CleanerPool generic = new CleanerPool(
				new Cleaner("GENERIC_TYPE_",'<','>'),
				new Cleaner("GENERIC_ARRAY",'[',']'),
				new Cleaner("GENERIC_FUNCTION", '{','}'),
				new Cleaner("GENERIC_PARENTHESIS",'(',')'));
		content = generic.clean(content);
		
		Matcher matcher = PATTERN.matcher(content);
		matcher.matches();
		
		int offset = matcher.group(1).length();

		String body = matcher.group(2);
		int equals = indexOf(body, "=");
		int quote = indexOf(body,",");
		int quotes = indexOf(body, ";");
		int min = Math.min(quote, quotes);
		body = body.substring(0, min);
		
		if(equals < quote && equals < quotes){
			assigment(body, generic);
		}else{
			onlyDefine(body, generic);
		}
		
		return offset+generic.unzip(body, ((s,p) -> s)).length();
	}
	
	private void assigment(String content, CleanerPool cleaner){
		System.out.println("assigment "+content);
		Iterator<String> values = onlyDefine(content, cleaner);
		if(!values.hasNext()) return;
		values.next();
		if(!values.hasNext()) return;
		String spacesValue = values.next();
		while(values.hasNext()) spacesValue+=" "+values.next();
		this.value = new Value(spacesValue);
	}
	
	private Iterator<String> onlyDefine(String content, CleanerPool cleaner){
		System.out.println("define "+content);
		content = generiqueTypes(content, cleaner);
		Iterator<String> values = new ArrayIterator<>(content.split("\\s+"));
		String value = null;
		int modifier;
		while(values.hasNext() && (modifier = JavaParser.getModifier(value = values.next())) > 0){
			this.modifier+=modifier;
		}
		if(this.type == null){
			this.type = value;
			if(values.hasNext()) value = values.next();
		}
		if(this.name == null){
			this.name = value;
		}
		
		return values;
	}
	
	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){
		System.out.println("generic "+content);
		String unzip = cleaner.unzip(content, (value, pattern) -> {
					return (pattern.equals("$GENERIC_FUNCTION")) ? null : value.replaceAll("\\s+", "");
				});
		System.out.println("unzip "+unzip);
		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}");
		System.out.println("matcher "+unzip);
		return unzip;
	}
	
	private int indexOf(String value, String target){
		return value.split(target)[0].length();
	}
	
	public int getModifier(){
		return this.modifier;
	}
	
	public String getName(){
		return this.name;
	}
	
	public String getType(){
		return this.type;
	}
	
	public Variable getValue(){
		return this.value;
	}
	
	public void show(int tab){
		String start = "";
		for(int i = 0; i < tab; i++) start+="\t";
		System.out.println(start+Modifier.toString(modifier)+" "+type+" "+name+(value == null ? ";":"="+value+";"));
	}
	
	public static class Value extends Variable{
		
		private String value;
		
		public Value(String value){
			this.value = value;
		}
		
		public String value(){
			return this.value;
		}
		
		@Override
		public String toString(){
			return this.value;
		}
	}
}
