/*
 * Created on 02.04.2005
 */
package net.sourceforge.ganttproject.gui.options;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.ComponentOrientation;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.ComboBoxModel;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JColorChooser;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SpringLayout;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

import org.jdesktop.swing.JXDatePicker;

import net.sourceforge.ganttproject.gui.options.model.BooleanOption;
import net.sourceforge.ganttproject.gui.options.model.ChangeValueDispatcher;
import net.sourceforge.ganttproject.gui.options.model.ChangeValueEvent;
import net.sourceforge.ganttproject.gui.options.model.ChangeValueListener;
import net.sourceforge.ganttproject.gui.options.model.ColorOption;
import net.sourceforge.ganttproject.gui.options.model.DateOption;
import net.sourceforge.ganttproject.gui.options.model.EnumerationOption;
import net.sourceforge.ganttproject.gui.options.model.GPOption;
import net.sourceforge.ganttproject.gui.options.model.GPOptionGroup;
import net.sourceforge.ganttproject.gui.options.model.StringOption;
import net.sourceforge.ganttproject.language.GanttLanguage;

/**
 * @author bard
 */
public class OptionsPageBuilder {
    I18N myi18n = new I18N();
    private Component myParentComponent;
    
    public OptionsPageBuilder() {
        this(null);
    }
    
    public OptionsPageBuilder(Component parentComponent) {
        myParentComponent = parentComponent;
    }
    
    public void setI18N(I18N i18n) {
    	myi18n = i18n;
    }
    
    public void setOptionKeyPrefix(String optionKeyPrefix) {
        myi18n.myOptionKeyPrefix = optionKeyPrefix;
    }
    public JComponent buildPage(GPOptionGroup[] optionGroups, String pageID) {
        JPanel result = new JPanel(new BorderLayout());
        result.setBorder(new EmptyBorder(0, 5, 0, 5));
        TopPanel topPanel = new TopPanel(myi18n.getPageTitle(pageID), myi18n
                .getPageDescription(pageID));
        topPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        result.add(topPanel, BorderLayout.NORTH);
        JComponent planePage = buildPlanePage(optionGroups);
        result.add(planePage, BorderLayout.CENTER);
        return result;
    }

    public JComponent buildPlanePage(GPOptionGroup[] optionGroups) {
        JPanel resultPanel = new JPanel(new BorderLayout());
        JComponent optionsPanel = new JPanel(new SpringLayout());
        for (int i = 0; i < optionGroups.length; i++) {
            optionsPanel.add(createGroupComponent(optionGroups[i]));
        }
        SpringUtilities.makeCompactGrid(optionsPanel, optionGroups.length, 1,
                0, 0, 5, 5);
        resultPanel.add(optionsPanel, BorderLayout.NORTH);
        return resultPanel;
    }

    private Component createGroupComponent(GPOptionGroup group) {
        JPanel optionsPanel = new JPanel(new SpringLayout());
        if (group.isTitled()) {
            Border lineBorder = BorderFactory.createMatteBorder(1,0,0,0,Color.BLACK);
            optionsPanel.setBorder(BorderFactory.createTitledBorder(lineBorder,myi18n
                    .getOptionGroupLabel(group)));
        }
        GPOption[] options = group.getOptions();
        for (int i = 0; i < options.length; i++) {
            GPOption nextOption = options[i];
            Component nextComponent = createOptionComponent(nextOption);
            if (needsLabel(nextOption)) {
                Component nextLabel =createOptionLabel(options[i]);
                optionsPanel.add(nextLabel);
                optionsPanel.add(nextComponent);                
            }
            else {
                optionsPanel.add(nextComponent);
                optionsPanel.add(new JPanel());
            }
        }
        if (options.length > 0) {
            SpringUtilities.makeCompactGrid(optionsPanel, options.length, 2, 0,
                    0, 3, 3);
        }
        return optionsPanel;
    }

    private boolean needsLabel(GPOption nextOption) {
        return false==nextOption instanceof BooleanOption;
    }

    public Component createStandaloneOptionPanel(GPOption option) {
        JPanel optionPanel = new JPanel(new BorderLayout());
        Component  optionComponent = createOptionComponent(option); 
        if (needsLabel(option)) {
            optionPanel.add(createOptionLabel(option), BorderLayout.WEST);
            optionPanel.add(optionComponent, BorderLayout.CENTER);
        }
        else {
            optionPanel.add(optionComponent, BorderLayout.WEST);
        }
        JPanel result = new JPanel(new BorderLayout());
        result.add(optionPanel, BorderLayout.NORTH);
        return result;
    }
    
    private Component createOptionLabel(GPOption option) {
        JLabel nextLabel = new JLabel(myi18n.getOptionLabel(option));
        nextLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 3));
        return nextLabel;
    }
    private Component createOptionComponent(GPOption option) {
        Component result = null;
        if (option instanceof EnumerationOption) {
            result = createEnumerationComponent((EnumerationOption) option);
        } else if (option instanceof BooleanOption) {
            result = createBooleanComponent((BooleanOption) option);
        }
        else if (option instanceof ColorOption) {
            result = createColorComponent((ColorOption)option);
        }
        else if (option instanceof DateOption) {
            result = createDateComponent((DateOption)option);
        }
        else if (option instanceof GPOptionGroup) {
            result = createButtonComponent((GPOptionGroup)option);
        }
        else if (option instanceof StringOption) {
            result = createStringComponent((StringOption)option);
        }
        if (result == null) {
            result = new JLabel("Unknown option class=" + option.getClass());
        }
        return result;
    }

    private Component createStringComponent(final StringOption option) {
        final JTextField result = new JTextField(option.getValue());
        result.getDocument().addDocumentListener(new DocumentListener() {
            public void insertUpdate(DocumentEvent e) {
                option.setValue(result.getText());
            }

            public void removeUpdate(DocumentEvent e) {
                option.setValue(result.getText());
            }

            public void changedUpdate(DocumentEvent e) {
                option.setValue(result.getText());
            }
        });
        return result;
    }

    private Component createButtonComponent(GPOptionGroup optionGroup) {
        Action action = new AbstractAction(myi18n.getAdvancedActionTitle()) {
            public void actionPerformed(ActionEvent e) {
                System.err
                        .println("[OptionsPageBuilder] createButtonComponent: ");
            }
            
        };
        JButton result = new JButton(action);
        return result;
    }
    private Component createBooleanComponent(BooleanOption option) {
        JCheckBox result = new JCheckBox(new BooleanOptionAction(option));
        result.setText(myi18n.getOptionLabel(option));
        result.setHorizontalAlignment(JCheckBox.LEFT);
        result.setHorizontalTextPosition(SwingConstants.TRAILING);
        result.setSelected(option.isChecked());
        ComponentOrientation componentOrientation = GanttLanguage.getInstance().getComponentOrientation();
        result.setComponentOrientation(componentOrientation);
        return result;
    }

    private JComboBox createEnumerationComponent(EnumerationOption option) {
        ComboBoxModel model = new EnumerationOptionComboBoxModel(option);
        JComboBox result = new JComboBox(model);
        return result;
    }

    private Component createColorComponent(final ColorOption option) {
        final JButton colorButton = new JButton();
        Action action = new AbstractAction(myi18n.getColorButtonText(option)) {
            public void actionPerformed(ActionEvent e) {
                ActionListener onOkPressing = new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        Color color = ourColorChooser.getColor();
                        colorButton.setBackground(color);
                        option.setValue(color);
                    }
                };
                ActionListener onCancelPressing = new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        // nothing to do for "Cancel"
                    }
                };
                JDialog dialog = JColorChooser.createDialog(myParentComponent,
                        myi18n.getColorChooserTitle(option), true,
                        ourColorChooser, onOkPressing, onCancelPressing);
                ourColorChooser.setColor(colorButton.getBackground());
                dialog.setVisible(true);
            };
        };
        colorButton.setAction(action);
        colorButton.setBackground(option.getValue());
        return colorButton;
    }
    
    private Component createDateComponent(final DateOption option) {
        final JXDatePicker result = new JXDatePicker();
        result.setDate(option.getValue());
        result.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                option.setValue(((JXDatePicker)e.getSource()).getDate());
            }
        });
        if (option instanceof ChangeValueDispatcher) {
            ((ChangeValueDispatcher)option).addChangeValueListener(new ChangeValueListener() {
                public void changeValue(ChangeValueEvent event) {
                    assert event.getNewValue() instanceof Date;
                    result.setDate((Date) event.getNewValue());
                }
            });
        }
        
        return result;
    }
    
    public static class I18N {
        private String myOptionKeyPrefix = "option.";
        private String myOptionGroupKeyPrefix = "optionGroup.";
        private String myOptionPageKeyPrefix = "optionPage.";
    	
    	public I18N() {
    	}
    	
    	protected String getValue(String key) {
    		return GanttLanguage.getInstance().getText(key);
    	}
        public String getPageTitle(String pageID) {
            return GanttLanguage.getInstance().getText(
                    myOptionPageKeyPrefix + pageID + ".title");
        }

        public String getPageDescription(String pageID) {
            return GanttLanguage.getInstance().getText(
                    myOptionPageKeyPrefix + pageID + ".description");
        }

        public String getOptionGroupLabel(GPOptionGroup group) {
            return GanttLanguage.getInstance().getText(
                    myOptionGroupKeyPrefix + group.getID() + ".label");
        }

        public String getOptionLabel(GPOption option) {
            return GanttLanguage.getInstance().getText(
                    myOptionKeyPrefix + option.getID() + ".label");
        }

        String getAdvancedActionTitle() {
            return GanttLanguage.getInstance().getText("optionAdvanced.label");
        }
        
        String getColorButtonText(ColorOption colorOption) {
            return GanttLanguage.getInstance().getText("colorButton");
        }
        
        String getColorChooserTitle(ColorOption colorOption) {
            return GanttLanguage.getInstance().getText("selectColor");
        }
    }
    
    private static JColorChooser ourColorChooser = new JColorChooser();
    
    static {
        ImageIcon calendarImage = new ImageIcon(OptionsPageBuilder.class.getResource(
        "/icons/calendar_16.gif"));        
        Icon nextMonth = new ImageIcon(OptionsPageBuilder.class
                .getResource("/icons/nextmonth.gif"));
        Icon prevMonth = new ImageIcon(OptionsPageBuilder.class
                .getResource("/icons/prevmonth.gif"));
        UIManager.put("JXDatePicker.arrowDown.image", calendarImage);
        UIManager.put("JXMonthView.monthUp.image", prevMonth);
        UIManager.put("JXMonthView.monthDown.image", nextMonth);
        UIManager.put("JXMonthView.monthCurrent.image", calendarImage);        
    }
}
