package adecWatt.view;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.SwingConstants;

import misc.Bundle;
import misc.LocalizedUserLabel;
import misc.Util;
import static misc.Util.GBC;
import static misc.Util.GBCNL;

import misc.ScaledImage;
import misc.Story;

import adecWatt.model.AdecWatt;
import adecWatt.model.Editable;
import adecWatt.model.Prop;
import adecWatt.model.Unit;
import adecWatt.model.unit.Workspace;
import adecWatt.view.PrintWorkspace;
import adecWatt.view.jProp.JPropGeo;
import adecWatt.view.jProp.JPropIcon;
import static adecWatt.model.Permanent.PropTypeEnum;
import static adecWatt.model.Prop.DoubleMix;
import static adecWatt.model.Prop.PropIcon;
import static adecWatt.model.Prop.PropMix;

public class JEditable implements SwingConstants {

    // ========================================
    static public final int previewSize = 800;

    private Unit<?> storyUnit;
    private HashSet<Editable<?, ?, ?, ?>> editableSet = new HashSet<Editable<?, ?, ?, ?>> ();
    private boolean linguist;
    private JTabbedPane jTabbedPane = new JTabbedPane ();
    private JPanel jPropList = Util.getGridBagPanel ();
    protected LocalizedUserLabel localizedUserLabel;
    private ArrayList<LocalizedUserLabel> localizedTabName = new ArrayList<LocalizedUserLabel> ();

    public boolean isLinguist () { return linguist; }
    public AdecWatt getAdecWatt () { return storyUnit.getAdecWatt (); }
    public void addLocalizedUserLabel (LocalizedUserLabel localizedUserLabel) { localizedTabName.add (localizedUserLabel); }

    public String getId () {
	if (editableSet.size () > 1)
	    return PropMix;
	for (Editable<?, ?, ?, ?> editable : editableSet)
	    return editable.getId ();
	return null;
    }
    public String getModelName () {
	String result = null;
	for (Editable<?, ?, ?, ?> editable : editableSet)
	    try {
		String model = editable.getModel ().getLocalName ();
		if (result == null) {
		    result = model;
		    continue;
		}
		if (!result.equals (model))
		    return PropMix;
	    } catch (Exception e) {
		return null;
	    }
	return result;
    }
    public String getName () {
	if (editableSet.size () > 1)
	    return PropMix;
	for (Editable<?, ?, ?, ?> editable : editableSet)
	    return editable.getName ();
	return null;
    }
    public List<String> getOrderedPropsName () {
	List<String> result = null;
	for (Editable<?, ?, ?, ?> editable : editableSet) {
	    List<String> tmp = editable.getOrderedPropsName ();
	    if (tmp == null)
		continue;
	    if (result == null) {
		result = tmp;
		continue;
	    }
	    result.retainAll (tmp);
	}
	return result;
    }
    public PropTypeEnum getTypeToken (String propName) {
	for (Editable<?, ?, ?, ?> editable : editableSet) {
	    Prop type = editable.getProp (propName);
	    if (type != null)
		return type.getTypeToken ();
	}
	return null;
    }
    public int getNbVal (String propName) {
	for (Editable<?, ?, ?, ?> editable : editableSet) {
	    Prop type = editable.getProp (propName);
	    if (type != null)
		return type.nbVal;
	}
	return 0;
    }
    public List<String> getPropLabel (String propName) {
	List<String> result = null;
	for (Editable<?, ?, ?, ?> editable : editableSet) {
	    List<String> tmp = editable.getPropLabel (propName);
	    if (result == null) {
		result = tmp;
		continue;
	    }
	    if (result.equals (tmp))
		continue;
	    return null;
	}
	return result;
    }
    public Collection<String> getPropEnumChoice (String propName) {
	Collection<String> result = null;
	for (Editable<?, ?, ?, ?> editable : editableSet) {
	    Collection<String> tmp = editable.getPropEnumChoice (propName);
	    if (result == null) {
		result = tmp;
		continue;
	    }
	    if (result.equals (tmp))
		continue;
	    return null;
	}
	return result;
    }
    public boolean getPropHidden (String propName) {
	for (Editable<?, ?, ?, ?> editable : editableSet)
	    if (!editable.getPropHidden (propName))
		return false;
	return true;
    }
    public boolean getPropLocalized (String propName) {
	for (Editable<?, ?, ?, ?> editable : editableSet)
	    if (editable.getPropLocalized (propName))
		return true;
	return false;
    }
    public boolean getPropHorizontalSpin (String propName, boolean skipFirst) {
	for (Editable<?, ?, ?, ?> editable : editableSet)
	    if (editable.getPropHorizontalSpin (propName, skipFirst))
		return true;
	return false;
    }
    public String getPropValue (String propName, boolean skipFirst) {
	String result = null;
	boolean nullExist = false;
	for (Editable<?, ?, ?, ?> editable : editableSet) {
	    try {
		String tmp = editable.getPropVal (propName, skipFirst).sValue;
		if (tmp == null) {
		    if (result != null)
			return PropMix;
		    nullExist = true;
		    continue;
		}
		if (result == null) {
		    if (nullExist)
			return PropMix;
		    result = tmp;
		    continue;
		}
		if (result.equals (tmp))
		    continue;
		return PropMix;
	    } catch (Exception e) {
		if (!skipFirst && editable.getProp (propName) == null)
		    return PropMix;
		nullExist = true;
		continue;
	    }
	}
	if (result != null && nullExist)
	    return PropMix;
	return result;
    }
    public Double[] getPartialPropValue (String propName, int nbVal, boolean skipFirst)	{
	Double[] result = null;
	for (Editable<?, ?, ?, ?> editable : editableSet) {
	    Double[] tmp = new Double [nbVal];
	    editable.getPartialProp (propName, tmp, skipFirst);
	    if (result == null) {
		result = tmp;
		continue;
	    }
	    int nbMix = 0;
	    for (int i = 0; i < result.length; i++) {
		if (result[i] == DoubleMix) {
		    nbMix++;
		    continue;
		}
		if (result[i] == tmp[i] || (result[i] != null && result[i].equals (tmp[i])))
		    continue;
		result[i] = DoubleMix;
		nbMix++;
	    }
	    if (nbMix == result.length)
		return result;
	}
	return result;
    }
    public ScaledImage	getPreview () {
	try {
	    return new ScaledImage (PrintWorkspace.getIcon ((Workspace) storyUnit, previewSize, true));
	} catch (Exception e) {
	    return null;
	}
    }
    private JPropGeo firstGeo;
    ArrayList<JProp> allProps = new ArrayList<JProp> ();

    public void setFirstGeo (JPropGeo firstGeo) {
	if (this.firstGeo == null)
	    this.firstGeo = firstGeo;
    }

    public void plotCity (double latitude, double longitude) {
	if (firstGeo == null)
	    return;
	firstGeo.setGeo (latitude, longitude);
    }
    public void toFront (Component c) {
	jTabbedPane.setSelectedComponent (c);
    }

    // ========================================
    public JEditable (List<Editable<?, ?, ?, ?>> editables) {
	for (Editable<?, ?, ?, ?> editable : editables) {
	    Unit<?> storyUnit = editable.getStoryUnit ();
	    if (this.storyUnit != null && storyUnit != this.storyUnit)
		throw new IllegalArgumentException ("Can't managed heterogenous unit");
	    this.storyUnit = storyUnit;
	    editableSet.add (editable);
	}
	if (storyUnit == null)
	    throw new IllegalArgumentException ("Can't managed no unit");
	linguist = getAdecWatt ().getUser ().isLinguist ();
    }
    public JPanel getDislay (boolean edit) {
	JPanel jDisplay = new JPanel (new BorderLayout ());
	JPanel right = new JPanel ();
	jDisplay.add (right, BorderLayout.EAST);
	right.add (jPropList);
	// XXX si edit ...
	String editableId = getId ();
	String modelName = getModelName ();
	modelName = modelName == null || modelName == PropMix ? "" : (" ("+modelName+")");
	JLabel jLabelId = new JLabel ((editableId == PropMix ? Bundle.getMessage ("MixId") : editableId)+modelName);
	jLabelId.setForeground (Color.GRAY);
	Util.addComponent (jLabelId, jPropList, GBCNL);
	JPropIcon jPropIcon = new JPropIcon (PropIcon, this);
	String editableName = getName ();
	JLabel jLabelName = null;
	if (editableName == PropMix)
	    jLabelName = new JLabel (Bundle.getMessage ("MixName"));
	else {
	    localizedUserLabel = new LocalizedUserLabel (editableName, storyUnit.isLocalized (), linguist);
	    jLabelName = localizedUserLabel.getJLabel ();
	}
	jLabelName.setHorizontalTextPosition (SwingConstants.RIGHT);
	// XXX si line autre icon
	allProps.add (jPropIcon);
	Util.addComponent (jPropIcon.getMainIcon (edit), jPropList, GBC);
	Util.addComponent (jLabelName, jPropList, GBCNL);
	for (String propName : getOrderedPropsName ())
	    try {
		if (PropIcon.equals (propName))
		    continue;
		JProp jProp = JProp.getJProp (propName, this);
		allProps.add (jProp);
		jProp.display (edit, jPropList, jTabbedPane);
	    } catch (Exception e) {
		e.printStackTrace ();
	    }
	if (jTabbedPane.getTabCount () > 0)
	    jDisplay.add (jTabbedPane, BorderLayout.CENTER);
	if (linguist)
	    jTabbedPane.addMouseListener (new MouseAdapter () {
		    public void mousePressed (MouseEvent e) {
			int idx = jTabbedPane.indexAtLocation (e.getX (), e.getY ());
			if (idx < 0)
			    return;
			LocalizedUserLabel localizedUserLabel = localizedTabName.get (idx);
			localizedUserLabel.mousePressed (e);
			jTabbedPane.setTitleAt (idx, localizedUserLabel.getCurrentLabel ());
		    }
		});
	return jDisplay;
    }

    // ========================================
    public boolean valideChange () {
	// if (!jNewPropName.getText ().isEmpty ())
	//     return false;
	return true;
    }

    public void confirmBundle () {
	if (!getAdecWatt ().getUser ().isLinguist ())
	    return;
	if (localizedUserLabel != null) {
	    String newLabel = localizedUserLabel.getNewLabel ();
	    if (newLabel != null)
		Bundle.setUser (JProp.AdecWattUser, getName (), newLabel);
	}
	for (JProp jProp : allProps)
	    jProp.confirmBundle ();
	Bundle.save (JProp.AdecWattUser);
    }

    public void updateStoryView () {
    	for (Editable<?, ?, ?, ?> editable : editableSet)
    	    editable.updateView ();
    }
    public void confirmChange () {
	// XXX revoir code avant 1/10/16 storyUnit.getLocalName ()
	// start story
	Story.Commands commands = storyUnit.story.new Commands (Editable.StoryEdit) {
		public void display () { updateStoryView (); }
	    };
	for (Editable<?, ?, ?, ?> editable : editableSet) {
	    ArrayList<Prop[]> changeProps = new ArrayList<Prop[]> ();
	    for (JProp jProp : allProps) {
		String propName = jProp.getPropName ();
		// props = {type, parent, own, last};
		Prop [] props = new Prop [] {editable.getProp (propName), editable.getParentPropVal (propName),
					     editable.getOwnProp (propName), null};
		jProp.getChange (props);
		changeProps.add (props);
	    }
	    editable.storyChange (commands, changeProps);
	}
	storyUnit.story.add (commands);
    }

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