package hr.fer.zemris.ffr.desktop.formCreator;

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyVetoException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.prefs.Preferences;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSeparator;

public class GUI extends JFrame {

	private static final long serialVersionUID = 1L;
	private JDesktopPane desktopPane;
	ActionMap actionMap;
	List<ProjectGUI> internalFramesList;
	private Preferences prefs;
	
	public GUI() {
		prefs = Preferences.userNodeForPackage(GUI.class);
		String guiLocale = prefs.get("guiLocale", "");
		String dataLocale = prefs.get("dataLocale", "");
		if(guiLocale.equals("")) {
			guiLocale = "en_US";
			prefs.put("guiLocale", guiLocale);
		}
		if(dataLocale.equals("")) {
			dataLocale = "hr_HR";
			prefs.put("dataLocale", dataLocale);
		}
		Locale guiLoc = parseLocale(guiLocale);
		Locale dataLoc = parseLocale(dataLocale);
		setDefaultCloseOperation(DISPOSE_ON_CLOSE);
		setSize(800, 600);
		setTitle("Form Creator v0.1");
		I18NUtil.setCurrentLocale(guiLoc);
		I18NUtil.setSortingLocale(dataLoc);
		System.out.println("Current locale: "+I18NUtil.getCurrentLocale());
		System.out.println("Data locale: "+I18NUtil.getSortingLocale());
		createActions();
		adjustActionLanguage();
		createGUI();
		createMenus();
	}

	private Locale parseLocale(String locale) {
		int p = locale.indexOf('_');
		if(p==-1) return new Locale(locale);
		return new Locale(locale.substring(0,p), locale.substring(p+1));
	}

	private void adjustActionLanguage() {
		ResourceBundle bundle = ResourceBundle.getBundle("ActionLabels", I18NUtil.getCurrentLocale());
		adjustActionLanguage(bundle, "act.settings");
		adjustActionLanguage(bundle, "act.settings.language");
		adjustActionLanguage(bundle, "act.new");
		adjustActionLanguage(bundle, "act.open");
		adjustActionLanguage(bundle, "act.save");
		adjustActionLanguage(bundle, "act.save_as");
		adjustActionLanguage(bundle, "act.file");
		adjustActionLanguage(bundle, "act.exit");
		adjustActionLanguage(bundle, "act.produceForms");
		adjustActionLanguage(bundle, "act.produceLists");
		adjustActionLanguage(bundle, "act.students.load1");
		adjustActionLanguage(bundle, "act.rooms.load1");
		adjustActionLanguage(bundle, "act.schedule.alphabetical");
		adjustActionLanguage(bundle, "act.schedule.random");
		adjustActionLanguage(bundle, "act.schedule.load1");
		adjustActionLanguage(bundle, "act.answers.set1");
		adjustActionLanguage(bundle, "act.problems.set1");
		adjustActionLanguage(bundle, "act.groups.set1");
	}

	private void adjustActionLanguage(ResourceBundle bundle, String actionKey) {
		Action act;
		act = actionMap.get(actionKey);
		act.putValue(Action.NAME, bundle.getObject(actionKey));
		act.putValue(Action.ACTION_COMMAND_KEY, actionKey);
		act.putValue(Action.SHORT_DESCRIPTION, bundle.getObject(actionKey+".sd"));
		act.putValue(Action.LONG_DESCRIPTION, bundle.getObject(actionKey+".ld"));
	}
	
	private void createActions() {
		actionMap = new ActionMap();
		
		Action act = new AbstractAction() {
			private static final long serialVersionUID = 1L;
			@Override
			public void actionPerformed(ActionEvent e) {
				actionNew();
			}
		};
		actionMap.put("act.new", act);
		
		act = new AbstractAction() {
			private static final long serialVersionUID = 1L;
			@Override
			public void actionPerformed(ActionEvent e) {
			}
		};
		actionMap.put("act.file", act);
		
		act = new AbstractAction() {
			private static final long serialVersionUID = 1L;
			@Override
			public void actionPerformed(ActionEvent e) {
				actionOpen();
			}
		};
		actionMap.put("act.open", act);
		
		act = new AbstractAction() {
			private static final long serialVersionUID = 1L;
			@Override
			public void actionPerformed(ActionEvent e) {
				actionSave();
			}
		};
		actionMap.put("act.save", act);
		
		act = new AbstractAction() {
			private static final long serialVersionUID = 1L;
			@Override
			public void actionPerformed(ActionEvent e) {
				actionSaveAs();
			}
		};
		actionMap.put("act.save_as", act);
		
		act = new AbstractAction() {
			private static final long serialVersionUID = 1L;
			@Override
			public void actionPerformed(ActionEvent e) {
				actionExit();
			}
		};
		actionMap.put("act.exit", act);
		
		act = new AbstractAction() {
			private static final long serialVersionUID = 1L;
			@Override
			public void actionPerformed(ActionEvent e) {
				actionProduceForms();
			}
		};
		actionMap.put("act.produceForms", act);
		
		act = new AbstractAction() {
			private static final long serialVersionUID = 1L;
			@Override
			public void actionPerformed(ActionEvent e) {
			}
		};
		actionMap.put("act.settings", act);
		
		act = new AbstractAction() {
			private static final long serialVersionUID = 1L;
			@Override
			public void actionPerformed(ActionEvent e) {
				actionLanguage();
			}
		};
		actionMap.put("act.settings.language", act);

		act = new AbstractAction() {
			private static final long serialVersionUID = 1L;
			@Override
			public void actionPerformed(ActionEvent e) {
				actionProduceLists();
			}
		};
		actionMap.put("act.produceLists", act);
		
		act = new AbstractAction() {
			private static final long serialVersionUID = 1L;
			@Override
			public void actionPerformed(ActionEvent e) {
				actionStudentsLoad1();
			}
		};
		actionMap.put("act.students.load1", act);
		
		act = new AbstractAction() {
			private static final long serialVersionUID = 1L;
			@Override
			public void actionPerformed(ActionEvent e) {
				actionRoomsLoad1();
			}
		};
		actionMap.put("act.rooms.load1", act);
		
		act = new AbstractAction() {
			private static final long serialVersionUID = 1L;
			@Override
			public void actionPerformed(ActionEvent e) {
				actionScheduleLoad1();
			}
		};
		actionMap.put("act.schedule.load1", act);
		
		act = new AbstractAction() {
			private static final long serialVersionUID = 1L;
			@Override
			public void actionPerformed(ActionEvent e) {
				alphabeticalStudentSchedule();
			}
		};
		actionMap.put("act.schedule.alphabetical", act);
		
		act = new AbstractAction() {
			private static final long serialVersionUID = 1L;
			@Override
			public void actionPerformed(ActionEvent e) {
				randomStudentSchedule();
			}
		};
		actionMap.put("act.schedule.random", act);
		
		act = new AbstractAction() {
			private static final long serialVersionUID = 1L;
			@Override
			public void actionPerformed(ActionEvent e) {
				actionAnswersSet1();
			}
		};
		actionMap.put("act.answers.set1", act);
		
		act = new AbstractAction() {
			private static final long serialVersionUID = 1L;
			@Override
			public void actionPerformed(ActionEvent e) {
				actionProblemsSet1();
			}
		};
		actionMap.put("act.problems.set1", act);
		
		act = new AbstractAction() {
			private static final long serialVersionUID = 1L;
			@Override
			public void actionPerformed(ActionEvent e) {
				actionGroupsSet1();
			}
		};
		actionMap.put("act.groups.set1", act);
	}

	private void createMenus() {
		JMenuBar menuBar = new JMenuBar();
		JMenu m = new JMenu(actionMap.get("act.file"));
		menuBar.add(m);
		m.add(new JMenuItem(actionMap.get("act.new")));
		m.add(new JMenuItem(actionMap.get("act.open")));
		m.add(new JMenuItem(actionMap.get("act.save")));
		m.add(new JMenuItem(actionMap.get("act.save_as")));
		m.add(new JSeparator());
		m.add(new JMenuItem(actionMap.get("act.exit")));
		m = new JMenu(actionMap.get("act.settings"));
		menuBar.add(m);
		m.add(new JMenuItem(actionMap.get("act.settings.language")));
		this.setJMenuBar(menuBar);
	}

	protected void actionNew() {
		ProjectGUI p = new ProjectGUI(this);
		p.setVisible(true);
		desktopPane.add(p);
		try {
			p.setSelected(true);
		} catch (PropertyVetoException ignorable) {
		}
	}

	protected void actionOpen() {
		ProjectGUI p = new ProjectGUI(this);
		if(!p.modelLoad()) {
			internalFramesList.remove(p);
			return;
		}
		String myAP = p.getProjectFileName().getAbsolutePath();
		for(ProjectGUI pg : internalFramesList) {
			if(pg==p) continue;
			if(pg.getProjectFileName()==null) continue;
			if(myAP.equals(pg.getProjectFileName().getAbsolutePath())) {
				try {
					pg.setSelected(true);
					internalFramesList.remove(p);
					return;
				} catch (PropertyVetoException ignorable) {
				}
			}
		}
		p.setVisible(true);
		desktopPane.add(p);
		try {
			p.setSelected(true);
		} catch (PropertyVetoException ignorable) {
		}
	}

	protected void actionSave() {
		ProjectGUI selpg = findSelectedProject();
		if(selpg==null) return;
		selpg.save();
	}

	protected void actionSaveAs() {
		ProjectGUI selpg = findSelectedProject();
		if(selpg==null) return;
		selpg.saveAs();
	}

	private static class ComboLanguageItem {
		String key;
		String value;
		
		public ComboLanguageItem(String key, String value) {
			super();
			this.key = key;
			this.value = value;
		}
		
		public String getKey() {
			return key;
		}
		
		public String getValue() {
			return value;
		}
		
		@Override
		public String toString() {
			return getValue();
		}

		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + ((key == null) ? 0 : key.hashCode());
			return result;
		}

		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			ComboLanguageItem other = (ComboLanguageItem) obj;
			if (key == null) {
				if (other.key != null)
					return false;
			} else if (!key.equals(other.key))
				return false;
			return true;
		}
	}
	
	protected void actionLanguage() {
		ResourceBundle bundle = ResourceBundle.getBundle("ActionLabels", I18NUtil.getCurrentLocale());
		DefaultComboBoxModel m1 = new DefaultComboBoxModel();
		m1.addElement(new ComboLanguageItem("en_US", bundle.getString("lang_en_US")));
		m1.addElement(new ComboLanguageItem("hr_HR", bundle.getString("lang_hr_HR")));
		DefaultComboBoxModel m2 = new DefaultComboBoxModel();
		m2.addElement(new ComboLanguageItem("en_US", bundle.getString("lang_en_US")));
		m2.addElement(new ComboLanguageItem("hr_HR", bundle.getString("lang_hr_HR")));

		String guiLocale = prefs.get("guiLocale", "");
		String dataLocale = prefs.get("dataLocale", "");
		for(int i = 0; i < m1.getSize(); i++) {
			ComboLanguageItem it = (ComboLanguageItem)m1.getElementAt(i);
			if(it.getKey().equals(guiLocale)) {
				m1.setSelectedItem(it);
			}
		}
		for(int i = 0; i < m2.getSize(); i++) {
			ComboLanguageItem it = (ComboLanguageItem)m2.getElementAt(i);
			if(it.getKey().equals(dataLocale)) {
				m2.setSelectedItem(it);
			}
		}
		JPanel p = new JPanel(new GridLayout(2,2));
		p.add(new JLabel(bundle.getString("lab.guiLanguage")));
		p.add(new JComboBox(m1));
		p.add(new JLabel(bundle.getString("lab.dataLanguage")));
		p.add(new JComboBox(m2));
		
		if(JOptionPane.OK_OPTION != JOptionPane.showConfirmDialog(this, p, bundle.getString("lab.selectLanguage"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE)) {
			return;
		}
		boolean change = false;
		String newGuiLocale = ((ComboLanguageItem)m1.getSelectedItem()).getKey();
		if(!newGuiLocale.equals(guiLocale)) {
			prefs.put("guiLocale", newGuiLocale);
			change = true;
			I18NUtil.setCurrentLocale(parseLocale(newGuiLocale));
		}
		String newDataLocale = ((ComboLanguageItem)m2.getSelectedItem()).getKey();
		if(!newDataLocale.equals(dataLocale)) {
			prefs.put("dataLocale", newDataLocale);
			change = true;
			I18NUtil.setSortingLocale(parseLocale(newDataLocale));
		}
		if(change) {
			adjustActionLanguage();
			for(ProjectGUI pg : internalFramesList) {
				pg.adjustLanguage();
			}
		}
	}
	
	private void actionExit() {
		System.exit(0);
	}

	protected void actionProduceForms() {
		ProjectGUI selpg = findSelectedProject();
		if(selpg==null) return;
		selpg.producePDF();
	}

	protected void actionProduceLists() {
		ProjectGUI selpg = findSelectedProject();
		if(selpg==null) return;
		selpg.produceSchedulePDF();
	}

	private ProjectGUI findSelectedProject() {
		ProjectGUI selpg = null;
		for(ProjectGUI pg : new LinkedList<ProjectGUI>(internalFramesList)) {
			if(pg.isSelected()) {
				selpg = pg;
				break;
			}
		}
		return selpg;
	}

	protected void actionStudentsLoad1() {
		ProjectGUI selpg = findSelectedProject();
		if(selpg==null) return;
		selpg.studentsLoad1();
	}

	protected void actionRoomsLoad1() {
		ProjectGUI selpg = findSelectedProject();
		if(selpg==null) return;
		selpg.roomsLoad1();
	}

	protected void actionScheduleLoad1() {
		ProjectGUI selpg = findSelectedProject();
		if(selpg==null) return;
		selpg.scheduleLoad1();
	}

	protected void actionAnswersSet1() {
		ProjectGUI selpg = findSelectedProject();
		if(selpg==null) return;
		selpg.answersSet1();
	}

	protected void actionProblemsSet1() {
		ProjectGUI selpg = findSelectedProject();
		if(selpg==null) return;
		selpg.problemsSet1();
	}

	protected void actionGroupsSet1() {
		ProjectGUI selpg = findSelectedProject();
		if(selpg==null) return;
		selpg.groupsSet1();
	}

	protected void alphabeticalStudentSchedule() {
		ProjectGUI selpg = findSelectedProject();
		if(selpg==null) return;
		selpg.alphabeticalStudentSchedule();
	}

	protected void randomStudentSchedule() {
		ProjectGUI selpg = findSelectedProject();
		if(selpg==null) return;
		selpg.randomStudentSchedule();
	}

	private void createGUI() {
		addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				handleWindowClosing();
			}
		});
		internalFramesList = new ArrayList<ProjectGUI>();
		desktopPane = new JDesktopPane();
		desktopPane.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
		setContentPane(desktopPane);
	}

	protected void handleWindowClosing() {
		boolean allNotClosed = false;
		for(ProjectGUI pg : new LinkedList<ProjectGUI>(internalFramesList)) {
			System.out.println("Zatvaram "+pg.getTitle());
			pg.closeFrame();
			if(pg.isVisible()) {
				allNotClosed = true;
				break;
			}
		}
		if(allNotClosed) {
			setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
		} else {
			setDefaultCloseOperation(DISPOSE_ON_CLOSE);
		}
	}
	
}
