package adecWatt.model;

import java.util.Arrays;
import java.util.Collection;
import java.util.TreeSet;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import misc.Bundle;
import adecWatt.model.xml.XmlPermanent;

public abstract class Permanent<P extends XmlPermanent<T, A>, T extends Enum<?>, A extends Enum<?>> {
    // ========================================
    static public enum UnitTypeEnum { Furniture, Information, Line, Accessory, Building, Lightplot; };
    static public enum SegmTypeEnum { Segment; };
    static public enum CompTypeEnum { Component; };
    static public enum AccTypeEnum  { Accessory; };
    // XXX type "Comp" pour référence ?
    static public enum PropTypeEnum { Text, Article, Icon, Image, Preview, Enum, Building, City, Number, Square, Geo, Cube; };

    static public enum UnitAttrEnum { Id, Name, Modifier, Parent, Author, Updated; };
    static public enum SegmAttrEnum { Name, Modifier, Model, Placeid; };
    static public enum CompAttrEnum { Name, Modifier, Model, Placeid, Available; };
    static public enum AccAttrEnum  { Name, Modifier, Model, Placeid; };
    static public enum PropAttrEnum { Name, Modifier, Multilabel, Spin, Choice, Rank; };

    // ========================================
    static public final String
	Lock		= "lock",
	Mandatory	= "mandatory",
	Localized	= "localized",
	NoMouse		= "nomouse",
	Hidden		= "hidden",
	Sticky		= "sticky",
	Reserved	= "reserved",
	Direct		= "direct";

    static public final String
	NoSpin	= "none",
	HorizontalSpin	= "horizontal";

    // ========================================
    static public final Collection<String> UnitModifiersSet		= Arrays.asList (Localized);
    static public final Collection<String> SegmModifiersSet		= Arrays.asList (Sticky, Hidden);
    static public final Collection<String> CompModifiersSet		= Arrays.asList (Sticky, Reserved, Hidden);
    static public final Collection<String> AccModifiersSet		= Arrays.asList ();
    static public final Collection<String> PropModifiersSet 		= Arrays.asList (Lock, Mandatory, Localized, Hidden, NoMouse);
    static public final Collection<String> PropHiddenModifiersSet	= Arrays.asList (Lock);
    static public final Collection<String> PropNotHiddenModifiersSet	= Arrays.asList (Mandatory, Localized, Hidden, NoMouse);

    static public final Collection<String> PropSpinSet 			= Arrays.asList (NoSpin, HorizontalSpin);

    // ========================================
    public abstract Collection<String>	getModifiersSet ();
    public abstract T			getTypeToken ();
    public abstract A			getNameToken ();
    public abstract A			getModifierToken ();

    protected P				xmlPermanent;
    protected String			name;
    protected Collection<String>	modifiers;
    protected Collection<String>	unknownModifiers;

    // ========================================
    public String		getName ()				{ return name; }
    public String		getLocalName ()				{ return isLocalized () ? Bundle.getUser (getName ()) : getName (); }
    public Collection<String>	getModifiers ()				{ return modifiers; }

    public String		getModifiersString ()			{ return getModifiersString (modifiers); }
    public boolean		isModifier (String modifierName)	{ return isModifier (modifierName, modifiers); }
    public boolean		isLocalized ()				{ return isModifier (Localized); }
    public boolean		isLock ()				{ return isModifier (Lock); }
    public boolean		isHidden ()				{ return isModifier (Hidden); }
    public boolean		isMandatory ()				{ return isModifier (Mandatory); }
    public boolean		isSticky ()				{ return isModifier (Sticky); }
    public boolean		isReserved ()				{ return isModifier (Reserved); }
    public boolean		isNoMouse ()				{ return isModifier (NoMouse); }
    public boolean		isDirect ()				{ return isModifier (Direct); }

    // ========================================
    protected Permanent () {
    }
    protected Permanent (P xmlPermanent) {
	initXmlAvantOwnProp (xmlPermanent);
    }

    protected void importFrom (Permanent<P, T, A> from) {
	if (unknownModifiers == null && from.unknownModifiers != null)
	    unknownModifiers = from.unknownModifiers;
	if (from.modifiers != null)
	    if (modifiers != null)
		modifiers.addAll (from.modifiers);
	    else
		modifiers = new TreeSet<String> (from.modifiers);
	// XXX pb cause furniture à la place de composant dans un copier/coller
	// if (xmlPermanent == null && from.xmlPermanent != null)
	//     xmlPermanent = from.xmlPermanent;
    }

    protected void initXmlAvantOwnProp (P xmlPermanent) {
	this.xmlPermanent = xmlPermanent;
	name = xmlPermanent.getFacet (getNameToken ());
	try {
	    unknownModifiers = xmlPermanent.getSplitFacet (getModifierToken ());
	    modifiers = null; // XXX pas utile
	    for (String token : unknownModifiers)
		addModifier (token);
	    unknownModifiers.removeAll (modifiers);
	    if (unknownModifiers.size () < 1)
		unknownModifiers = null;
	} catch (Exception e) {
	}
    }

    // ========================================
    public void setModifiers (Collection<String> modifiers) {
	if (modifiers == null || modifiers.size () == 0) {
	    this.modifiers = null;
	    return;
	}
	this.modifiers = modifiers;
    }
    public void addModifier (String modifier) {
	if (modifier == null || modifier.isEmpty ())
	    return;
	if (!getModifiersSet ().contains (modifier))
	    return;
	if (modifiers == null)
	    modifiers = new TreeSet<String> ();
	modifiers.add (modifier);
    }
    public void removeModifier (String modifier) {
	if (modifiers == null || modifier == null || modifier.isEmpty ())
	    return;
	modifiers.remove (modifier);
	if (modifiers.size () < 1)
	    modifiers = null;
    }
    static public boolean isModifier (String modifierName, Collection<String> modifiers) {
	return modifiers != null && modifiers.contains (modifierName);
    }
    static public String getModifiersString (Collection<String> modifiers) {
	if (modifiers == null)
	    return "";
	return String.join ("|", modifiers);
    }

    // ========================================
    @SuppressWarnings ("unchecked")
	public Element getXml (Node parent, Document document) {
	Element child = xmlPermanent == null ?
	    document.createElement (getTypeToken ().toString ().toLowerCase ())
	    : xmlPermanent.getXml (document);
	parent.appendChild (child);
	XmlPermanent.putFacet (child, getNameToken (), name);
	XmlPermanent.putSplitFacet (child, getModifierToken (), modifiers, unknownModifiers);
	return child;
    }

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