/*
 * File:     MergeStep1.java
 * Project:  MPI Linguistic Application
 * Date:     03 April 2006
 *
 * Copyright (C) 2001-2006  Max Planck Institute for Psycholinguistics
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package mpi.eudico.client.annotator.imports;

import mpi.eudico.client.annotator.ElanLocale;
import mpi.eudico.client.annotator.Preferences;

import mpi.eudico.client.annotator.gui.multistep.MultiStepPane;
import mpi.eudico.client.annotator.gui.multistep.StepPane;

import mpi.eudico.client.annotator.util.ElanFileFilter;
import mpi.eudico.client.annotator.util.FileExtension;

import mpi.eudico.server.corpora.clomimpl.abstr.TranscriptionImpl;

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;

import java.io.File;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;
import javax.swing.filechooser.FileFilter;


/**
 * The first step of a merge process. Two sources can be specified and a destination
 * (file name) for the merged transcriptions. The first source (the transcription
 * tiers are going to be added to) can either be a file name or a transcription loaded
 * in ELAN.
 *
 * @author Han Sloetjes
 * @version 1.0
 */
public class MergeStep1 extends StepPane implements ActionListener,
    ItemListener {
    private TranscriptionImpl curTranscription;
    private JButton browseSource1;
    private JButton browseSource2;
    private JButton browseDest;
    private JLabel select1Label;
    private JLabel select2Label;
    private JLabel selectDestLabel;
    private JTextField source1Field;
    private JTextField source2Field;
    private JTextField destField;
    private JCheckBox curTransCB;
    private boolean src1Ready = false;
    private boolean src2Ready = false;
    private boolean destReady = false;

    /**
     * Constructor.
     *
     * @param multiPane the enclosing MultiStepPane
     */
    public MergeStep1(MultiStepPane multiPane) {
        super(multiPane);

        initComponents();
    }

    /**
     * Constructor.
     *
     * @param multiPane the enclosing MultiStepPane
     * @param curTranscription a loaded transcription
     */
    public MergeStep1(MultiStepPane multiPane,
        TranscriptionImpl curTranscription) {
        super(multiPane);
        this.curTranscription = curTranscription;

        initComponents();
    }

    /**
     * Initializes ui components.
     */
    public void initComponents() {
        setLayout(new GridBagLayout());
        setBorder(new EmptyBorder(12, 12, 12, 12));
        browseSource1 = new JButton(ElanLocale.getString("Button.Browse"));
        browseSource2 = new JButton(ElanLocale.getString("Button.Browse"));
        browseDest = new JButton(ElanLocale.getString("Button.Browse"));
        source1Field = new JTextField();
        source2Field = new JTextField();
        destField = new JTextField();
        source1Field.setEditable(false);
        source1Field.setEnabled(false);
        source2Field.setEditable(false);
        source2Field.setEnabled(false);
        destField.setEditable(false);
        destField.setEnabled(false);
        select1Label = new JLabel(ElanLocale.getString(
                    "MergeTranscriptionDialog.Label.Source1"));
        select2Label = new JLabel(ElanLocale.getString(
                    "MergeTranscriptionDialog.Label.Source2"));
        selectDestLabel = new JLabel(ElanLocale.getString(
                    "MergeTranscriptionDialog.Label.Destination"));
        curTransCB = new JCheckBox("Use current transcription");

        Insets insets = new Insets(4, 6, 4, 6);
        GridBagConstraints gbc = new GridBagConstraints();

        if (curTranscription != null) {
            curTransCB.setSelected(true);
            source1Field.setText(curTranscription.getFullPath());
            browseSource1.setEnabled(false);
            src1Ready = true;

            gbc.gridx = 0;
            gbc.gridy = 0;

            //gbc.gridwidth = 2;
            gbc.anchor = GridBagConstraints.NORTHWEST;
            gbc.insets = insets;
            gbc.fill = GridBagConstraints.HORIZONTAL;
            gbc.weightx = 1.0;
            add(select1Label, gbc);

            gbc.gridy = 1;
            add(curTransCB, gbc);

            //gbc.gridwidth = 1;
            gbc.gridy = 2;
            gbc.anchor = GridBagConstraints.WEST;
            add(source1Field, gbc);

            gbc.gridx = 1;
            gbc.fill = GridBagConstraints.NONE;
            gbc.anchor = GridBagConstraints.EAST;
            gbc.weightx = 0;
            add(browseSource1, gbc);

            curTransCB.addItemListener(this);
        } else {
            gbc.gridx = 0;
            gbc.gridy = 0;

            //gbc.gridwidth = 2;
            gbc.anchor = GridBagConstraints.NORTHWEST;
            gbc.insets = insets;
            gbc.fill = GridBagConstraints.HORIZONTAL;
            gbc.weightx = 1.0;
            add(select1Label, gbc);

            gbc.gridy = 1;

            //gbc.gridwidth = 1;
            gbc.anchor = GridBagConstraints.WEST;
            add(source1Field, gbc);

            gbc.gridx = 1;
            gbc.fill = GridBagConstraints.NONE;
            gbc.anchor = GridBagConstraints.EAST;
            gbc.weightx = 0;
            add(browseSource1, gbc);
        }

        gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 3;
        gbc.anchor = GridBagConstraints.WEST;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.weightx = 1.0;
        gbc.insets = insets;
        add(select2Label, gbc);

        gbc.gridy = 4;
        add(source2Field, gbc);

        gbc.gridx = 1;
        gbc.fill = GridBagConstraints.NONE;
        gbc.anchor = GridBagConstraints.EAST;
        gbc.weightx = 0.0;
        add(browseSource2, gbc);

        gbc.gridx = 0;
        gbc.gridy = 5;
        gbc.anchor = GridBagConstraints.WEST;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.weightx = 1.0;
        add(selectDestLabel, gbc);

        gbc.gridy = 6;
        add(destField, gbc);

        gbc.gridx = 1;
        gbc.fill = GridBagConstraints.NONE;
        gbc.anchor = GridBagConstraints.EAST;
        gbc.weightx = 0.0;
        add(browseDest, gbc);

        browseSource1.addActionListener(this);
        browseSource2.addActionListener(this);
        browseDest.addActionListener(this);
    }

    /**
     * @see mpi.eudico.client.annotator.gui.multistep.Step#getStepTitle()
     */
    public String getStepTitle() {
        return ElanLocale.getString("MergeTranscriptionDialog.Title");
    }

    /**
     * @see mpi.eudico.client.annotator.gui.multistep.Step#enterStepForward()
     */
    public void enterStepForward() {
        // the next button is already disabled
    }

    /**
     * @see mpi.eudico.client.annotator.gui.multistep.Step#enterStepBackward()
     */
    public void enterStepBackward() {
        multiPane.setButtonEnabled(MultiStepPane.NEXT_BUTTON, true);
        multiPane.setButtonEnabled(MultiStepPane.CANCEL_BUTTON, true);
    }

    /**
     * Before we can leave this step we have to have two valid Transcription
     * objects or paths and the path to the destination file. Store all of
     * these in the properties map.
     *
     * @see mpi.eudico.client.annotator.gui.multistep.Step#leaveStepForward()
     */
    public boolean leaveStepForward() {
        //store
        if (curTransCB.isSelected()) {
            multiPane.putStepProperty("Source1", curTranscription);
        } else {
            multiPane.putStepProperty("Source1", source1Field.getText());
        }

        multiPane.putStepProperty("Source2", source2Field.getText());
        multiPane.putStepProperty("Destination", destField.getText());

        return true;
    }

    /**
     * Prompts the user to browse to a valid .eaf file.
     *
     * @return a String representation of a file
     */
    private String getOpenFileName() {
        String eafDir = (String) Preferences.get("LastUsedEAFDir", null);

        if (eafDir == null) {
            eafDir = System.getProperty("user.dir");
        }

        JFileChooser chooser = new JFileChooser();

        // the file chooser is not really part of the localisation
        chooser.setApproveButtonText("Select");
        chooser.setCurrentDirectory(new File(eafDir));
        chooser.setDialogTitle(ElanLocale.getString(
                "MergeTranscriptionDialog.SelectEAF"));

        File eafFile = null;
        FileFilter filter = ElanFileFilter.createFileFilter(ElanFileFilter.EAF_TYPE);
        chooser.setFileFilter(filter);

        if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
            File curDir = chooser.getCurrentDirectory();

            if (curDir != null) {
                Preferences.set("LastUsedEAFDir", curDir.getAbsolutePath(), null);
            }

            eafFile = chooser.getSelectedFile();

            if (eafFile != null) {
                String name = eafFile.getAbsolutePath();

                if (isExistingEAF(name)) {
                    return name;
                } else {
                    return null;
                }
            } else {
                return null;
            }
        } else {
            // dialog canceled
            return null;
        }
    }

    /**
     * Prompts the user to provide a filepath for a new .eaf file.
     *
     * @return a String representation of a file
     */
    private String getSaveFileName() {
        String eafDir = (String) Preferences.get("LastUsedEAFDir", null);

        if (eafDir == null) {
            eafDir = System.getProperty("user.dir");
        }

        JFileChooser chooser = new JFileChooser();

        // the file chooser is not really part of the localisation
        chooser.setApproveButtonText("Save");
        chooser.setCurrentDirectory(new File(eafDir));
        chooser.setDialogTitle(ElanLocale.getString(
                "MergeTranscriptionDialog.SelectEAF"));

        File eafFile = null;
        FileFilter filter = ElanFileFilter.createFileFilter(ElanFileFilter.EAF_TYPE);
        chooser.setFileFilter(filter);

        if (chooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
            File curDir = chooser.getCurrentDirectory();

            if (curDir != null) {
                Preferences.set("LastUsedEAFDir", curDir.getAbsolutePath(), null);
            }

            eafFile = chooser.getSelectedFile();

            if (eafFile != null) {
                String name = eafFile.getAbsolutePath();

                if (!validEAFName(name)) {
                    name += ("." + FileExtension.EAF_EXT[0]);
                }

                File f = new File(name);

                if (f.exists()) {
                    if (JOptionPane.showConfirmDialog(null,
                                (name + "\n" +
                                ElanLocale.getString(
                                    "MergeTranscriptionDialog.Warning.DestinationExists")),
                                ElanLocale.getString("Message.Warning"),
                                JOptionPane.YES_NO_OPTION) == JOptionPane.NO_OPTION) {
                        return null;
                    }

                    return name;
                }

                return name;
            } else {
                return null;
            }
        } else {
            // dialog canceled
            return null;
        }
    }

    /**
     * Checks if a filename points to an exisitng .eaf file.
     *
     * @param fileName a String representation of a file
     *
     * @return true if the file exists and is an .eaf, false otherwise
     */
    private boolean isExistingEAF(String fileName) {
        if (fileName == null) {
            return false;
        }

        File f = new File(fileName);

        if (!f.exists()) {
            return false;
        }

        return validEAFName(fileName);
    }

    /**
     * Checks the extension of the filename.
     *
     * @param name the filename
     *
     * @return true if it ends with .eaf (case insensitive)
     */
    private boolean validEAFName(String name) {
        if (name == null) {
            return false;
        }

        String lowerPathName = name.toLowerCase();

        String[] exts = FileExtension.EAF_EXT;
        boolean validExt = false;

        for (int i = 0; i < exts.length; i++) {
            if (lowerPathName.endsWith("." + exts[i])) {
                validExt = true;

                break;
            }
        }

        return validExt;
    }

    /**
     * If there are valid sources and a valid destination the next button can
     * be enabled, after storing the file paths to the properties map.
     */
    private void checkCondition() {
        if (src1Ready && src2Ready && destReady) {
            if (source1Field.getText().equals(source2Field.getText())) {
                JOptionPane.showMessageDialog(this,
                    ElanLocale.getString(
                        "MergeTranscriptionDialog.Warning.SameSources"),
                    ElanLocale.getString("Message.Warning"),
                    JOptionPane.WARNING_MESSAGE);
                multiPane.setButtonEnabled(MultiStepPane.NEXT_BUTTON, false);

                return;
            }

            if (source1Field.getText().equals(destField.getText()) ||
                    source2Field.getText().equals(destField.getText())) {
                JOptionPane.showMessageDialog(this,
                    ElanLocale.getString(
                        "MergeTranscriptionDialog.Warning.DestinationIsSource"),
                    ElanLocale.getString("Message.Warning"),
                    JOptionPane.WARNING_MESSAGE);
                multiPane.setButtonEnabled(MultiStepPane.NEXT_BUTTON, false);

                return;
            }

            multiPane.setButtonEnabled(MultiStepPane.NEXT_BUTTON, true);
        } else {
            multiPane.setButtonEnabled(MultiStepPane.NEXT_BUTTON, false);
        }
    }

    /**
     * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
     */
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == browseSource1) {
            String name = getOpenFileName();

            if (name != null) {
                source1Field.setText(name);
                src1Ready = true;
            } else {
                if (isExistingEAF(source1Field.getText())) {
                    src1Ready = true;
                } else {
                    src1Ready = false;
                }
            }
        } else if (e.getSource() == browseSource2) {
            String name = getOpenFileName();

            if (name != null) {
                source2Field.setText(name);
                src2Ready = true;
            } else {
                if (isExistingEAF(source2Field.getText())) {
                    src2Ready = true;
                } else {
                    src2Ready = false;
                }
            }
        } else {
            String name = getSaveFileName();

            if (name != null) {
                destField.setText(name);
                destReady = true;
            } else {
                if ((destField.getText() != null) &&
                        (destField.getText().length() > 4)) {
                    destReady = true;
                } else {
                    destReady = false;
                }
            }
        }

        checkCondition();
    }

    /**
     * @see java.awt.event.ItemListener#itemStateChanged(java.awt.event.ItemEvent)
     */
    public void itemStateChanged(ItemEvent e) {
        // only one possible source
        if (e.getStateChange() == ItemEvent.SELECTED) {
            browseSource1.setEnabled(false);
            source1Field.setText(curTranscription.getFullPath());
            src1Ready = true;
        } else {
            browseSource1.setEnabled(true);
            source1Field.setText("");
            src1Ready = false;
        }

        checkCondition();
    }
}
