/*
 * File:     AbstractConstraintPanel.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
 */

/* 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.search.content.query.viewer;

import mpi.search.SearchLocale;

import mpi.search.content.model.CorpusType;

import mpi.search.content.query.model.Constraint;

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;

import java.util.HashMap;

import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;


/**
 * The ConstraintPanel is the GUI for editing one single Constraint ConstraintPanels are
 * meant to be included in the SearchConfigPanel
 *
 * @author Alexander Klassmann
 * @version July 2004
 */
abstract public class AbstractConstraintPanel extends JPanel
    implements ItemListener {
    protected static int tierComboBoxWidth = 0;

    //Components
    protected PatternPanel patternPanel;
    protected RelationPanel relationPanel;
    protected JComponent titleComponent;
    final protected CardLayout framedPanelLayout = new CardLayout();
    final protected JPanel framedPanel = new JPanel(framedPanelLayout);

    /** Holds value of property DOCUMENT ME! */
    final protected JPanel optionPanel = new JPanel(new BorderLayout());

    /** Holds value of property DOCUMENT ME! */
    protected JComboBox tierComboBox;

    /** Holds value of property DOCUMENT ME! */
    final protected JCheckBox regExCheckBox = new JCheckBox(SearchLocale.getString(
                "Search.Constraint.RegularExpression"), false);

    /** Holds value of property DOCUMENT ME! */
    final protected JCheckBox caseCheckBox = new JCheckBox(SearchLocale.getString(
                "Search.Constraint.CaseSensitive"), false);

    /** Holds value of property DOCUMENT ME! */
    final private Border grayBorder = new CompoundBorder(new EmptyBorder(3, 3,
                3, 3), new LineBorder(Color.gray));

    /** Holds value of property DOCUMENT ME! */
    protected AttributeConstraintPanel attributePanel;

    /** Holds value of property DOCUMENT ME! */
    final protected CorpusType type;

    /** Holds value of property DOCUMENT ME! */
    final protected QueryPanel queryPanel;

    //Constants

    /** Holds value of property DOCUMENT ME! */
    final protected int constraintNr;
    final protected Font font;

    /**
     * Creates a new AbstractConstraintPanel object.
     *
     * @param parentPanel DOCUMENT ME!
     * @param font DOCUMENT ME!
     * @param constraintNr DOCUMENT ME!
     * @param type DOCUMENT ME!
     */
    public AbstractConstraintPanel(QueryPanel parentPanel, Font font,
        int constraintNr, CorpusType type) {
        this.queryPanel = parentPanel;
        this.type = type;
        this.constraintNr = constraintNr;
        this.font = font;

        regExCheckBox.setFont(regExCheckBox.getFont().deriveFont(8f));
        caseCheckBox.setFont(caseCheckBox.getFont().deriveFont(8f));
    }

    /**
     * DOCUMENT ME!
     */
    protected void makeLayout() {
        //RegExPanel
        patternPanel = new PatternPanel(type, tierComboBox, constraintNr, font);

        //RelationPanel
        relationPanel = new RelationPanel(queryPanel, type, constraintNr);

        //OptionPanel
        JPanel checkBoxPanel = new JPanel(new GridLayout(2, 1));
        checkBoxPanel.add(regExCheckBox);
        checkBoxPanel.add(caseCheckBox);
        optionPanel.add(checkBoxPanel, BorderLayout.WEST);

        //InputPanel
        JPanel inputPanel = new JPanel(new GridLayout(2, 1));
        inputPanel.add(patternPanel);
        inputPanel.add(relationPanel);

        //AttributePanel
        if (type.hasAttributes()) {
            attributePanel = new AttributeConstraintPanel(type);
            optionPanel.add(attributePanel, BorderLayout.CENTER);
            attributePanel.setTier(getTierName());
        }

        //FramedPanel
        JPanel specificationPanel = new JPanel();
        specificationPanel.add(inputPanel, BorderLayout.CENTER);
        specificationPanel.add(optionPanel, BorderLayout.EAST);
        framedPanel.add(specificationPanel, "");
        framedPanel.setBorder(grayBorder);
        framedPanelLayout.show(framedPanel, "");

        //this
        setLayout(new BorderLayout());
        add(new JLabel(" " + constraintNr + " "), BorderLayout.WEST);
        add(titleComponent, BorderLayout.NORTH);
        add(framedPanel, BorderLayout.CENTER);

        tierComboBox.addItemListener(this);

        try {
            Class popupMenu = type.getInputMethodClass();
            popupMenu.getConstructor(new Class[] {
                    Component.class, AbstractConstraintPanel.class
                }).newInstance(new Object[] {
                    patternPanel.getDefaultInputComponent(),
                    AbstractConstraintPanel.this
                });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //implementation of ItemListener
    public void itemStateChanged(ItemEvent e) {
        if (e.getStateChange() == ItemEvent.SELECTED) {
            if (e.getSource() == tierComboBox) {
                if (type.isClosedVoc((String) e.getItem())) {
                    regExCheckBox.setEnabled(false);
                    setRegEx(false);
                    setCaseSensitive(false);
                } else {
                    regExCheckBox.setEnabled(true);
                }

                if (type.strictCaseSensitive((String) e.getItem())) {
                    setCaseSensitive(true);
                }

                boolean caseSensitiveFixed = type.isClosedVoc((String) e.getItem()) ||
                    type.strictCaseSensitive((String) e.getItem());

                if (!caseSensitiveFixed) {
                    if (!caseCheckBox.isEnabled()) {
                        setCaseSensitive(false);
                    }

                    // change from fixed to variable -> set default
                }

                caseCheckBox.setEnabled(!caseSensitiveFixed);

                if (attributePanel != null) {
                    attributePanel.setTier((String) e.getItem());
                }

                queryPanel.notifyOtherConstraints(constraintNr);
            }
        }
    }

    //methods for getting the specification of the constraint
    public String getTierName() {
        return (String) tierComboBox.getSelectedItem();
    }

    /**
     * DOCUMENT ME!
     *
     * @param tierName DOCUMENT ME!
     */
    protected void setTierName(String tierName) {
        tierComboBox.setSelectedItem(tierName);
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public boolean isRegEx() {
        return regExCheckBox.isSelected();
    }

    /**
     * DOCUMENT ME!
     *
     * @param regEx DOCUMENT ME!
     */
    protected void setRegEx(boolean regEx) {
        regExCheckBox.setSelected(regEx);
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    protected boolean isCaseSensitive() {
        return caseCheckBox.isSelected();
    }

    /**
     * DOCUMENT ME!
     *
     * @param sensitiv DOCUMENT ME!
     */
    protected void setCaseSensitive(boolean sensitiv) {
        caseCheckBox.setSelected(sensitiv);
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    protected String getPattern() {
        return patternPanel.getPattern();
    }

    /**
     * DOCUMENT ME!
     *
     * @param pattern DOCUMENT ME!
     */
    protected void setPattern(String pattern) {
        patternPanel.setPattern(pattern);
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    protected HashMap getAttributes() {
        HashMap attributes = new HashMap();

        if (attributePanel != null) {
            String[] attributeNames = type.getAttributeNames(getTierName());

            for (int i = 0; i < attributeNames.length; i++) {
                attributes.put(attributeNames[i],
                    attributePanel.getAttributeValue(attributeNames[i]));
            }
        }

        return attributes;
    }

    /**
     * DOCUMENT ME!
     *
     * @param c DOCUMENT ME!
     */
    public void setConstraint(Constraint c) {
        setRegEx(c.isRegEx());
        setCaseSensitive(c.isCaseSensitive());
        setPattern(c.getPattern());
        relationPanel.setLowerBoundary(c.getLowerBoundary());
        relationPanel.setUpperBoundary(c.getUpperBoundary());
        relationPanel.setUnit(c.getUnit());
    }

    /**
     * DOCUMENT ME!
     *
     * @param comboBox DOCUMENT ME!
     * @param units DOCUMENT ME!
     */
    protected static void updateComboBox(JComboBox comboBox, String[] units) {
        //don't refill if equal strings
        if (units.length == comboBox.getItemCount()) {
            boolean equal = true;

            for (int i = 0; i < units.length; i++) {
                if (!units[i].equals(comboBox.getItemAt(i))) {
                    equal = false;
                }
            }

            if (equal) {
                return;
            }
        }

        Object oldItem = comboBox.getSelectedItem();

        comboBox.removeAllItems();

        for (int i = 0; i < units.length; i++) {
            comboBox.addItem(units[i]);
        }

        //select old item
        comboBox.setSelectedItem(oldItem);

        //if oldItem not in Box, select smallest possible linguistic unit
        if (comboBox.getSelectedItem() == null) {
            comboBox.setSelectedIndex(0);
        }
    }
}
