/*
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License");  you may not use this file except in 
 * compliance with the License.  You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
 * the specific language governing rights and limitations under the License.
 *
 * The Original Code is Protege-2000.
 *
 * The Initial Developer of the Original Code is Stanford University. Portions
 * created by Stanford University are Copyright (C) 2007.  All Rights Reserved.
 *
 * Protege was developed by Stanford Medical Informatics
 * (http://www.smi.stanford.edu) at the Stanford University School of Medicine
 * with support from the National Library of Medicine, the National Science
 * Foundation, and the Defense Advanced Research Projects Agency.  Current
 * information about Protege can be obtained at http://protege.stanford.edu.
 *
 */

package edu.stanford.smi.protege.ui;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

import edu.stanford.smi.protege.action.ExportToCsvUtil;
import edu.stanford.smi.protege.model.KnowledgeBase;
import edu.stanford.smi.protege.model.Slot;
import edu.stanford.smi.protege.resource.Icons;
import edu.stanford.smi.protege.util.AllowableAction;
import edu.stanford.smi.protege.util.ApplicationProperties;
import edu.stanford.smi.protege.util.ComponentFactory;
import edu.stanford.smi.protege.util.ComponentUtilities;
import edu.stanford.smi.protege.util.FileField;
import edu.stanford.smi.protege.util.FileUtilities;
import edu.stanford.smi.protege.util.LabeledComponent;
import edu.stanford.smi.protege.util.ModalDialog;
import edu.stanford.smi.protege.util.SelectableList;

public class ExportConfigurationPanel {

	private KnowledgeBase kb;

	private JPanel configPanel;
	private JCheckBox exportTypesCheckBox;
	private JCheckBox exportHeaderCheckBox;
	private JCheckBox exportBrowserTextCheckBox;
	private JCheckBox exportMetadataCheckBox;
	private FileField fileField;
	private JTextField slotDelimiterTextField;
	private JTextField slotValuesDelimiterTextField;

	private List<Slot> slots = new ArrayList<Slot>();
	private Collection<Slot> possibleSlots = new ArrayList<Slot>();
	private String metadataString = "";


	//Ugly, but did not find a better solution
	private static HashMap<String, String> replaceChars = new HashMap<String, String>();

	static {
		replaceChars.put("\\t", "\t");
		replaceChars.put("\\b", "\b");
		replaceChars.put("\\n", "\n");
		replaceChars.put("\\f", "\f");
		replaceChars.put("\\r", "\r");
	}


	public ExportConfigurationPanel(KnowledgeBase kb) {
		this.kb = kb;
	}


	public JPanel getConfigPanel() {
		configPanel = new JPanel();
		configPanel.setLayout(new BoxLayout(configPanel, BoxLayout.Y_AXIS));

		fileField = new FileField("Exported file", getExportedFileName(), ExportToCsvUtil.EXPORT_FILE_EXTENSION, "Exported result files" );
		configPanel.add(fileField);

		LabeledComponent slotsListComp = getSlotsListComponent();
		configPanel.add(slotsListComp);

		configPanel.add(Box.createRigidArea(new Dimension(0, 10)));

		JPanel p1 = new JPanel(new GridLayout(2,2));
		p1.add(new JLabel("Slot delimiter"));
		slotDelimiterTextField = new JTextField(ExportToCsvUtil.getSlotsDelimiter(), 10);
		p1.add(slotDelimiterTextField);

		p1.add(new JLabel("Slot values delimiter"));
		slotValuesDelimiterTextField = new JTextField(ExportToCsvUtil.getSlotValuesDelimiter(), 10);
		p1.add(slotValuesDelimiterTextField);
		configPanel.add(p1);

		configPanel.add(Box.createRigidArea(new Dimension(0, 10)));

		JPanel p2 = new JPanel(new GridLayout(4,1));

		exportHeaderCheckBox = ComponentFactory.createCheckBox("Export slots name as first line in the file");
		exportHeaderCheckBox.setAlignmentX(Component.LEFT_ALIGNMENT);
		exportHeaderCheckBox.setSelected(true);
		p2.add(exportHeaderCheckBox);

		exportTypesCheckBox = ComponentFactory.createCheckBox("Export instance type(s)");
		exportTypesCheckBox.setAlignmentX(Component.LEFT_ALIGNMENT);
		exportTypesCheckBox.setSelected(false);
		p2.add(exportTypesCheckBox);

		exportBrowserTextCheckBox = ComponentFactory.createCheckBox("Export browser text (instead of name)");
		exportBrowserTextCheckBox.setAlignmentX(Component.LEFT_ALIGNMENT);
		exportBrowserTextCheckBox.setSelected(ExportToCsvUtil.isExportBrowserTextEnabled());
		p2.add(exportBrowserTextCheckBox);

		p2.add(getExportMetadataComponent());

		configPanel.add(p2);

		return configPanel;
	}


	private JComponent getExportMetadataComponent() {
		boolean exportMetadata = ExportToCsvUtil.isExportMetadata();

		JPanel p = new JPanel();
		p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));

		exportMetadataCheckBox = ComponentFactory.createCheckBox("Export additional text as last line in the file");
		exportMetadataCheckBox.setAlignmentX(Component.LEFT_ALIGNMENT);
		exportMetadataCheckBox.setSelected(exportMetadata);

		p.add(exportMetadataCheckBox);
		p.add(Box.createRigidArea(new Dimension(10, 0)));

		final JButton editTextButton = new JButton("Edit text");
		editTextButton.setEnabled(exportMetadata);
		editTextButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				onEditText();
			}
		});

		exportMetadataCheckBox.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				boolean selected = exportMetadataCheckBox.isSelected();
				editTextButton.setEnabled(selected);
				ExportToCsvUtil.setExportMetadata(selected);
			}
		});

		p.add(editTextButton);

		return p;
	}


	protected void onEditText() {
		 JTextArea _comment = ComponentFactory.createTextArea();
		 _comment.setPreferredSize(new Dimension(300, 150));
		 _comment.setText(getExportMetadataText());
		 LabeledComponent lc = new LabeledComponent("Information to be exported in the last line", new JScrollPane(_comment));
		 int rval = ModalDialog.showDialog(configPanel, lc, "Export information", ModalDialog.MODE_OK_CANCEL);
         if (rval == ModalDialog.OPTION_OK) {
        	 setExportMetadata(_comment.getText());
         }
	}


	private LabeledComponent getSlotsListComponent() {
		final SelectableList slotsList = ComponentFactory.createSelectableList(null);
		slotsList.setCellRenderer(FrameRenderer.createInstance());

		ComponentUtilities.addListValues(slotsList, slots);

		LabeledComponent labeledComp = new LabeledComponent("Slots to export", new JScrollPane(slotsList), true );

		labeledComp.addHeaderButton(new AllowableAction("Add slots", Icons.getAddSlotIcon(), null) {

			public void actionPerformed(ActionEvent e) {
				HashSet<Slot> allSlots = new HashSet<Slot>();
				Iterator j = kb.getSlots().iterator();
				while (j.hasNext()) {
					Slot s = (Slot) j.next();
					if (!s.isSystem()) {
						allSlots.add(s);
					}
				}

				allSlots.add(kb.getNameSlot());
				allSlots.addAll(possibleSlots);

				List allSlotsList = new ArrayList<Slot>(allSlots);
				Collections.sort(allSlotsList, new FrameComparator());

				// Show util window for multiple slot selection
				Collection<Slot> newSlots = DisplayUtilities.pickSlots(configPanel, allSlotsList, "Select slots to export (multiple selection)");
				addSlotsIfNotExists(newSlots);

				ComponentUtilities.clearListValues(slotsList);
				ComponentUtilities.addListValues(slotsList, slots);
			}

		});

		labeledComp.addHeaderButton(new AllowableAction("Remove slot", Icons.getRemoveSlotIcon(), slotsList) {

			public void actionPerformed(ActionEvent arg0) {
				Collection selection = getSelection();

				if (selection != null) {
					slots.removeAll(selection);
				}

				ComponentUtilities.clearListValues(slotsList);
				ComponentUtilities.addListValues(slotsList, slots);
			}

		});

		return labeledComp;
	}

	private void addSlotsIfNotExists(Collection<Slot> newSlots) {
		for (Slot slot : newSlots) {
			if (!slots.contains(slot)) {
				slots.add(slot);
			}
		}
	}

	@SuppressWarnings("deprecation")
	private String getExportedFileName(){
		String projPath = kb.getProject().getProjectFilePath();;
		String projName = kb.getProject().getProjectName();

		if (kb.getProject().isMultiUserClient()) {
			//use the application directory
			projPath = ApplicationProperties.getApplicationDirectory().getAbsolutePath();
			projName = "query";
		}

		String filename = FileUtilities.replaceFileName(projPath, projName + ExportToCsvUtil.EXPORT_FILE_PREFIX);
		filename = filename + "." + ExportToCsvUtil.EXPORT_FILE_EXTENSION;

		return filename;
	}


	public boolean isExportTypesEnabled() {
		return exportTypesCheckBox.isSelected();
	}

	public Collection<Slot> getExportedSlots() {
		return slots;
	}

	public File getExportedFile() {
		return fileField.getFilePath();
	}

	public boolean isExportHeaderEnabled() {
		return exportHeaderCheckBox.isSelected();
	}

	public boolean isExportBrowserTextEnabled(){
		return exportBrowserTextCheckBox.isSelected();
	}

	public boolean isExportMetadataEnabled() {
		return exportMetadataCheckBox.isSelected();
	}

	public String getSlotDelimiter() {
		return getDelimiterString(slotDelimiterTextField.getText());
	}

	public String getSlotValuesDelimiter() {
		return getDelimiterString(slotValuesDelimiterTextField.getText());
	}

	//Ugly, but did not find better solution
	private String getDelimiterString(String string) {
		String newString = new String(string);

		for (Object element : replaceChars.keySet()) {
			String ch = (String) element;
			newString = newString.replace(ch, replaceChars.get(ch));
		}

		return newString;
	}


	public Collection<Slot> getPossibleSlots() {
		return possibleSlots;
	}


	/**
	 * Give a chance to other parts of the code to set the slots that will show up
	 * when clicking on the "Add Slot" button
	 * @param possibleSlots
	 */
	public void setPossibleSlots(Collection<Slot> possibleSlots) {
		this.possibleSlots = possibleSlots;
	}

	public String getExportMetadataText() {
		return metadataString;
	}

	public void setExportMetadata(String text) {
		metadataString = text;
	}

}
