package lu.tudor.santec.gecamed.formeditor.gui.component;

import java.awt.Color;
import java.awt.Font;
import java.awt.GraphicsEnvironment;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.font.TextAttribute;
import java.util.Map;
import java.util.Vector;

import javax.swing.AbstractButton;
import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.JToggleButton;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;

import lu.tudor.santec.gecamed.core.gui.GECAMedIconNames;
import lu.tudor.santec.gecamed.core.gui.GECAMedModule;
import lu.tudor.santec.gecamed.core.gui.widgets.NamedComponent;
import lu.tudor.santec.gecamed.formeditor.gui.controller.ColorChangeListener;
import lu.tudor.santec.gecamed.formeditor.gui.model.ComboBoxElement;
import lu.tudor.santec.i18n.Translatrix;

import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.CellConstraints.Alignment;
import com.jgoodies.forms.layout.FormLayout;

public class DefaultPropertyPanel extends SettingsBasePanel
{
	private static final long serialVersionUID = 1L;
	
	/** the logger Object for this class */
//	private static Logger logger = Logger.getLogger(DefaultPropertyPanel.class.getName());
	
	private static final String[] FONTS = GraphicsEnvironment.getLocalGraphicsEnvironment(). 
    										getAvailableFontFamilyNames();
	
	/* ======================================== */
	// 		MEMBERS
	/* ======================================== */
	
	protected boolean 			paintBorder = false;
	protected Color				borderColor = Color.BLACK;
	protected boolean 			paintBackground;
	protected Color 			backgroundColor;
	
	
	/* ---------------------------------------- */
	// 		COMPONENTS
	/* ---------------------------------------- */
	
	// NamedComponents
	protected NamedComponent 	borderColorComponent;
	protected NamedComponent 	backgroundColorComponent;
	protected NamedComponent 	fontSizeComponent;
	protected NamedComponent 	fontFamilyComponent;
	protected NamedComponent 	fontColorComponent;
	protected NamedComponent 	hAlignComponent;
	protected NamedComponent 	vAlignComponent;
	
	// ComboBoxes
	protected JComboBox 		fontFamilyBox;
	protected JComboBox 		hAlignmentBox;
	protected JComboBox 		vAlignmentBox;
	
	// CheckBoxes & ToggleButtons
	protected JCheckBox			paintBorderBox;
	protected JCheckBox			paintBackgroundBox;
	protected JToggleButton		boldButton;
	protected JToggleButton		italicButton;
	protected JToggleButton		underlineButton;
	
	// ColorChooser
	protected GECAMedColorChooser borderColorChooser;
	protected GECAMedColorChooser backgroundColorChooser;
	protected GECAMedColorChooser fontColorChooser;
	
	// Texts
	protected NumericField		fontSizeField;
	
	
	/* ======================================== */
	// 		CONSTRUCTOR
	/* ======================================== */
	
	public DefaultPropertyPanel(EditableComponent editableComponent)
	{
		super(editableComponent);
	}
	
	
	@Override
	protected void init ()
	{
		if (editableComponent.isRealComponent())
			initRealComponent();
		else 
			initDummyAndBorderComponent();
	}
	
	private void initDummyAndBorderComponent ()
	{
		JComponent		component 	= editableComponent.getComponentForProperty();
		
		// initialize border color
		Border border = component.getBorder();
		
		paintBorder = !(border == null || border instanceof EmptyBorder);
		
		if (border != null && border instanceof LineBorder)
			 borderColor = ((LineBorder)border).getLineColor();
		else borderColor = Color.BLACK;
		
		// initialize background color
		backgroundColor = component.getBackground();
		paintBackground = component.isOpaque();
	}
	
	protected void initRealComponent ()
	{
		JComponent		component 	= editableComponent.getComponentForProperty();
		
		/* ----------  BORDER  ---------- */
		Border border = component.getBorder();
		paintBorder = border != null && border instanceof LineBorder;
		
		if (paintBorder)
			 borderColor = ((LineBorder)border).getLineColor();
		else borderColor = Color.BLACK;
		
		paintBorderBox = new JCheckBox(
				Translatrix.getTranslationString("formeditor.paintBorder"), 
				paintBorder);
		paintBorderBox.setToolTipText(
				Translatrix.getTranslationString("formeditor.paintBorderToolTip"));
		paintBorderBox.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent e) 
			{
				paintBorder = ((JCheckBox)e.getSource()).isSelected();
				paintBorder();
			}
		});
		paintBorderBox.setOpaque(false);
		
		appendRow(paintBorderBox);
		
		borderColorChooser = new GECAMedColorChooser(this,
				Translatrix.getTranslationString("formeditor.chooseColor"),
				borderColor);
		borderColorChooser.setToolTipText(
				Translatrix.getTranslationString("formeditor.borderColorToolTip"));
		borderColorChooser.addColorChangeListener(new ColorChangeListener() 
		{
			public void colorChangedByAction(Color c) 
			{
				if (c != null) 
				{
					borderColor = c;
					paintBorder();
				}
			}
			
			public void colorChanged (Color c) {} 
		});
		
		borderColorComponent = new NamedComponent(
				Translatrix.getTranslationString("formeditor.borderColor"), 
				borderColorChooser);
		appendRow(borderColorComponent);
		/* ---------------------------------------- */
		
		
		/* ----------  BACKGROUND  ---------- */
		paintBackground = component.isOpaque();
		backgroundColor = component.getBackground();
		
		paintBackgroundBox = new JCheckBox(
				Translatrix.getTranslationString("formeditor.paintBackground"),
				paintBackground);
		paintBackgroundBox.setToolTipText(
				Translatrix.getTranslationString("formeditor.paintBackgroundToolTip"));
		paintBackgroundBox.addActionListener(new ActionListener() {
	
			public void actionPerformed(ActionEvent e) 
			{
				paintBackground = ((JCheckBox)e.getSource()).isSelected();
				editableComponent.setComponentOpaq(paintBackground);
				editableComponent.repaint();
			}
		});
		paintBackgroundBox.setOpaque(false);
		
		appendRow(paintBackgroundBox);
		
		backgroundColorChooser = new GECAMedColorChooser(this, 
				Translatrix.getTranslationString("formeditor.chooseColor"),
				component.getBackground());
		backgroundColorChooser.setColor(backgroundColor);
		backgroundColorChooser.setToolTipText(
				Translatrix.getTranslationString("formeditor.backgroundColorToolTip"));
		backgroundColorChooser.addColorChangeListener(new ColorChangeListener() 
		{
			public void colorChanged(Color c) {}
			
			public void colorChangedByAction (Color c) 
			{
				if (c != null) 
				{
					editableComponent.setComponentBackground(c);
					editableComponent.setComponentBackgroundTemporarily(backgroundColor);
					editableComponent.repaint();
				}
			}
		});
		
		backgroundColorComponent = new NamedComponent(
				Translatrix.getTranslationString("formeditor.backgroundColor"), 
				backgroundColorChooser);
		appendRow(backgroundColorComponent);
		/* ---------------------------------------- */
		
		
		/* ----------  FONT  ---------- */
		Font font = component.getFont();
		
		// -- style --
		JLabel fontStyleLabel = new JLabel("<html><b>" +
				Translatrix.getTranslationString("formeditor.fontStyle") + ":");
		fontStyleLabel.setOpaque(false);
		appendRow(fontStyleLabel);
		
		// 		-- bold
		boldButton = new JToggleButton(
				GECAMedModule.getMediumIcon(GECAMedIconNames.TEXT_BOLD), 
				font.getAttributes().get(TextAttribute.WEIGHT) != null && 
				!font.getAttributes().get(TextAttribute.WEIGHT).equals(TextAttribute.WEIGHT_REGULAR));
		boldButton.setToolTipText(
				Translatrix.getTranslationString("formeditor.boldButtonToolTip"));
		boldButton.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent e) 
			{
				fontStyleChanged(boldButton, TextAttribute.WEIGHT, 
						TextAttribute.WEIGHT_BOLD, TextAttribute.WEIGHT_REGULAR);
			}
		});
		boldButton.setOpaque(true);
	
		// 		-- italic
		italicButton = new JToggleButton(
				GECAMedModule.getMediumIcon(GECAMedIconNames.TEXT_ITALIC), 
				font.getAttributes().get(TextAttribute.POSTURE) != null && 
				!font.getAttributes().get(TextAttribute.POSTURE).equals(TextAttribute.POSTURE_REGULAR));
		italicButton.setToolTipText(
				Translatrix.getTranslationString("formeditor.italicButtonToolTip"));
		italicButton.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent e) 
			{
				fontStyleChanged(italicButton, TextAttribute.POSTURE, 
						TextAttribute.POSTURE_OBLIQUE, TextAttribute.POSTURE_REGULAR);
			}
		});
		italicButton.setOpaque(false);
	//	italicBox.setSize(32, 32);
	
		// 		-- underline
		underlineButton = new JToggleButton(
				GECAMedModule.getMediumIcon(GECAMedIconNames.TEXT_UNDER), 
				font.getAttributes().get(TextAttribute.UNDERLINE) != null && 
				font.getAttributes().get(TextAttribute.UNDERLINE).equals(TextAttribute.UNDERLINE_ON));
		underlineButton.setToolTipText(
				Translatrix.getTranslationString("formeditor.underlineButtonToolTip"));
		underlineButton.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent e) 
			{
				fontStyleChanged(underlineButton, TextAttribute.UNDERLINE, 
						TextAttribute.UNDERLINE_ON, null);
			}
		});
		underlineButton.setOpaque(false);
		
		JPanel buttonPanel = new JPanel(new FormLayout("32px, 2dlu, 32px, 2dlu, 32px", "32px"));
		buttonPanel.add(boldButton, CC.xy(1, 1));
		buttonPanel.add(italicButton, CC.xy(3, 1));
		buttonPanel.add(underlineButton, CC.xy(5, 1));
		buttonPanel.setOpaque(false);
		appendRow(buttonPanel);
		
		// -- size
		fontSizeField = new NumericField(font.getSize());
		fontSizeField.addKeyListener(new KeyListener() 
		{
			public void keyPressed(KeyEvent e) {}
			public void keyTyped(KeyEvent e) {}
			
			public void keyReleased(KeyEvent e) 
			{
				fontSizeChanged();
			}
		});
		
		fontSizeComponent = new NamedComponent(
				Translatrix.getTranslationString("formeditor.fontSize"), 
				fontSizeField);
		fontSizeComponent.setToolTipText(
				Translatrix.getTranslationString("formeditor.fontSizeToolTip"));
		appendRow(fontSizeComponent);
		
		// -- family
		fontFamilyBox = new JComboBox(FONTS);
		String fontFamily = (String) font.getAttributes().get(TextAttribute.FAMILY);
		for (int index = 0; index < fontFamilyBox.getItemCount(); index++) 
		{
			if (fontFamily.equals(fontFamilyBox.getItemAt(index))) 
			{
				fontFamilyBox.setSelectedIndex(index);
				break;
			}
		}
		
		fontFamilyBox.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent e) 
			{
				editableComponent.changeFont(TextAttribute.FAMILY, fontFamilyBox.getSelectedItem());
			}
		});
		
		fontFamilyComponent = new NamedComponent(
				Translatrix.getTranslationString("formeditor.fontFamily"), 
				fontFamilyBox);
		fontFamilyComponent.setToolTipText(
				Translatrix.getTranslationString("formeditor.fontFamilyToolTip"));
		appendRow(fontFamilyComponent);
		
		// -- color
		fontColorChooser = new GECAMedColorChooser(this,
				Translatrix.getTranslationString("formeditor.chooseColor"),
//				(Color)component.getFont().getAttributes().get(TextAttribute.FOREGROUND));
				component.getForeground());
				//component.getForeground());
		fontColorChooser.setToolTipText(
				Translatrix.getTranslationString("formeditor.fontColorToolTip"));
		fontColorChooser.addColorChangeListener(new ColorChangeListener() 
		{
			public void colorChangedByAction(Color c) 
			{
				if (c != null) 
				{
					editableComponent.changeFont(TextAttribute.FOREGROUND, c);
					editableComponent.repaint();
				}
			}
			
			public void colorChanged (Color c) {}
		});
		
		fontColorComponent = new NamedComponent(
				Translatrix.getTranslationString("formeditor.fontColor"), 
				fontColorChooser);
		appendRow(fontColorComponent);
		/* ---------------------------------------- */
		
		
		/* ----------  HORIZONTAL ALIGNMENT  ---------- */
		// the alignment items are created and put into the comboBox
		Vector<ComboBoxElement<Alignment>> hAlignmentItems = new Vector<ComboBoxElement<Alignment>>();
		hAlignmentItems.addElement(new ComboBoxElement<Alignment>(
				Translatrix.getTranslationString("formeditor.default"),
				CellConstraints.DEFAULT));
		hAlignmentItems.addElement(new ComboBoxElement<Alignment>(
				Translatrix.getTranslationString("formeditor.left"),
				CellConstraints.LEFT));
		hAlignmentItems.addElement(new ComboBoxElement<Alignment>(
				Translatrix.getTranslationString("formeditor.center"),
				CellConstraints.CENTER));
		hAlignmentItems.addElement(new ComboBoxElement<Alignment>(
				Translatrix.getTranslationString("formeditor.right"),
				CellConstraints.RIGHT));
		hAlignmentItems.addElement(new ComboBoxElement<Alignment>(
				Translatrix.getTranslationString("formeditor.fill"),
				CellConstraints.FILL));
		
		hAlignmentBox = new JComboBox(hAlignmentItems);
		
		final CellConstraints constraints = editableComponent.getConstraints();
		if (constraints != null)
		{
			int index;
			if (constraints.hAlign.equals(CellConstraints.LEFT)) 
				index = 1;
			else if (constraints.hAlign.equals(CellConstraints.CENTER)) 
				index = 2;
			else if (constraints.hAlign.equals(CellConstraints.RIGHT)) 
				index = 3;
			else if (constraints.vAlign.equals(CellConstraints.FILL)) 
				index = 4;
			else /* if (constraints.hAlign.equals(CellConstraints.DEFAULT)) */
				index = 0;
			
			hAlignmentBox.setSelectedIndex(index);
		}
		
		hAlignmentBox.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent e) 
			{
				hAlignmentBoxClicked();
			}
		});
		
		hAlignComponent = new NamedComponent(
				Translatrix.getTranslationString("formeditor.hAlign"), 
				hAlignmentBox);
		hAlignComponent.setToolTipText(
				Translatrix.getTranslationString("formeditor.hAlignToolTip"));
		appendRow(hAlignComponent);
		/* ---------------------------------------- */
		
		
		/* ----------  VERTICAL ALIGNMENT  ---------- */
		// the alignment items are created and put into the comboBox
		Vector<ComboBoxElement<Alignment>> vAlignmentItems = new Vector<ComboBoxElement<Alignment>>();
		vAlignmentItems.addElement(new ComboBoxElement<Alignment>(
				Translatrix.getTranslationString("formeditor.default"),
				CellConstraints.DEFAULT));
		vAlignmentItems.addElement(new ComboBoxElement<Alignment>(
				Translatrix.getTranslationString("formeditor.top"),
				CellConstraints.TOP));
		vAlignmentItems.addElement(new ComboBoxElement<Alignment>(
				Translatrix.getTranslationString("formeditor.center"),
				CellConstraints.CENTER));
		vAlignmentItems.addElement(new ComboBoxElement<Alignment>(
				Translatrix.getTranslationString("formeditor.bottom"),
				CellConstraints.BOTTOM));
		vAlignmentItems.addElement(new ComboBoxElement<Alignment>(
				Translatrix.getTranslationString("formeditor.fill"),
				CellConstraints.FILL));
		
		vAlignmentBox = new JComboBox(vAlignmentItems);
		
		if (constraints != null)
		{
			int index;
			if (constraints.vAlign.equals(CellConstraints.TOP)) 
				index = 1;
			else if (constraints.vAlign.equals(CellConstraints.CENTER)) 
				index = 2;
			else if (constraints.vAlign.equals(CellConstraints.BOTTOM)) 
				index = 3;
			else if (constraints.vAlign.equals(CellConstraints.FILL)) 
				index = 4;
			else /* if (constraints.vAlign.equals(CellConstraints.DEFAULT)) */
				index = 0;
			
			vAlignmentBox.setSelectedIndex(index);
		}
		vAlignmentBox.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent e)
			{
				vAlignmentBoxClicked();
			}
		});
		
		vAlignComponent = new NamedComponent(
				Translatrix.getTranslationString("formeditor.vAlign"), 
				vAlignmentBox);
		vAlignComponent.setToolTipText(
				Translatrix.getTranslationString("formeditor.vAlignToolTip"));
		appendRow(vAlignComponent);
	}


	public void paintBorder () 
	{
		if (paintBorder) {
			editableComponent.setBorder(BorderFactory.createLineBorder(borderColor));
		} else {
			editableComponent.setBorder(BorderFactory.createEmptyBorder());
		}
		editableComponent.repaint();
	}


	public void fontSettingsChanged ()
	{
		fontSettingsChanged(TextAttribute.FAMILY);
		fontSettingsChanged(TextAttribute.SIZE);
		fontSettingsChanged(TextAttribute.FOREGROUND);
		fontSettingsChanged(TextAttribute.POSTURE);
		fontSettingsChanged(TextAttribute.WEIGHT);
		fontSettingsChanged(TextAttribute.UNDERLINE);
	}
	
	
	public void fontSettingsChanged(TextAttribute key)
	{
		if (!editableComponent.isRealComponent())
			return;
		
		Map<TextAttribute, ?> attributes = editableComponent
				.getComponentForProperty().getFont().getAttributes();
		Object value = attributes.get(key);
		
		if (TextAttribute.UNDERLINE.equals(key))
		{
			underlineButton.setSelected(value != null);
		}
		else if (value == null)
		{
			return;
		} 
		else if (TextAttribute.FAMILY.equals(key))
		{
			for (int index = 0; index < fontFamilyBox.getItemCount(); index++)
			{
				if (value.equals(fontFamilyBox.getItemAt(index)))
				{
					fontFamilyBox.setSelectedIndex(index);
					return;
				}
			}
		}
		else if (TextAttribute.SIZE.equals(key))
		{
			String valueText = String.valueOf(((Float)value).intValue());
			String fieldText = fontSizeField.getText();
			
			if (!valueText.equals(fieldText))
				fontSizeField.setText(valueText);
		}
		else if (TextAttribute.FOREGROUND.equals(key))
		{
			fontColorChooser.setColor((Color) value);
		}
		else if (TextAttribute.POSTURE.equals(key))
		{
			italicButton.setSelected((Float)value > 0);
		}
		else if (TextAttribute.WEIGHT.equals(key))
		{
			boldButton.setSelected((Float)value > TextAttribute.WEIGHT_REGULAR);
		}
	}
	
	
	
	/* ======================================== */
	// 		HELPER METHODS
	/* ======================================== */
	
	protected void fontStyleChanged (AbstractButton button, TextAttribute key, Object trueValue, Object falseValue)
	{
		editableComponent.changeFont(key, button.isSelected() ? trueValue : falseValue);
	}
	
	protected void fontSizeChanged()
	{
		Integer size;
		try {
			size = Integer.valueOf((int)Double.parseDouble(fontSizeField.getText()));
			if (size < 0)
			{
				size *= -1;
			}
		} catch (NumberFormatException nfe) {
//			logger.log(Level.ERROR, nfe.getMessage(), nfe);
			return;
		}
		Number fontSize = (Number) editableComponent.getFont(TextAttribute.SIZE);
		
		if (fontSize != null && size.intValue() == fontSize.intValue())
			return;
		
		editableComponent.changeFont(TextAttribute.SIZE, size);
		
	}
	
	protected void vAlignmentBoxClicked ()
	{
		CellConstraints 	constraints = editableComponent.getConstraints();
		ComboBoxElement<?> 	elem 		= (ComboBoxElement<?>) vAlignmentBox.getSelectedItem();
		Alignment 			alignment 	= (Alignment) elem.getValue();
		
		constraints.rchw(constraints.gridY, constraints.gridX, 
				constraints.gridHeight, constraints.gridWidth, 
				alignment, constraints.hAlign);
		editableComponent.model.getView().rearrangeEditPanel();
	}
	

	protected void hAlignmentBoxClicked ()
	{
		CellConstraints 	constraints = editableComponent.getConstraints();
		ComboBoxElement<?> 	elem = (ComboBoxElement<?>) hAlignmentBox.getSelectedItem();
		Alignment 			alignment = (Alignment) elem.getValue();
		
		constraints.rchw(constraints.gridY, constraints.gridX, 
				constraints.gridHeight, constraints.gridWidth, 
				constraints.vAlign, alignment);
		editableComponent.model.getView().rearrangeEditPanel();
	}
	
	
	
	/* ======================================== */
	// 		GETTER & SETTER
	/* ======================================== */
	
	public boolean isPaintBorder()
	{
		return paintBorder;
	}
	
	public void setPaintBorder(boolean paintBorder)
	{
		this.paintBorder = paintBorder;
		if (paintBorderBox != null)
			paintBorderBox.setSelected(paintBorder);
	}
	
	public Color getBorderColor()
	{
		return borderColor;
	}
	
	public void setBorderColor(Color borderColor)
	{
		this.borderColor = borderColor;
		if (borderColorChooser != null)
			borderColorChooser.setColor(borderColor);
		
	}
	
	public boolean isPaintBackground()
	{
		return paintBackground;
	}
	
	public void setPaintBackground(boolean paintBackground)
	{
		this.paintBackground = paintBackground;
		if (paintBackgroundBox != null)
			paintBackgroundBox.setSelected(paintBackground);
	}
	
	public Color getBackgroundColor ()
	{
		return backgroundColor;
	}
	
	public void setBackgroundColor (Color color)
	{
		this.backgroundColor = color;
		if (backgroundColorChooser != null)
			backgroundColorChooser.setColor(color);
	}
	
	
	
	/* ---------------------------------------- */
	// 		COMPONENT GETTER
	/* ---------------------------------------- */
	
	public NamedComponent getBorderColorComponent()
	{
		return borderColorComponent;
	}

	public NamedComponent getBackgroundColorComponent()
	{
		return backgroundColorComponent;
	}

	public NamedComponent getFontSizeComponent()
	{
		return fontSizeComponent;
	}

	public NamedComponent getFontFamilyComponent()
	{
		return fontFamilyComponent;
	}

	public NamedComponent getFontColorComponent()
	{
		return fontColorComponent;
	}

	public NamedComponent gethAlignComponent()
	{
		return hAlignComponent;
	}

	public NamedComponent getvAlignComponent()
	{
		return vAlignComponent;
	}

	public JComboBox getFontFamilyBox()
	{
		return fontFamilyBox;
	}

	public JComboBox gethAlignmentBox()
	{
		return hAlignmentBox;
	}

	public JComboBox getvAlignmentBox()
	{
		return vAlignmentBox;
	}

	public JCheckBox getPaintBorderBox()
	{
		return paintBorderBox;
	}

	public JCheckBox getPaintBackgroundBox()
	{
		return paintBackgroundBox;
	}

	public JTextField getFontSizeField()
	{
		return fontSizeField;
	}
}
