package adecWatt.view;

import java.awt.Color;
import java.awt.Font;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Collection;
import java.util.List;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;

import misc.Bundle;
import misc.LocalizedUserLabel;
import misc.Util;

import adecWatt.control.AdecWattManager;
import adecWatt.model.AdecWatt;
import adecWatt.model.ImageDB;
import adecWatt.model.PermanentDB;
import adecWatt.model.Prop;
import adecWatt.view.jProp.JPropText;
import static adecWatt.model.Permanent.PropTypeEnum;
import static adecWatt.model.Prop.PropMix;

public abstract class JProp {

    // ========================================
    static public final String
	AdecWattUser	= "AdecWattUser";

    public final static int defaultImageWidth = 256;
    public final static int defaultImageHeight = 512;

    static public Color
	textFgColor	= Color.black,
	textBgColor	= Color.white,
	noValueFgColor	= Color.darkGray,
	noValueBgColor	= Color.lightGray,
	badValueColor	= Color.red;

    public Border
	defaultBorder  = null,
	badValueBorder = new LineBorder (badValueColor);

    static protected JLabel getMsgLabel (String msg) {
	JLabel unknown = new JLabel (msg);
	unknown.setForeground (noValueFgColor);
	unknown.setBackground (noValueBgColor);
	unknown.setOpaque (true);
	return unknown;
    }
    static public JLabel getUnknownLabel () { return getMsgLabel ("?"); }
    static public JLabel getEmptyLabel ()   { return getMsgLabel ("_"); }

    // ========================================
    static public JProp getJProp (String propName, JEditable jEditable) {
	PropTypeEnum type = jEditable.getTypeToken (propName);
	try {
	    // find class adecWatt.view.jProp.JProp<<TYPE>> (avec TYPE = type.getTypeToken ())
	    return (JProp)
		ClassLoader.getSystemClassLoader ().
		loadClass (JPropText.class.getPackage ().getName ()+".JProp"+type).
		getConstructor (String.class, JEditable.class).
		newInstance (propName, jEditable);
	} catch (Exception e) {
	    throw new IllegalArgumentException ("Can't find constructor for type ("+type+").");
	}
    }

    // ========================================
    protected JEditable jEditable;
    protected AdecWatt adecWatt; // XXX ???
    protected PermanentDB permanentDB;
    protected ImageDB iconDB;
    protected ImageDB imageDB;
    protected String propName;
    protected PropTypeEnum type;
    protected int nbVal;
    protected Collection<String> enumChoice;
    protected boolean hidden;
    protected String ownValue, parentValue, lastValue;
    protected Double[] ownValues, parentValues, lastValues;
    protected boolean horizontalSpin, parentHorizontalSpin;
    protected LocalizedUserLabel localizedUserLabel;
    protected LocalizedUserLabel[] localizedUserMultiLabels;

    //public String		getSValue ()		{ return lastValue; }
    public ImageDB		getIconDB ()		{ return iconDB; }
    public ImageDB		getImageDB ()		{ return imageDB; }
    public String		getLastValue ()		{ return lastValue; }
    public String		getPropName ()		{ return propName; }
    public boolean		getHorizontalSpin ()	{ return horizontalSpin; }
    protected void		updateView ()		{ }
    abstract protected void	displayByType (boolean edit, JPanel jPropList, JTabbedPane jTabbedPane);

    // ========================================
    protected JProp (String propName, JEditable jEditable) {
	this.jEditable = jEditable;
	adecWatt = jEditable.getAdecWatt ();
	permanentDB = adecWatt.getPermanentDB ();
	iconDB = adecWatt.getIconDB ();
	imageDB = adecWatt.getImageDB ();
	this.propName = propName;
	type = jEditable.getTypeToken (propName);
	nbVal = jEditable.getNbVal (propName);
	enumChoice = jEditable.getPropEnumChoice (propName);
	lastValue = ownValue = jEditable.getPropValue (propName, false);
	parentValue = jEditable.getPropValue (propName, true);
	if (nbVal > 0) {
	    ownValues = jEditable.getPartialPropValue (propName, nbVal, false);
	    parentValues = jEditable.getPartialPropValue (propName, nbVal, true);
	    lastValues = ownValues;
	}
	hidden = jEditable.getPropHidden (propName);
	// XXX seulement si icon ou image
	parentHorizontalSpin = jEditable.getPropHorizontalSpin (propName, true);
	horizontalSpin = jEditable.getPropHorizontalSpin (propName, false)^parentHorizontalSpin;
	if (ownValue == null) {
	    lastValue = ownValue = parentValue;
	    lastValues = ownValues = parentValues;
	    horizontalSpin = parentHorizontalSpin;
	}
	boolean isLocalized = jEditable.getPropLocalized (propName);
	boolean linguist = jEditable.isLinguist ();
	localizedUserLabel = new LocalizedUserLabel (propName, isLocalized, linguist);
	List<String> multiLabel = jEditable.getPropLabel (propName);
	if (multiLabel == null)
	    return;
	localizedUserMultiLabels = new LocalizedUserLabel [multiLabel.size ()];
	for (int i = 0; i < localizedUserMultiLabels.length; i++) {
	    localizedUserMultiLabels[i] = new LocalizedUserLabel (multiLabel.get (i), isLocalized, linguist);
	    JLabel result = localizedUserMultiLabels[i].getJLabel ();
	    Font defaultFont = result.getFont ();
	    result.setFont (new Font (defaultFont.getName (), Font.PLAIN, (defaultFont.getSize ()*3)/4));
	}
    }

    // ========================================
    public void display (boolean edit, JPanel jPropList, JTabbedPane jTabbedPane) {
	if (!edit && (hidden || lastValue == null) && type != PropTypeEnum.Preview)
	    return;
	displayByType (edit, jPropList, jTabbedPane);
    }

    public void setUnchange (JTextComponent jTextComponent, boolean unchange) {
	if (unchange) {
	    jTextComponent.setText ("");
	    jTextComponent.setForeground (noValueFgColor);
	    jTextComponent.setBackground (noValueBgColor);
	} else {
	    jTextComponent.setForeground (textFgColor);
	    jTextComponent.setBackground (textBgColor);
	}
    }
    public void setChangeListener (final JTextComponent jTextComponent) {
	final Document document = jTextComponent.getDocument ();
	document.addDocumentListener (new DocumentListener () {
		public void changedUpdate (DocumentEvent e) {
		    document.removeDocumentListener (this);
		    setUnchange (jTextComponent, false);
		    document.addDocumentListener (this);
		}
		public void insertUpdate (DocumentEvent e) { changedUpdate (e); }
		public void removeUpdate (DocumentEvent e) { changedUpdate (e); }
	    });
	jTextComponent.addMouseListener (new MouseAdapter () {
		@SuppressWarnings ("serial")
		public void mousePressed (final MouseEvent e) {
		    if (!SwingUtilities.isRightMouseButton (e))
			return;
		    new JPopupMenu () {
			{
			    Util.addMenuItem (AdecWattManager.actionUnchange, new ActionListener () {
				    public void actionPerformed (ActionEvent e) {
					setUnchange (jTextComponent, true);
				    }
				}, this);
			    Point pos = e.getPoint ();
			    show (jTextComponent, pos.x, pos.y);
			}
		    };
		}
	    });
    }
    public void removeVal () {
	if (lastValue == parentValue)
	    return;
	lastValue = parentValue;
	lastValues = parentValues;
	updateView ();
    }
    public void unchangeVal () {
	lastValue = PropMix;
	lastValues = Prop.string2tab (lastValue, nbVal);
	updateView ();
    }
    public void setSpin (boolean horizontalSpin) {
	this.horizontalSpin = horizontalSpin;
	updateView ();
    }
    public void setVal (String newVal) {
	if (newVal == null | newVal.isEmpty ()) {
	    removeVal ();
	    return;
	}
	if (lastValue != null && newVal.equals (lastValue))
	    return;
	lastValue = newVal;
	lastValues = Prop.string2tab (lastValue, nbVal);
	updateView ();
    }

    // ========================================
    /**
       props = {type, parent, own, last};
     */
    public void getChange (Prop[] props) {
	lastValue = getLastValue ();
	if (lastValue != null && lastValue.isEmpty ())
	    lastValue = null;
	boolean newHorizontalSpin = horizontalSpin ^ parentHorizontalSpin;
	if (!(newHorizontalSpin)) {
	    if ((lastValue == null && props [2] == null) ||
		(lastValue != null && props [2] != null && lastValue.equals (props [2].sValue))) {
		props [3] = props [2];
		return;
	    }
	    if (lastValue == null && props [2] != null) {
		props [3] = props [1];
		return;
	    }
	}
	props [3] = new Prop (propName, type, horizontalSpin);
	props [3].setValue (lastValue);
    }

    public void confirmBundle () {
	String newLabel = localizedUserLabel.getNewLabel ();
	if (newLabel != null)
	    Bundle.setUser (AdecWattUser, localizedUserLabel.getLabel (), newLabel);
	if (localizedUserMultiLabels == null)
	    return;
	for (int i = 0; i < localizedUserMultiLabels.length; i++) {
	    newLabel = localizedUserMultiLabels[i].getNewLabel ();
	    if (newLabel != null)
		Bundle.setUser (AdecWattUser, localizedUserMultiLabels[i].getLabel (), newLabel);
	}
    }

    // ========================================
}
