package project;

import java.awt.Color;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.channels.FileLockInterruptionException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import javax.swing.JTextArea;
import javax.swing.JTextField;


public class FormFactory {
	
	Map<String,GenericForm3> formCollection=new HashMap<String,GenericForm3>();
	
	public FormFactory(Repository repository){
		addForms(repository);
		
	}
	
	public Map<String,GenericForm3> getForms(){
		return formCollection;
	}
	
public static  ConfigAttribute mapToConfig1(String line) {
	String[] attributesArray=line.split("=");
	String[] attributeValues=attributesArray[1].split(",");
	String attributeName=attributesArray[0];
	if (attributeName.equalsIgnoreCase("formName")){
		ConfigAttribute.unID++;
	}
	
	ConfigAttribute configAttribute=new ConfigAttribute(attributeName.trim(), attributeValues,ConfigAttribute.unID);
	return configAttribute;
}

public static  List<ConfigAttribute> csvParser(){
	List<ConfigAttribute> configAttributes=null;
	try {
		InputStream is=new FileInputStream(new File("config.txt"));
		BufferedReader br=new BufferedReader(new InputStreamReader(is));
		configAttributes=br.lines()
				.filter(line -> !(line.trim().equals("")) &&  !(line.startsWith("**") ||line.endsWith("**")) )
				.map(FormFactory::mapToConfig1)
				.collect(Collectors.toList());
		br.close();
	} catch (Exception e) {
		e.printStackTrace();
	}
	return configAttributes;
	
}

@SuppressWarnings("unchecked")
public List<FormConfiguration> createFormConfigurator (){
	
	List<FormConfiguration> configCollection=new ArrayList<FormConfiguration>();
	List<ConfigAttribute> configAttributes=csvParser();
	FormConfiguration config=new FormConfiguration();
	Hashtable<Integer,List<String>> ht;
	for (ConfigAttribute configAttribute :configAttributes ){
		String attributeName=configAttribute.getAttributeName();
		int formID=configAttribute.formID;
		String[] attributesValues=configAttribute.attributeValue;
		List<String> strList=Arrays.asList(attributesValues);
		int[] intArray;
		switch (attributeName){
			case "labelNames":
				config.setLabelNames( attributesValues);
				break;
				
			case "fieldNames":
				config.setFieldNames( attributesValues);
				break;
				
			case "fieldClass":
				config.setFieldClass(convertToclassArray( attributesValues));
				break;
				
			case "gridSize":
				config.setGridSize(Integer.parseInt(attributesValues[0]));
				break;
				
			case "formName":
				config.setFormName(attributesValues[0].trim());
				break;
				
			case "formClass":
					try {
						config.setFormClass(Class.forName(attributesValues[0]));
					} catch (ClassNotFoundException e) {
						e.printStackTrace();
					}
					break;
				
			case "fieldSize":
				intArray= strList.stream()
							.mapToInt(Integer::parseInt)
							.toArray();
							
				config.setFieldSize(intArray);
				
			case "verifiers":
				intArray= strList.stream()
				.mapToInt(Integer::parseInt)
				.toArray();
				
				config.setVerifiers(intArray);
				break;
				
			case "directions":
				intArray= strList.stream()
				.mapToInt(Integer::parseInt)
				.toArray();
				
				config.setDirection(intArray);
				break;
				
			case "optionsV":
				intArray= strList.stream()
				.mapToInt(Integer::parseInt)
				.toArray();
				 ht= getOptionsValues(intArray, configAttributes,formID);
				config.setFieldOptionsValue(ht);
				break;
				
			case "optionsD":
				intArray= strList.stream()
				.mapToInt(Integer::parseInt)
				.toArray();
				 ht= getOptionsValues(intArray, configAttributes,formID );
				config.setFieldOptionsDisplay(ht);
				break;
				
			case "color":
				config.setFormColor(mapToColor(attributesValues));
				configCollection.add(config);
				config=new FormConfiguration();
		}
		
	}
	return configCollection;
}


Color mapToColor(String[] colorArray){
	
	return new Color(Integer.parseInt(colorArray[0]),Integer.parseInt(colorArray[1]),Integer.parseInt(colorArray[2]));
}


public Hashtable<Integer,List<String>> getOptionsValues(int[] intArray,List<ConfigAttribute> configAttributes,int formID){
	Hashtable<Integer,List<String>> ht=new Hashtable<Integer,List<String>>();
	int count=0;
	Predicate<ConfigAttribute> myFilter=null;
	for (int i : intArray){
		if (count % 2 ==0){
			 myFilter= (att  -> att.getAttributeName().contains("options"+i));
		}
		if (count % 2 ==1){
			List<String> list=configAttributes.stream()
						.filter(att -> att.formID==formID)
						.filter(myFilter)
						.map(FormFactory::maptoList)
						.flatMap(List::stream)
						.collect(Collectors.toList());
			ht.put(i, (List<String>)list);
		}
		count++;
	}
	return ht;
}

public static List<String> maptoList (ConfigAttribute configAttribute){
	List<String> attrtibuteValueList=Arrays.asList(configAttribute.getAttributeValue());
	return attrtibuteValueList;
	
}



public void addForms(Repository repository){
	
	List<FormConfiguration> configCollection=createFormConfigurator();
	for (FormConfiguration config : configCollection){
		config.setRepository(repository);
		GenericForm3 form=new GenericForm3(config);
		formCollection.put(config.formName, form);
	}

}



public  Class<?>[] convertToclassArray(String[] array){
	
	Class<?>[] classArray=new Class<?>[array.length];
	List<Class<?>> classList= Arrays.asList(array).stream()
							.map(FormFactory::mapToClass)
							.collect(Collectors.toList());
	
	 classList.toArray(classArray);
	 return classArray;
	 
	
}

public static Class<?> mapToClass(String str){
	
	switch (str){
	case "1":
		return JTextField.class;
	case "2":
		return JTextArea.class;
	case "3":
		return RoundedTextField.class;
	case "4":
		return RoundedTextArea.class;
	case "5":
		return RadioButtons.class;
		
	}
	return null;
}


}
