package addOns;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.stream.Collectors;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.JSplitPane;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.text.NumberFormatter;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonIOException;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;

import addOns.JSON.HolonElementSketch;
import api.AddOn;
import classes.AbstractCanvasObject;
import classes.GroupNode;
import classes.HolonElement;
import classes.HolonObject;
import ui.controller.Control;
import ui.view.RandomPriotity;
import utility.Random;
import utility.ImageImport;

public class Randomizer implements AddOn {
	private Control  control;
	private int minAmountOfElements = 3;
	private int maxAmountOfElements = 7;
	private JPanel content = new JPanel();
	private JPanel tablePanel = new JPanel();
	private RandomPriotity prioPanel = new RandomPriotity();
	private JCheckBox priorityCheckbox = new JCheckBox("Random");
	private boolean useRandomPriority = true;
	
	//To Test the Layout Faster   
	public static void main(String[] args)
    {
        JFrame newFrame = new JFrame("exampleWindow");
        Randomizer instance = new Randomizer();
        newFrame.setContentPane(instance.getPanel());
        newFrame.pack();
        newFrame.setVisible(true);
	      newFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
	private File file;
	public double randomChance = 1.0;
	
	
	private HashMap<HolonObject, Boolean> objectMap = new HashMap<HolonObject, Boolean>();
	private List<JCheckBox> checkboxList = new ArrayList<JCheckBox>();
	
	
	
	
	
	
	public Randomizer(){
		for(int i = 0; i < 30; i++) {
			objectMap.put(new HolonObject("dude"), true);
		}
		content.setLayout(new BorderLayout());
		JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, createParameterPanel(), createFilterPanel());
		splitPane.setDividerLocation(0.5);
		content.add(splitPane, BorderLayout.CENTER);
		
		JButton buttonRun = new JButton("Run");
		buttonRun.addActionListener(actionEvent -> run());
		content.add(buttonRun, BorderLayout.PAGE_END);
	}
	private JScrollPane createFilterPanel() {
		//Table
		
		tablePanel.setLayout(new BoxLayout(tablePanel, BoxLayout.PAGE_AXIS));
		JScrollPane scrollPanel = new JScrollPane(tablePanel);
		scrollPanel.setPreferredSize(new Dimension(300,300));
		
		
		
		fillTablePanel();
		return scrollPanel;
	}
	
	private void fillTablePanel() {
		//Clear old Data
		tablePanel.removeAll();
		checkboxList.clear();
		
		//HeadPanel
		int lineSpace = 20;
		JPanel headPanel = new JPanel();
		headPanel.setLayout(new BoxLayout(headPanel, BoxLayout.LINE_AXIS));
		headPanel.add(new JLabel("FILTER"));
		JButton updateButton = new JButton();
		updateButton.setIcon(new ImageIcon(ImageImport.loadImage("Images/replace.png", 15, 15)));
		updateButton.addActionListener(action -> {
			this.updateFilterList();
			content.updateUI();
		});
		updateButton.setToolTipText("Manuel updates the filter list with all canvas objects.");
		headPanel.add(updateButton);
		headPanel.add(Box.createHorizontalGlue());
		headPanel.add(new JLabel("SelectAll"));
		JCheckBox selectAllCheckbox = new JCheckBox();
		selectAllCheckbox.setSelected(true);
		selectAllCheckbox.addItemListener(input -> checkboxList.forEach(box -> box.setSelected(selectAllCheckbox.isSelected())));
		headPanel.add(selectAllCheckbox);
		tablePanel.add(headPanel);
		
		
		//Entrys
		for(HolonObject hObject: objectMap.keySet().stream().sorted(Comparator.comparing(ob -> ob.getName())).collect(Collectors.toList())) {
			//Entry
			JPanel entryPanel = new JPanel();
			entryPanel.setLayout(new BoxLayout(entryPanel, BoxLayout.LINE_AXIS));
			JLabel label = new JLabel(hObject.getName() + "[" + hObject.getId() + "]", new ImageIcon(ImageImport.loadImage(hObject.getImage(), lineSpace, lineSpace)), JLabel.LEFT);
			entryPanel.add(label);
			entryPanel.add(Box.createHorizontalGlue());
			JCheckBox checkbox = new JCheckBox();
			checkbox.setSelected(true);
			checkbox.addItemListener(change -> {
				objectMap.put(hObject, checkbox.isSelected());
				System.out.println("hObject:" + hObject + " changed to " + checkbox.isSelected());
			});
			checkboxList.add(checkbox);
			entryPanel.add(checkbox);
			tablePanel.add(entryPanel);
		}
	}
	
	
	private JSplitPane createParameterPanel() {
		
		JPanel choosePanel = new JPanel(null);
		choosePanel.setPreferredSize(new Dimension(300,200));
		choosePanel.setMinimumSize(new Dimension(300,200));
		JLabel minAmount = new JLabel("minAmountOfElements:");
		minAmount.setBounds(20, 60 , 200, 20);
		choosePanel.add(minAmount);
		JLabel maxAmount = new JLabel("maxAmountOfElements:");
		maxAmount.setBounds(20, 85 , 200, 20);
		choosePanel.add(maxAmount);
		
		//Integer formatter
		NumberFormat format = NumberFormat.getIntegerInstance();
		format.setGroupingUsed(false);
		format.setParseIntegerOnly(true);
		NumberFormatter integerFormatter = new NumberFormatter(format);
		integerFormatter.setMinimum(0);
		integerFormatter.setCommitsOnValidEdit(true);
				
				
		JFormattedTextField minAmountTextField = new  JFormattedTextField(integerFormatter);
		minAmountTextField.setValue(this.minAmountOfElements);
		minAmountTextField.setToolTipText("Only positive Integer.");
		minAmountTextField.addPropertyChangeListener(actionEvent -> this.minAmountOfElements = Integer.parseInt(minAmountTextField.getValue().toString()));
		minAmountTextField.setBounds(220, 60, 50, 20);
		choosePanel.add(minAmountTextField);
		
		JFormattedTextField maxAmountTextField = new  JFormattedTextField(integerFormatter);
		maxAmountTextField.setValue(this.maxAmountOfElements);
		maxAmountTextField.setToolTipText("Only positive Integer.");
		maxAmountTextField.addPropertyChangeListener(actionEvent -> this.maxAmountOfElements = Integer.parseInt(maxAmountTextField.getValue().toString()));
		maxAmountTextField.setBounds(220, 85, 50, 20);
		choosePanel.add(maxAmountTextField);
		
		JButton chooseFileButton = new JButton("Choose File");
		chooseFileButton.setBounds(20, 10, 200, 30);
		chooseFileButton.addActionListener(actionEvent -> file = openCatalogFile());
		choosePanel.add(chooseFileButton);
		
		
		JSlider bitSlider = createFlipChanceSlider();
		bitSlider.setBounds(10, 110, 280, 80);
		choosePanel.add(bitSlider);
		
		JPanel prioritySelectionPanel = new JPanel();
		prioritySelectionPanel.setLayout(new BoxLayout(prioritySelectionPanel, BoxLayout.PAGE_AXIS));
		//priorityCheckbox.setAlignmentY(0.0f);
		//selection
		prioritySelectionPanel.add(this.priorityCheckbox);
		priorityCheckbox.addItemListener(change -> {
			prioPanel.setEnabled(priorityCheckbox.isSelected());
			useRandomPriority = priorityCheckbox.isSelected();
		});
		priorityCheckbox.setSelected(useRandomPriority);
		
		
		prioritySelectionPanel.add(prioPanel);
		JSplitPane parameterPanel = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, choosePanel, prioritySelectionPanel);
		parameterPanel.setPreferredSize(new Dimension(600,200));
		
		return parameterPanel;
	}
	
	private void run() {
		List<HolonElementSketch> holonElementCatalog = new ArrayList<HolonElementSketch>();
		if(file == null)file = openCatalogFile();
		if(file == null) return;
		readCatalogFromJson(file, holonElementCatalog);
		holonElementCatalog.forEach(con -> con.checkValues());
		objectMap.forEach((hObject, state) ->{
			//Ignore Filtered objects 
			System.out.println("hObject:" + hObject + " state:" + state);
			if(!state) {
				return;
			}
			//Randomize
			hObject.getElements().clear();
			int randomAmountOfElementsToAdd = Random.nextIntegerInRange(minAmountOfElements, maxAmountOfElements + 1);
			for(int i = 0; i < randomAmountOfElementsToAdd; i++) {
				HolonElement ele = holonElementCatalog.get(Random.nextIntegerInRange(0, holonElementCatalog.size())).createHolonElement(control.getModel(), Random.nextDouble() < randomChance , hObject.getName());
				if(this.useRandomPriority) ele.setPriority(prioPanel.getPriority());
				hObject.getElements().add(ele);				
			}
			
		});
		control.calculateStateAndVisualForCurrentTimeStep();
		control.updateCanvas();
		
		
	}
	
	private void fillObjectMap(List<AbstractCanvasObject> nodes) {
		for (AbstractCanvasObject aCps : nodes) {
			if (aCps instanceof HolonObject) {
				HolonObject hO = (HolonObject) aCps;
				objectMap.put(hO, true);
				
			}
			else if(aCps instanceof GroupNode) {
				fillObjectMap(((GroupNode)aCps).getNodes());
			}
		}
		
	}
	
	public void updateFilterList() {
		objectMap.clear();
		if(control != null)
			fillObjectMap(control.getModel().getObjectsOnCanvas());
		
		this.fillTablePanel();
	}
	
	@Override
	public JPanel getPanel() {
		return content;
	}
	@Override
	public void setController(Control control) {
		this.control = control;
		
		//Update Filter List
		updateFilterList();
	}
	

	private JSlider createFlipChanceSlider() {
		JSlider flipChance =new JSlider(JSlider.HORIZONTAL,0, 100, 100);
		flipChance.setBorder(BorderFactory.createTitledBorder("ActiveProbability"));
		flipChance.setMajorTickSpacing(50);
		flipChance.setMinorTickSpacing(5);
		flipChance.setPaintTicks(true);
		Hashtable<Integer, JLabel> labelTable = new Hashtable<Integer, JLabel>();
		labelTable.put( Integer.valueOf(0), new JLabel("0.0") );
		labelTable.put( Integer.valueOf(50), new JLabel("0.5") );
		labelTable.put( Integer.valueOf(100), new JLabel("1.0") );
		flipChance.setToolTipText("" +randomChance);
		flipChance.addChangeListener(actionEvent ->{
			randomChance  =(double)flipChance.getValue()/100.0;
			flipChance.setToolTipText("" +randomChance);
		});
		flipChance.setLabelTable( labelTable );
		flipChance.setPaintLabels(true);
		return flipChance;
	}
	
	
	
	
	private void readCatalogFromJson(File file, List<HolonElementSketch> catalog) {
		Gson gson = new Gson();
		JsonParser parser = new JsonParser();
		try {
			JsonElement jsonTreeRoot = parser.parse(new FileReader(file));
			if(jsonTreeRoot.isJsonArray()) {
				JsonArray jsonArray = jsonTreeRoot.getAsJsonArray();
				jsonArray.forEach(jsonObject -> {
					HolonElementSketch newObject= gson.fromJson( jsonObject, HolonElementSketch.class);
					System.out.println(gson.toJson(newObject));
					
					catalog.add(newObject);
				});
			}	
		} catch (JsonSyntaxException e) {
			e.printStackTrace();
		} catch (JsonIOException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		
	}
	
	
	
	
	
	public File openCatalogFile() {		
		JFileChooser fileChooser = new JFileChooser();
		fileChooser.setCurrentDirectory(new File(System.getProperty("user.dir")+"/randomizerConfigFiles/"));
		fileChooser.setFileFilter(new FileNameExtensionFilter("JSON Files", "json"));
		fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
		fileChooser.setAcceptAllFileFilterUsed(false);
		int result = fileChooser.showOpenDialog(content);
		if(result == JFileChooser.APPROVE_OPTION) {
			//Found a file
			return fileChooser.getSelectedFile();
		}
		return null;
	}

}
