/*
 * Copyright 2008-2014, David Karnok 
 * The file is part of the Open Imperium Galactica project.
 * 
 * The code should be distributed under the LGPL license.
 * See http://www.gnu.org/licenses/lgpl.html for details.
 */

package hu.openig.editors.ce;

import hu.openig.core.Pair;
import hu.openig.model.GameDefinition;
import hu.openig.model.Parameters;
import hu.openig.utils.Exceptions;
import hu.openig.utils.XElement;

import java.awt.BorderLayout;
import java.awt.Desktop;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.GroupLayout.ParallelGroup;
import javax.swing.GroupLayout.SequentialGroup;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

/**
 * The main definition panel.
 * @author akarnokd, 2012.12.17.
 */
public class CEDefinitionPanel extends CEBasePanel implements CEPanelPreferences {
	/** */
	private static final long serialVersionUID = 3418547993103195127L;
	/** The element names. */
	static final String[] ELEMENT_NAMES = {
		"intro", "image", "battle", "bridge", "buildings",
		"diplomacy", "galaxy", "planets", "players",
		"talks", "tech", "test", "walks", "scripting",
		"chats", "spies"
	};
	/** The parameter names. */
	static final String[] PARAM_NAMES = {
		"groundRadarUnitSize", "fleetRadarUnitSize", "researchSpeed", 
		"productionUnit", "constructionSpeed", "constructionCost",
		"repairSpeed", "repairCost", "costToHitpoints", 
		"nearbyDistance", "simulationRatio", "fleetSpeed",
		"stationLimit", "battleshipLimit", "mediumshipLimit", 
		"fighterLimit", "radarShareLimit"
	};
	/** Campaign field. */
	JComboBox<String> levelField;
	/** Campaign field. */
	JComboBox<String> techLevelField;
	/** The tabs. */
	JTabbedPane tabs;
	/** The campaign's directory. */
	JTextField directory;
	/** The indicators. */
	final Map<String, JLabel> indicators = new LinkedHashMap<>();
	/** The input fields. */
	final Map<String, JTextField> fields = new LinkedHashMap<>();
	/** The language fields. */
	final List<JTextField> languageFields = new ArrayList<>();
	/** The language fields. */
	final List<JTextField> titleFields = new ArrayList<>();
	/** The language fields. */
	final List<JTextArea> descriptionFields = new ArrayList<>();
	/** The texts subpanel. */
	JPanel textsSubPanel;
	/**
	 * Constructor. Initializes the panel.
	 * @param ctx the context
	 */
	public CEDefinitionPanel(CEContext ctx) {
		super(ctx);
		initComponents();
	}
	/** Initialize the content. */
	void initComponents() {
		
		JLabel directoryLabel = new JLabel(get("definition.Directory"));
		directory = new JTextField();
		directory.setEditable(false);
		JButton openDir = new JButton(get("definition.Directory.Open"));

		JPanel panel2 = new JPanel();
		GroupLayout gl = new GroupLayout(panel2);
		panel2.setLayout(gl);
		gl.setAutoCreateContainerGaps(true);
		gl.setAutoCreateGaps(true);
		
		gl.setHorizontalGroup(
			gl.createParallelGroup()
			.addGroup(
				gl.createSequentialGroup()
				.addComponent(directoryLabel)
				.addComponent(directory)
				.addComponent(openDir)
			)
		);
		
		gl.setVerticalGroup(
			gl.createSequentialGroup()
			.addGroup(
				gl.createParallelGroup(Alignment.BASELINE)
				.addComponent(directoryLabel)
				.addComponent(directory, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
				.addComponent(openDir)
			)
		);
		
		tabs = new JTabbedPane();
		tabs.addTab(get("definition.Texts"), createTextsPanel());
		tabs.addTab(get("definition.References"), createReferencesPanel());
		tabs.addTab(get("definition.Properties"), createPropertiesPanel());
		
		setLayout(new BorderLayout());
		add(panel2, BorderLayout.PAGE_START);
		add(tabs, BorderLayout.CENTER);
		
		// ---------------------------------
		
		openDir.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				
				if (Desktop.isDesktopSupported()) {
					Desktop d = Desktop.getDesktop();
					try {
						d.open(context.dataManager().getDefinitionDirectory().getCanonicalFile());
					} catch (IOException e1) {
						Exceptions.add(e1);
					}
				}
			}
		});
	}
	/** @return Create the textual descriptions panel. */
	JPanel createTextsPanel() {
		JPanel p = new JPanel();
		p.setLayout(new BorderLayout());
		
		textsSubPanel = new JPanel();
		JScrollPane comp = new JScrollPane(textsSubPanel);
		comp.getVerticalScrollBar().setBlockIncrement(90);
		comp.getVerticalScrollBar().setUnitIncrement(30);
		p.add(comp, BorderLayout.CENTER);
		
		return p;
	}
	/** @return The referenced main data files panel. */
	JPanel createReferencesPanel() {
		JPanel p = new JPanel();
		
		GroupLayout gl = new GroupLayout(p);
		p.setLayout(gl);
		gl.setAutoCreateContainerGaps(true);
		gl.setAutoCreateGaps(true);
		
		SequentialGroup rows = gl.createSequentialGroup();
		ParallelGroup col1 = gl.createParallelGroup();
		ParallelGroup col2 = gl.createParallelGroup();
		ParallelGroup col3 = gl.createParallelGroup();

		for (String a : ELEMENT_NAMES) {
			JLabel indicator = new JLabel();
			JLabel caption = new JLabel(get("definition.ref_" + a));
			JTextField textField = new JTextField();
			
			indicators.put(a, indicator);
			fields.put(a, textField);
			
			ParallelGroup pg = gl.createParallelGroup(Alignment.BASELINE);
			
			col1.addComponent(caption);
			col2.addComponent(textField);
			col3.addComponent(indicator, 20, 20, 20);
			
			pg.addComponent(caption);
			pg.addComponent(textField, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE);
			pg.addComponent(indicator, 20, 20, 20);
			
			rows.addGroup(pg);
		}
		
		gl.setHorizontalGroup(
			gl.createSequentialGroup()
			.addGroup(col1)
			.addGroup(col2)
			.addGroup(col3)
		);
		gl.setVerticalGroup(rows);
		
		return p;
	}
	/**
	 * @return the properties listing panel
	 */
	JPanel createPropertiesPanel() {
		JPanel p = new JPanel();
		
		GroupLayout gl = new GroupLayout(p);
		p.setLayout(gl);
		gl.setAutoCreateContainerGaps(true);
		gl.setAutoCreateGaps(true);
		
		SequentialGroup rows = gl.createSequentialGroup();
		ParallelGroup col1 = gl.createParallelGroup();
		ParallelGroup col2 = gl.createParallelGroup();
		ParallelGroup col3 = gl.createParallelGroup();
		
		for (String a : PARAM_NAMES) {
			JLabel indicator = new JLabel();
			JLabel caption = new JLabel(get("definition.refprop_" + a));
			JTextField textField = new JTextField(10);
			textField.setHorizontalAlignment(JTextField.RIGHT);
			caption.setToolTipText(get("definition.refprop_" + a + ".tip"));
			textField.setToolTipText(get("definition.refprop_" + a + ".tip"));
			
			indicators.put(a, indicator);
			fields.put(a, textField);
			
			ParallelGroup pg = gl.createParallelGroup(Alignment.BASELINE);
			
			col1.addComponent(caption);
			col2.addComponent(textField, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE);
			col3.addComponent(indicator, 20, 20, 20);
			
			pg.addComponent(caption);
			pg.addComponent(textField, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE);
			pg.addComponent(indicator, 20, 20, 20);
			
			rows.addGroup(pg);
		}
		
		gl.setHorizontalGroup(
			gl.createSequentialGroup()
			.addGroup(col1)
			.addGroup(col2)
			.addGroup(col3)
		);
		gl.setVerticalGroup(rows);

		
		return p;
	}
	@Override
	public void loadPreferences(XElement preferences) {
		// TODO Auto-generated method stub

	}

	@Override
	public void savePreferences(XElement preferences) {
		// TODO Auto-generated method stub

	}

	@Override
	public String preferencesId() {
		return "definition-panel";
	}
	/**
	 * Update the text fields.
	 */
	void updateTexts() {
		textsSubPanel.removeAll();
		GroupLayout gl0 = new GroupLayout(textsSubPanel);
		textsSubPanel.setLayout(gl0);
		
		languageFields.clear();
		titleFields.clear();
		descriptionFields.clear();
		
		ParallelGroup hg = gl0.createParallelGroup(Alignment.CENTER);
		SequentialGroup vg = gl0.createSequentialGroup();
		
		final GameDefinition definition = context.campaignData().definition;
		for (final String lang : definition.languages()) {
			textsSubPanel.add(new JSeparator(JSeparator.HORIZONTAL));
			
			JLabel langLabel = new JLabel(get("definition_language"));
			JTextField langField = new JTextField(lang, 2);
			JLabel titleLabel = new JLabel(get("definition_title"));
			JTextField titleField = new JTextField(definition.getTitle(lang));
			JLabel descLabel = new JLabel(get("definition_description"));
			JTextArea descField = new JTextArea(definition.getDescription(lang));
			JButton remove = new JButton(icon("/hu/openig/gfx/minus16.png"));
			remove.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent e) {
					definition.texts.remove(lang);
					updateTexts();
				}
			});
			
			languageFields.add(langField);
			titleFields.add(titleField);
			descriptionFields.add(descField);
			
			JPanel p = new JPanel();
			GroupLayout gl = new GroupLayout(p);
			p.setLayout(gl);
			gl.setAutoCreateContainerGaps(true);
			gl.setAutoCreateGaps(true);
			
			gl.setHorizontalGroup(
				gl.createSequentialGroup()
				.addGroup(
					gl.createParallelGroup()
					.addGroup(
						gl.createSequentialGroup()
						.addComponent(langLabel)
						.addComponent(langField, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
						.addGap(30)
						.addComponent(titleLabel)
						.addComponent(titleField)
					)
					.addGroup(
						gl.createSequentialGroup()
						.addComponent(descLabel)
						.addComponent(descField)
					)
				)
				.addComponent(remove)
			);
			gl.setVerticalGroup(
				gl.createParallelGroup(Alignment.CENTER)
				.addGroup(
					gl.createSequentialGroup()
					.addGroup(
						gl.createParallelGroup(Alignment.BASELINE)
						.addComponent(langLabel)
						.addComponent(langField, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
						.addComponent(titleLabel)
						.addComponent(titleField, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
					)
					.addGroup(
						gl.createParallelGroup(Alignment.BASELINE)
						.addComponent(descLabel)
						.addComponent(descField, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
					)
				)
				.addComponent(remove)
			);
			
			JSeparator sep = new JSeparator(JSeparator.HORIZONTAL);
			
			hg.addComponent(p);
			vg.addComponent(p);

			hg.addComponent(sep);
			vg.addComponent(sep, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE);
			
		}
		
		JButton addNew = new JButton(icon("/hu/openig/gfx/plus16.png"));
		addNew.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				doAddNewLanguage();
			}
		});
		
		hg.addComponent(addNew);
		vg.addComponent(addNew);
		
		gl0.setHorizontalGroup(hg);
		gl0.setVerticalGroup(vg);
		
	}
	/**
	 * Add a new language.
	 */
	void doAddNewLanguage() {
		GameDefinition definition = context.campaignData().definition;
		String n = Integer.toString(definition.languages().size() + 1);
		definition.texts.put(n, Pair.of("", ""));
		updateTexts();
	}
	/**
	 * Load the fields.
	 */
	public void load() {
		CampaignData cd = context.campaignData();
		try {
			directory.setText(context.dataManager().getDefinitionDirectory().getCanonicalPath());
		} catch (IOException e1) {
			Exceptions.add(e1);
		}
		for (String a : ELEMENT_NAMES) {
			JTextField tf = fields.get(a);
			tf.setText(cd.def.childValue(a));
		}
		Parameters params = new Parameters(null);
		XElement xparam = cd.def.childElement("parameters");
		if (xparam != null) {
			for (String a : PARAM_NAMES) {
				JTextField tf = fields.get(a);
				String val = xparam.get(a, null);
				if (val == null) {
					try {
						val = Parameters.class.getField(a).get(params).toString();
					} catch (Exception ex) {
						Exceptions.add(ex);
					}
				}
				tf.setText(val);
			}
		}
		updateTexts();
	}
}