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 FormConfiguration getFormConfigurator2(String formName,int gridSize){
		
		FormConfiguration formConfigurator=new FormConfiguration();
		String[] labelNames={"ID","FirstRelationship Age","Status","Longest Relationship","Sexual Orientation","Parents Status","Partnership Duration","Principles","Religion","Children","Siblings","Virgin","Health","Sex Life","Attractiveness","Happiness"};
		String[] fieldNames={"Id","FirstRelationshipAge","Status","LongestRelationship","SexualOrientation","ParentsStatus","PartnershipDuration","Principles","Religion","Children","Siblings","Virgin","Health","SexLife","Attractiveness","Happiness"};
		Class<?>[] fieldClass=new Class[] {RoundedTextField.class,RoundedTextField.class,RoundedTextField.class,RoundedTextField.class,RoundedTextField.class,RoundedTextField.class,RoundedTextField.class,RoundedTextArea.class,
				RoundedTextField.class,RoundedTextField.class,RoundedTextField.class,RadioButtons.class,RadioButtons.class,RadioButtons.class,RadioButtons.class,RadioButtons.class};
		int[] fieldSize=new int[] {5,5,25,25,25,25,25,25,25,5,5};
		int[] verifiers= new int[]{0,1,2,2,2,2,2,0,2,1,1,0,0,0,0,0};
		int[] directions= new int[]{0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1};
		
		Hashtable<Integer, List<String>> fieldOptionsDisplay=new Hashtable<>();
		List<String> listDisplay=Arrays.asList("Yes","No");
		
		Hashtable<Integer, List<String>> fieldOptionsValues=new Hashtable<>();
		List<String> listValues=Arrays.asList("1","0");
		
		fieldOptionsDisplay.put(11,listDisplay);
		fieldOptionsValues.put(11,listValues);
		
		listDisplay=Arrays.asList("1","2","3","4","5");
		listValues=Arrays.asList("1","2","3","4","5");
		
		fieldOptionsDisplay.put(12,listDisplay);
		fieldOptionsValues.put(12,listValues);
		fieldOptionsDisplay.put(13,listDisplay);
		fieldOptionsValues.put(13,listValues);
		fieldOptionsDisplay.put(14,listDisplay);
		fieldOptionsValues.put(14,listValues);
		fieldOptionsDisplay.put(15,listDisplay);
		fieldOptionsValues.put(15,listValues);
		
		formConfigurator.setLabelNames(labelNames);
		formConfigurator.setFieldNames(fieldNames);
		formConfigurator.setFieldClass(fieldClass);
		formConfigurator.setFieldSize(fieldSize);
		formConfigurator.setFieldOptionsDisplay(fieldOptionsDisplay);
		formConfigurator.setFieldOptionsValue(fieldOptionsValues);
		formConfigurator.setGridSize(gridSize);
		formConfigurator.setVerifiers(verifiers);
		formConfigurator.setDirection(directions);
		formConfigurator.setFormName("Relationship");
		
		Object formDataObject=null;
		 
		
		try {
			 //formDataObject=Class.forName(formName).newInstance();
			 formConfigurator.setFormClass(Class.forName(formName));
			 formConfigurator.setFormData(formDataObject);
			
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return formConfigurator;
	}
	
public static FormConfiguration getFormConfigurator1(String formName,int gridSize){
		
		FormConfiguration formConfigurator=new FormConfiguration();
		String[] labelNames={"Id","Age","Gender","Ethnicity","Occupation","Country","Origin","Education"};
		String[] fieldNames=labelNames;
		Class<?>[] fieldClass=new Class[] {JTextField.class,RoundedTextField.class,RadioButtons.class,RoundedTextField.class,RoundedTextField.class,RoundedTextField.class,RoundedTextField.class,RadioButtons.class};
		int[] fieldSize=new int[] {5,5,25,25,25,25,25,25};
		int[] verifiers= new int[]{0,1,0,2,2,2,2,2};
		int[] directions= new int[]{0,0,1,0,0,0,0,2};
		
		Hashtable<Integer, List<String>> fieldOptionsDisplay=new Hashtable<>();
		Hashtable<Integer, List<String>> fieldOptionsValues=new Hashtable<>();
		List<String> listDisplay=Arrays.asList("Male","Female");
		List<String> listValues=Arrays.asList("Male","Female");
		fieldOptionsDisplay.put(2,listDisplay);
		fieldOptionsValues.put(2,listValues);
		
		listDisplay=Arrays.asList("Did not attend school","Primary School","Secondary School","College/6th Form","University(Undergraduate)","Universirty(Post Graduate)","Other");
		listValues=listDisplay;
		fieldOptionsDisplay.put(7,listDisplay);
		fieldOptionsValues.put(7,listValues);
		
		formConfigurator.setLabelNames(labelNames);
		formConfigurator.setFieldNames(fieldNames);
		formConfigurator.setFieldClass(fieldClass);
		formConfigurator.setFieldSize(fieldSize);
		formConfigurator.setFieldOptionsValue(fieldOptionsValues);
		formConfigurator.setFieldOptionsDisplay(fieldOptionsDisplay);
		formConfigurator.setGridSize(gridSize);
		formConfigurator.setVerifiers(verifiers);
		formConfigurator.setDirection(directions);
		formConfigurator.setFormName("Participant");
		Object formDataObject=null;
		 
		
		try {
			
			// formDataObject=Class.forName(formName).newInstance();
			 formConfigurator.setFormClass(Class.forName(formName));
			 formConfigurator.setFormData(formDataObject);
			
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return formConfigurator;
	}

public static FormConfiguration getFormConfigurator3(String formName,int gridSize){
	
	FormConfiguration formConfigurator=new FormConfiguration();
	String[] labelNames={"Id","Alchocol Units","TV","Books","Best Attributes","Famil Gathering","Criminal Conviction","Hobbies","Describe Yourself","Free Time","Disappointment",
			"Excersise Per Week","Food","movies","Music","Worst Attribute","Smoke","Menopause","Favourite Quote",
			"Aspiration","Achievement","Passion"};
	String[] fieldNames={"Id","AlcoholUnits","Tv","Books","BestAttribute","FamilyGathering","CriminalConviction","Hobbies","DescribeYourself",
			"FreeTime","Disappointment","ExercisePerWeek","Food", "Movies","Music","WorstAttribute","Smoke","Menopause",
			"FavouriteQuote","Aspiration","Achievement","Passion"};
	Class<?>[] fieldClass=new Class[] {RoundedTextField.class,RoundedTextField.class,RoundedTextField.class,RoundedTextField.class,RoundedTextField.class,
			RadioButtons.class,RadioButtons.class,RoundedTextArea.class,RoundedTextArea.class,RoundedTextArea.class,RoundedTextArea.class,
			RoundedTextField.class,RoundedTextField.class,RoundedTextField.class,RoundedTextField.class,RoundedTextField.class,RadioButtons.class,RadioButtons.class,
			RoundedTextArea.class,RoundedTextArea.class,RoundedTextArea.class,RoundedTextArea.class};
	int[] fieldSize=new int[] {5,5,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20};
	int[] verifiers= new int[]{0,1,2,2,2,0,0,0,0,0,0,2,2,2,2,2,0,0,0,0,0,0};
	int[] directions= new int[]{0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0};
	
	Hashtable<Integer, List<String>> fieldOptionsDisplay=new Hashtable<>();
	Hashtable<Integer, List<String>> fieldOptionsValues=new Hashtable<>();
	List<String> listDisplay=Arrays.asList("Yes","No");
	List<String> listValues=Arrays.asList("1","0");
	for (int i=5;i<7;i++){
		fieldOptionsDisplay.put(i,listDisplay);
		fieldOptionsValues.put(i,listValues);
	}
	for (int i=16;i<18;i++){
		fieldOptionsDisplay.put(i,listDisplay);
		fieldOptionsValues.put(i,listValues);
	}

	
	
	formConfigurator.setLabelNames(labelNames);
	formConfigurator.setFieldNames(fieldNames);
	formConfigurator.setFieldClass(fieldClass);
	formConfigurator.setFieldSize(fieldSize);
	formConfigurator.setFieldOptionsValue(fieldOptionsValues);
	formConfigurator.setFieldOptionsDisplay(fieldOptionsDisplay);
	formConfigurator.setGridSize(gridSize);
	formConfigurator.setVerifiers(verifiers);
	formConfigurator.setDirection(directions);
	formConfigurator.setFormName("Interests");
	Object formDataObject=null;
	
	 
	
	try {
		
		// formDataObject=Class.forName(formName).newInstance();
		 formConfigurator.setFormClass(Class.forName(formName));
		 formConfigurator.setFormData(formDataObject);
		
		
	} catch (Exception e) {
		e.printStackTrace();
	}
	
	return formConfigurator;
}

static Function<String,ConfigAttribute> mapToConfig=(line) -> {
	String[] attributesArray=line.split("=");
	String[] attributeValues=attributesArray[1].split(",");
	String attributeName=attributesArray[0];
	System.out.println(attributeName);
	//System.out.println(attributeValues);
	Arrays.asList(attributeValues).forEach(System.out::print);
	ConfigAttribute configAttribute=new ConfigAttribute(attributeName, attributeValues,1);
	return configAttribute;
	
};

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++;
	}
	System.out.println(attributeName);
	Arrays.asList(attributeValues).forEach(System.out::print);
	Arrays.asList(attributeValues).forEach(System.out::print);
	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());
		System.out.println("Size of ConfigAttributes is ="+configAttributes.size());
		
		
	} catch (FileNotFoundException e) {
		e.printStackTrace();
	}
	return configAttributes;
	
}

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;
		System.out.println("attributes***********");
		System.out.println(attributeName);
		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());
				System.out.println(attributesValues[0]);
				break;
				
			case "formClass":
					try {
						config.setFormClass(Class.forName(attributesValues[0]));
						System.out.println(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);
				System.out.println("********formID="+formID);
				break;
			case "optionsD":
				intArray= strList.stream()
				.mapToInt(Integer::parseInt)
				.toArray();
				 ht= getOptionsValues(intArray, configAttributes,formID );
				config.setFieldOptionsDisplay(ht);
				System.out.println("**********formID="+formID);
				break;
			case "color":
				config.setFormColor(mapToColor(attributesValues));
				configCollection.add(config);
				config=new FormConfiguration();
				System.out.println("*********FormID in the Color="+formID);
				
		}
		
	}
	return configCollection;
	
}

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


public Hashtable getOptionsValues(int[] intArray,List<ConfigAttribute> configAttributes,int formID){
	Hashtable<Integer,List<String>> ht=new Hashtable<Integer,List<String>>();
	//List<Hashtable<Integer,List<String>>> htList=new ArrayList<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){
		System.out.println(i);
		System.out.println(intArray.length);
		System.out.println("count="+count);
		System.out.println("FormID in the Stream="+formID);
		configAttributes.stream()
		.filter(att  -> att.getAttributeName().contains("options"+i))
		.forEach(att -> System.out.println(att.attributeValue[0]));
		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);
		System.out.println("formName="+config.formName);
	}

}



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;
}


}
