package org.greenstone.gatherer.cdm;

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import org.greenstone.gatherer.Configuration;
import org.greenstone.gatherer.DebugStream;
import org.greenstone.gatherer.Dictionary;
import org.greenstone.gatherer.Gatherer;
import org.greenstone.gatherer.gui.TestingPreparation;
import org.greenstone.gatherer.util.JarTools;
import org.greenstone.gatherer.util.StaticStrings;
import org.w3c.dom.*;

import java.lang.reflect.*;

public class IndexOptionManager 
    implements BuildTypeManager.BuildTypeListener {

    // we have an IndexOptionList (DOMProxyListModel) for each option type
    private IndexOptionList level_model = null; 
    private IndexOptionList options_model = null; 
    /** the default level option  - for mgpp and lucene */
    private IndexOption default_level = null;
    
    private String build_type = null;
    private Control controls = null;
    
    public IndexOptionManager(String current_build_type) {
	level_model = new IndexOptionList(CollectionDesignManager.collect_config.getLevels());
	options_model = new IndexOptionList(CollectionDesignManager.collect_config.getIndexOptions());
	
	DebugStream.println("IndexOptionManager: " + level_model.getSize() + " levels parsed.");
	DebugStream.println("IndexOptionManager: " + options_model.getSize() + " index options parsed.");
	
	build_type = current_build_type;
	if (build_type.equals(BuildTypeManager.BUILD_TYPE_MG)) {
	    level_model.setAssigned(false);
	}
	//	else if (build_type.equals(BuildTypeManager.BUILD_TYPE_LUCENE)) {
	//   options_model.setAssigned(false);
	//}
	// Parse and retrieve the default level 
	Element default_level_element = CollectionDesignManager.collect_config.getLevelDefault();
	default_level = new IndexOption(default_level_element);
	if (build_type.equals(BuildTypeManager.BUILD_TYPE_MG)) {
	    default_level.setAssigned(false);
	}
	
    }
	
    
    public void buildTypeChanged(String new_build_type) {
	boolean levels_enabled = true;
	//boolean stem_enabled = true;
	if (new_build_type.equals(BuildTypeManager.BUILD_TYPE_MG)) {
	    levels_enabled = false;
	}// else if (new_build_type.equals(BuildTypeManager.BUILD_TYPE_LUCENE)) {
	 //   stem_enabled = false;
	//}
	level_model.setAssigned(levels_enabled);
	default_level.setAssigned(levels_enabled);
	//options_model.setAssigned(stem_enabled);
	((IndexOptionControl)controls).buildTypeChanged(new_build_type);
	build_type = new_build_type;
    }

    /** Method to acquire the controls for editing the indexes.
     * @return the Control
     */
    public Control getControls() {
	if(controls == null) {
	    // Build controls
	    controls = new IndexOptionControl();
	}
	return controls;
    }
    
    public int getNumLevels() {
	return level_model.getSize();
    }
    public ArrayList getLevels() {
	return level_model.children();
    }
    
    private void addLevel(String level) {
	if (level_model.getOption(level) == null) {
	    int position = 0;
	    
	    if (level.equals(StaticStrings.SECTION_STR) && level_model.getSize()==1) {
		position = 1;
	    }
	    level_model.add(position, new IndexOption(level));
	    // add in a default collection meta
	    CollectionMeta meta = new CollectionMeta(StaticStrings.STOP_CHARACTER + level);
	    meta.setAssigned(true);
	    if (level.equals("document") || level.equals("section")) {
		meta.setValue("_text" + level + "_");
	    } else {	    
		meta.setValue(level);
	    }
	    CollectionDesignManager.collectionmeta_manager.addMetadatum(meta);
	}
    }

    private IndexOption getLevel(String level) {
	return level_model.getOption(level);
    }

    private void removeLevel(String level_name) {
	// Remove any current metadata from this level
	CollectionDesignManager.collectionmeta_manager.removeMetadata(StaticStrings.STOP_CHARACTER + level_name);
	// Remove the level
	level_model.removeOption(level_name);
    }

   /** Method to set the default level
     * @param level the new default level
     */
    private void setDefaultLevel(String level) {
 	if(level != null) {
	    default_level.setValue(level);
	    if (!build_type.equals(BuildTypeManager.BUILD_TYPE_MG)) {
		default_level.setAssigned(true);
	    } 
	} else {
	    default_level.setAssigned(false);
	}
    }

    private class IndexOptionControl
	extends JPanel
	implements Control {

	public StemmingControl stem_control = null;
	public LevelControl level_control = null;
	
	public IndexOptionControl() {
            
            this.setComponentOrientation(Dictionary.getOrientation());
	    stem_control = new StemmingControl();
	    level_control = new LevelControl();
            
	    setLayout(new BorderLayout());
	    //if (!build_type.equals(BuildTypeManager.BUILD_TYPE_LUCENE)) {
		add(stem_control, BorderLayout.EAST);
		//}
	    if (!build_type.equals(BuildTypeManager.BUILD_TYPE_MG)) {
		add(level_control, BorderLayout.WEST);
	    }
	    TestingPreparation.setNamesRecursivelyForControl(this);
	    //TestingPreparation.setNamesRecursively(this);
	}
	

	public void destroy() {}
	public void gainFocus() {}
	public void loseFocus() {}

	public void buildTypeChanged(String new_build_type)
	{
	    if (build_type.equals(new_build_type)) {
		// shouldn't happen
		return;
	    }
	    // tell our sub parts about the change in build type
	    stem_control.buildTypeChanged(new_build_type);
	    level_control.buildTypeChanged(new_build_type);
	    
	    // then display/hide as appropriate
	    //if (build_type.equals(BuildTypeManager.BUILD_TYPE_LUCENE)) {
		// Changing to MG/MGPP
	    //	add(stem_control, BorderLayout.NORTH);
	    //}
	    //else if (new_build_type.equals(BuildTypeManager.BUILD_TYPE_LUCENE)) {
		// Changing to Lucene
		//remove(stem_control);
	    //}
	    if (build_type.equals(BuildTypeManager.BUILD_TYPE_MG)) {
		// changing from MG
		add(level_control, BorderLayout.WEST);
	    }
	    else if (new_build_type.equals(BuildTypeManager.BUILD_TYPE_MG)) {
		// changing to MG
		remove(level_control);
	    }
	    
	}
	    
    }
    
    private class StemmingControl
	extends JPanel
	implements BuildTypeManager.BuildTypeListener
    {
	private JCheckBox stem_checkbox = new JCheckBox();
	private JCheckBox casefold_checkbox = new JCheckBox();
	private JCheckBox accentfold_checkbox = new JCheckBox();
	private JCheckBox separate_cjk_checkbox =new JCheckBox();
	
	public StemmingControl()
	{
            this.setComponentOrientation(Dictionary.getOrientation());
	    setLayout(new BorderLayout(10,10));
	    setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
	    
	    stem_checkbox.setText(Dictionary.get("CDM.IndexingManager.Stem"));
	    stem_checkbox.setToolTipText(Dictionary.get("CDM.IndexingManager.Stem_Tooltip"));
	    stem_checkbox.setActionCommand(StaticStrings.STEM_OPTION_STR);
	    stem_checkbox.setComponentOrientation(Dictionary.getOrientation());
            
	    casefold_checkbox.setText(Dictionary.get("CDM.IndexingManager.Casefold"));
	    casefold_checkbox.setToolTipText(Dictionary.get("CDM.IndexingManager.Casefold_Tooltip"));
	    casefold_checkbox.setActionCommand(StaticStrings.CASEFOLD_OPTION_STR);
	    casefold_checkbox.setComponentOrientation(Dictionary.getOrientation());
            
	    accentfold_checkbox.setText(Dictionary.get("CDM.IndexingManager.Accent_fold"));
	    accentfold_checkbox.setToolTipText(Dictionary.get("CDM.IndexingManager.Accent_fold_Tooltip"));
	    accentfold_checkbox.setActionCommand(StaticStrings.ACCENTFOLD_OPTION_STR);
	    // Accent-folding is currently not available for MG
	    // accentfold_checkbox.setEnabled(!build_type.equals(BuildTypeManager.BUILD_TYPE_MG));
            accentfold_checkbox.setComponentOrientation(Dictionary.getOrientation());
            
	    separate_cjk_checkbox.setText(Dictionary.get("CDM.IndexingManager.Separate_cjk"));
	    separate_cjk_checkbox.setToolTipText(Dictionary.get("CDM.IndexingManager.Separate_cjk_Tooltip"));
	    separate_cjk_checkbox.setActionCommand(StaticStrings.SEPARATE_CJK_OPTION_STR);
            separate_cjk_checkbox.setComponentOrientation(Dictionary.getOrientation());
            
	    JPanel checkbox_panel = new JPanel();
	    checkbox_panel.setLayout(new GridLayout(1, 1));
	    checkbox_panel.setComponentOrientation(Dictionary.getOrientation());
            // todo, remove one of these panels
	    JPanel stem_panel = new JPanel();
	    stem_panel.setLayout(new GridLayout(2,2));
	    stem_panel.add(stem_checkbox);
	    stem_panel.add(casefold_checkbox);
	    stem_panel.add(accentfold_checkbox);
	    stem_panel.add(separate_cjk_checkbox);
	    stem_panel.setComponentOrientation(Dictionary.getOrientation());
            
	    // JPanel other_panel = new JPanel();
	    // other_panel.setLayout(new GridLayout(1,1));
	    // other_panel.add(separate_cjk_checkbox);
            // other_panel.setComponentOrientation(Dictionary.getOrientation());   
	    
            
	    checkbox_panel.add(stem_panel);
	    //checkbox_panel.add(other_panel);
            
            JLabel tmp = new JLabel(Dictionary.get("CDM.IndexingManager.Options"));
            tmp.setComponentOrientation(Dictionary.getOrientation());
	    add(tmp, BorderLayout.NORTH);
	    add(checkbox_panel, BorderLayout.CENTER);

	    // set the defaults
	    if (build_type.equals(BuildTypeManager.BUILD_TYPE_LUCENE)|| build_type.equals(BuildTypeManager.BUILD_TYPE_SOLR)) {
		stem_checkbox.setSelected(false);
		stem_checkbox.setEnabled(false);
		casefold_checkbox.setSelected(true);
		casefold_checkbox.setEnabled(false);
		accentfold_checkbox.setSelected(true);
		accentfold_checkbox.setEnabled(false);
		if (options_model.getOption(StaticStrings.SEPARATE_CJK_OPTION_STR) != null) {
		    separate_cjk_checkbox.setSelected(true);
		}
	    } else {
		if (build_type.equals(BuildTypeManager.BUILD_TYPE_MG)) {
		    accentfold_checkbox.setEnabled(false);
		}
		
		// set up the checked/unchecked boxes
		    // we'll assume that the config file has got it correct
		// no more setting all to on if nothing in config file
		if (options_model.getSize()!=0) {
		    if (options_model.getOption(StaticStrings.STEM_OPTION_STR)!=null) {
			stem_checkbox.setSelected(true);
		    }
		    if (options_model.getOption(StaticStrings.CASEFOLD_OPTION_STR)!=null) {
			casefold_checkbox.setSelected(true);
		    }
		    if (options_model.getOption(StaticStrings.ACCENTFOLD_OPTION_STR)!=null) {
			accentfold_checkbox.setSelected(true);
		    }
		    if (options_model.getOption(StaticStrings.SEPARATE_CJK_OPTION_STR) != null) {
			separate_cjk_checkbox.setSelected(true);
		    }
		    
		}
	    }
	
	    CheckBoxListener cbl = new CheckBoxListener();
	    stem_checkbox.addActionListener(cbl);
	    casefold_checkbox.addActionListener(cbl);
 	    accentfold_checkbox.addActionListener(cbl);
	    separate_cjk_checkbox.addActionListener(cbl);
	    
	    // changing stem indexes changes build settings
	    stem_checkbox.addActionListener(CollectionDesignManager.buildcol_change_listener);
	    casefold_checkbox.addActionListener(CollectionDesignManager.buildcol_change_listener);
 	    accentfold_checkbox.addActionListener(CollectionDesignManager.buildcol_change_listener);
	    separate_cjk_checkbox.addActionListener(CollectionDesignManager.buildcol_change_listener);
	    
	}
	
	public void buildTypeChanged(String new_build_type) {
	    // accentfold only enabled for mgpp
	    if (new_build_type.equals(BuildTypeManager.BUILD_TYPE_MGPP)) {
		accentfold_checkbox.setEnabled(true);
		accentfold_checkbox.setSelected(true);
		options_model.addOption(StaticStrings.ACCENTFOLD_OPTION_STR);
		if (build_type.equals(BuildTypeManager.BUILD_TYPE_LUCENE) || build_type.equals(BuildTypeManager.BUILD_TYPE_SOLR)) {
		    // was lucene/solr
		    stem_checkbox.setEnabled(true);
		    stem_checkbox.setSelected(true);
		    options_model.addOption(StaticStrings.STEM_OPTION_STR);
		    casefold_checkbox.setEnabled(true);
		    casefold_checkbox.setSelected(true);
		    options_model.addOption(StaticStrings.CASEFOLD_OPTION_STR);
		} // else, was mg, stem and case remain the same
		    
	    }
	    if (new_build_type.equals(BuildTypeManager.BUILD_TYPE_MG)) {
		accentfold_checkbox.setSelected(false);
		accentfold_checkbox.setEnabled(false);
		options_model.removeOption(StaticStrings.ACCENTFOLD_OPTION_STR);
	
		if (build_type.equals(BuildTypeManager.BUILD_TYPE_LUCENE) || build_type.equals(BuildTypeManager.BUILD_TYPE_SOLR)) {
		    // was lucene
		    stem_checkbox.setEnabled(true);
		    stem_checkbox.setSelected(true);
		    options_model.addOption(StaticStrings.STEM_OPTION_STR);
		    casefold_checkbox.setEnabled(true);
		    casefold_checkbox.setSelected(true);
		    options_model.addOption(StaticStrings.CASEFOLD_OPTION_STR);
		} // else, was mgpp, stem and case remain the same
	   
	    }
	    if (new_build_type.equals(BuildTypeManager.BUILD_TYPE_LUCENE) || new_build_type.equals(BuildTypeManager.BUILD_TYPE_SOLR)) {
		accentfold_checkbox.setSelected(true);
		accentfold_checkbox.setEnabled(false);
		options_model.removeOption(StaticStrings.ACCENTFOLD_OPTION_STR);
		stem_checkbox.setSelected(false);
		stem_checkbox.setEnabled(false);
		options_model.removeOption(StaticStrings.STEM_OPTION_STR);
		casefold_checkbox.setSelected(true);
		casefold_checkbox.setEnabled(false);
		options_model.removeOption(StaticStrings.CASEFOLD_OPTION_STR);
	
	    }
	}

	private class CheckBoxListener
	    implements ActionListener {
	    public void actionPerformed(ActionEvent event) {
		if (!((JCheckBox)event.getSource()).isSelected()) {
		    // deselecting
		    options_model.removeOption(event.getActionCommand());
		}
		else {
		    // selecting a new one
		    options_model.addOption(event.getActionCommand());
		}
	    }
	}
    }



    /** This class creates a set of controls for editing the levels. */
    private class LevelControl
	extends JPanel 
	implements BuildTypeManager.BuildTypeListener
    {
	
	JCheckBox document_checkbox = null;
	JCheckBox section_checkbox = null;
	JRadioButton document_default_radio = null;
	JRadioButton section_default_radio = null;
	
	public LevelControl() {
	    this.setComponentOrientation(Dictionary.getOrientation());
	    JPanel checkbox_panel = new JPanel();
            checkbox_panel.setComponentOrientation(Dictionary.getOrientation());
	    JPanel default_panel = new JPanel();
            default_panel.setComponentOrientation(Dictionary.getOrientation());
	    document_checkbox = new JCheckBox();
            document_checkbox.setComponentOrientation(Dictionary.getOrientation());
	    document_checkbox.setText(Dictionary.get("CDM.LevelManager.Document"));
	    document_checkbox.setActionCommand(StaticStrings.DOCUMENT_STR);
	    document_default_radio = new JRadioButton();
	    document_default_radio.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
	    document_default_radio.setOpaque(false);
	    document_default_radio.setActionCommand(StaticStrings.DOCUMENT_STR);
	    document_default_radio.setIcon(JarTools.getImage("radio_unselected.gif"));
	    document_default_radio.setSelectedIcon(JarTools.getImage("radio_selected.gif"));
            document_default_radio.setComponentOrientation(Dictionary.getOrientation());
            
	    section_checkbox = new JCheckBox();
	    section_checkbox.setText(Dictionary.get("CDM.LevelManager.Section"));
	    section_checkbox.setActionCommand(StaticStrings.SECTION_STR);
            section_checkbox.setComponentOrientation(Dictionary.getOrientation());
            
	    section_default_radio = new JRadioButton();
	    section_default_radio.setOpaque(true);
	    section_default_radio.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
	    section_default_radio.setOpaque(false);
	    section_default_radio.setIcon(JarTools.getImage("radio_unselected.gif"));
	    section_default_radio.setSelectedIcon(JarTools.getImage("radio_selected.gif"));
            section_default_radio.setComponentOrientation(Dictionary.getOrientation());
            
	    section_default_radio.setActionCommand(StaticStrings.SECTION_STR);
	    ButtonGroup default_group = new ButtonGroup();
	    default_group.add(document_default_radio);
	    default_group.add(section_default_radio);

	 

	    if (level_model.getSize()==0) {
		// no levels yet, set document
		document_checkbox.setSelected(true);
		addLevel(StaticStrings.DOCUMENT_STR);
	    } else {
		if (getLevel(StaticStrings.DOCUMENT_STR)!= null) {
		    document_checkbox.setSelected(true);
		}
		if (getLevel(StaticStrings.SECTION_STR) != null) {
		    section_checkbox.setSelected(true);
		}
	    }

	    if (default_level.isAssigned()) {
		// set the default based on specified default
		if (default_level.getValue().equals(StaticStrings.DOCUMENT_STR) && document_checkbox.isSelected()) {
		    document_default_radio.setSelected(true);
		}
		else if (default_level.getValue().equals(StaticStrings.SECTION_STR) && section_checkbox.isSelected()) {
		    section_default_radio.setSelected(true);
		} else {
    		    default_level.setAssigned(false);
		}
	    }
	    // if have no valid specified default
	    if (!default_level.isAssigned()) {
		String default_l = StaticStrings.DOCUMENT_STR;
		if (document_checkbox.isSelected()) {
		    document_default_radio.setSelected(true);
		    default_l = StaticStrings.DOCUMENT_STR;
		} else if (section_checkbox.isSelected()) {
		    section_default_radio.setSelected(true);
		    default_l = StaticStrings.SECTION_STR;
		}
		setDefaultLevel(default_l);
	    }
	    
	    validateControls();
	    JLabel checkbox_label = new JLabel(Dictionary.get("CDM.LevelManager.Level_Title"));
	    checkbox_panel.setLayout(new GridLayout(3,1));
	    checkbox_panel.setToolTipText(Dictionary.get("CDM.IndexManager.Level_Tooltip"));
	    checkbox_panel.add(checkbox_label);
	    checkbox_panel.add(document_checkbox);
	    checkbox_panel.add(section_checkbox);
            checkbox_label.setComponentOrientation(Dictionary.getOrientation());
            
	    JLabel default_label = new JLabel(Dictionary.get("CDM.LevelManager.Default"));
	    default_panel.setLayout(new GridLayout(3,1));
	    default_panel.setToolTipText(Dictionary.get("CDM.LevelManager.Default_Tooltip"));
	    default_panel.add(default_label);
	    default_panel.add(document_default_radio);
	    default_panel.add(section_default_radio);
            default_label.setComponentOrientation(Dictionary.getOrientation());
        
	    CheckBoxListener cbl = new CheckBoxListener();
	    document_checkbox.addActionListener(cbl);
	    section_checkbox.addActionListener(cbl);

	    // changing selected levels changes build settings
	    document_checkbox.addActionListener(CollectionDesignManager.buildcol_change_listener);
	    section_checkbox.addActionListener(CollectionDesignManager.buildcol_change_listener);
	    
	    RadioListener rl = new RadioListener();
	    document_default_radio.addActionListener(rl);
	    section_default_radio.addActionListener(rl);
	    // changing the default doesn't need a rebuild

	    setLayout(new BorderLayout(10,10));
	    setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
	    add(checkbox_panel, BorderLayout.LINE_START);
	    add(default_panel, BorderLayout.CENTER);
	} // LevelControl
	
	public void buildTypeChanged(String new_build_type) {};
	public void gainFocus() {

	}

	public void loseFocus() {

	}

	public void destroy() {
	}

	private class RadioListener
	    implements ActionListener {
	    public void actionPerformed(ActionEvent event) {
		String new_level = event.getActionCommand();
		setDefaultLevel(new_level);
	    }
	}
	private class CheckBoxListener
	    implements ActionListener {
	    
	    public void actionPerformed(ActionEvent event) {
		if (!((JCheckBox)event.getSource()).isSelected()) {
		    // deselecting
		    if (noLevelsSelected()) {
			// can't do this
			((JCheckBox)event.getSource()).setSelected(true);
		    } else {
			// remove the level
			removeLevel(event.getActionCommand());
		    }
		} else {
		    // selecting a new one
		    addLevel(event.getActionCommand());
		}
		validateControls();
	    }
	}
	    
	private boolean noLevelsSelected() {
	    if (!document_checkbox.isSelected() && !section_checkbox.isSelected()) {
		return true;

	    }
	    return false;
	}

	private void validateControls() {
            
	    boolean document_enabled = document_checkbox.isSelected();
	    document_default_radio.setEnabled(document_enabled);
	    
	    boolean section_enabled = section_checkbox.isSelected();
	    section_default_radio.setEnabled(section_enabled);

	    // have we disabled our default??
	    if (!document_enabled && document_default_radio.isSelected()) {
		section_default_radio.setSelected(true);
		setDefaultLevel(StaticStrings.SECTION_STR);
               
	    } else if (!section_enabled && section_default_radio.isSelected()) {
		document_default_radio.setSelected(true);
		setDefaultLevel(StaticStrings.DOCUMENT_STR);
	    }

           
	}

    }

}
