// XXX test eclipse

package adecWatt.model;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Collection;
import misc.DimensionDouble;
import misc.ScaledImage;
import misc.Story;

import adecWatt.model.unit.Accessory;
import adecWatt.model.unit.Workspace;
import adecWatt.model.xml.XmlAcc;

public class Acc extends Embedded<XmlAcc, Permanent.AccTypeEnum, Permanent.AccAttrEnum, Editable<?, ?, ?, ?>, Acc> {
    // ========================================
    public Collection<String>	getModifiersSet ()	{ return AccModifiersSet; }
    public AccTypeEnum		getTypeToken ()		{ return AccTypeEnum.Accessory; }
    public AccAttrEnum		getNameToken ()		{ return AccAttrEnum.Name; }
    public AccAttrEnum		getModifierToken ()	{ return AccAttrEnum.Modifier; }
    public AccAttrEnum		getPlaceIdToken ()	{ return AccAttrEnum.Placeid; }
    public AccAttrEnum		getModelToken ()	{ return AccAttrEnum.Model; }

    public Workspace		getStoryUnit ()		{ return ((Comp)container).container; }
    public Acc	getLink (Editable<?, ?, ?, ?> support)	{ return new Acc (name, placeId, support, (Accessory) model); }

    // ========================================
    public Acc (Editable<?, ?, ?, ?> support, XmlAcc xmlAcc) {
     	super (support, xmlAcc);
    }
    public Acc (String name, String placeName, Editable<?, ?, ?, ?> support, Accessory model) {
	super (name, placeName, support, model);
    }
    public Acc (Editable<?, ?, ?, ?> support, Accessory model) {
	super (null, "", support, model);
    }
    public Acc clone (Editable<?, ?, ?, ?> support) {
	Acc result = new Acc (support, (Accessory) model);
	result.importFrom (this);
	return result;
    }

    // ========================================
    public boolean search (String text) {
	if (getName ().toLowerCase ().indexOf (text) >= 0 ||
	    getLocalName ().toLowerCase ().indexOf (text) >= 0 ||
	    getId ().indexOf (text) >= 0)
	    return true;
	return false;
    }

    public String getCircuit (Comp realContainer) {
	String result = super.getCircuit ();
	if (result != null)
	    return result;
	return realContainer.getCircuit ();
    }
    public double getWatt (Comp realContainer) {
	double result = super.getWatt ();
	if (result > 0)
	    return result;
	return realContainer.getWatt ();
    }

    // ========================================
    public void validateContainer (Story.Commands commands, String commandName) {
	container.validateContainer (commands, commandName);
	if (container.getLocalEmbedded (getId ()) == this)
	    return;
	Story story = commands.getStory ();
	commands.add (story.new Command (commandName) {
		@SuppressWarnings ("unchecked")
		public void exec () { ((Editable<?, ?, ?, Embedded<?,?,?,?,?>>) container).addEmbedded (Acc.this); }
		@SuppressWarnings ("unchecked")
		public void undo () { ((Editable<?, ?, ?, Embedded<?,?,?,?,?>>) container).removeEmbedded (Acc.this); }
		public void display () { container.updateView (); }
	    });
    }

    public void storyChange (Story.Commands commands, ArrayList<Prop[]> changeProps) {
	storyChange (commands, true, ownProps, changeProps);
    }
    public void storyTransform (Story.Commands commands, Collection<String> modifiers, Unit<?> permanent, String newName, ArrayList<Prop[]> transProps) {
	storyTransform (commands, null, modifiers, permanent, ownProps, transProps);
    }
    public void updateView () {
	((Comp) container).updateView ();
    }

    // ========================================
    public void changeConnectedTo (String connectedTo) {
	getLocalProp (Prop.PropConnectedTo, Prop.PropTypeEnum.Text).setValue (connectedTo);
    }
    public void changeConnectedOn (String connectedOn) {
	getLocalProp (Prop.PropConnectedOn, Prop.PropTypeEnum.Text).setValue (connectedOn);
    }

    // ========================================
    public String toString () {
	return getName ();
    }

    // ========================================
    public void print (Graphics2D printGraphics, Comp comp) {
	Point2D.Double accPos = getPos ();
	DimensionDouble accSize = getSize ();
	ScaledImage accIcon = getIcon ();
	if (comp.isLow ()) {
	    ScaledImage scaledLowImage = getLowIcon ();
	    if (scaledLowImage != null)
		accIcon = scaledLowImage;
	}
	Color accColor = getColor ();
	if (accColor != null)
	    accIcon = comp.getAdecWatt ().getIconDB ().getColoredScaledImages (accIcon, accColor);
	DimensionDouble compSize = comp.getSize ();
	if (accSize.width < 0)
	    accSize.width *= -compSize.width;
	if (accSize.height < 0)
	    accSize.height *= -compSize.height;
	accPos.x = accPos.x < 0 ? (-accPos.x-.5)*(compSize.width-accSize.width) : accPos.x - (compSize.width-accSize.width)/2.;
	accPos.y = accPos.y < 0 ? (-accPos.y-.5)*(compSize.height-accSize.height) : accPos.y - (compSize.height-accSize.height)/2.;
	// XXX double accThetaDegree = acc.getThetaDegree ();
	double thetaDegree = comp.getThetaDegree ();
	AffineTransform at = AffineTransform.getRotateInstance (Math.toRadians ((int) thetaDegree));
	double [] center = new double [] {accPos.x, accPos.y};
	at.transform (center, 0, center, 0, 1);
	Point2D.Double compPos = comp.getPos ();
	Point2D.Double absPos = new Point2D.Double (compPos.getX ()+center[0], compPos.getY ()+center[1]);
	String id = getId ();
	comp.accCenter.put (id, absPos);
	comp.accSize.put (id, accSize);
	Workspace.printImage (printGraphics, accIcon, absPos, accSize, thetaDegree, null);
	Workspace.printText (printGraphics, getLabel (), getLabelColor (), absPos, accSize, thetaDegree);
    }

    // ========================================
    static public final BasicStroke solidConnection = new BasicStroke (2, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
    static public final Color connectionColor = Color.GRAY;
    static public final Color boxColor = new Color (0, 1, 0, .5F);
    static public final Color warningColor = new Color (1, .5F, 0, .7F);
    static public final Color errorColor = new Color (1, 0, 0, .7F);
    static public final Color circuitColor = Color.BLACK;

    static public void printCircuit (Graphics2D connectionGraphics, double printScale, Point2D center, Circuits.CircuitState circuitState) {
	printCircuit (connectionGraphics, center, circuitState, 20/printScale);
    }
    static public void printCircuit (Graphics2D connectionGraphics, Point2D center, Circuits.CircuitState circuitState, double boxSide) {
	Ellipse2D.Double box = new Ellipse2D.Double (center.getX ()-boxSide/2, center.getY ()-boxSide/2, boxSide, boxSide);
	Color color = boxColor;
	switch (circuitState.state) {
	case PLUG:
	    break;
	case LOOP:
	case UNPLUG:
	    color = warningColor;
	    break;
	case SHORTCUT:
	    color = errorColor;
	}
	connectionGraphics.setPaint (color);
	connectionGraphics.fill (box);
	if (circuitState.name == null)
	    return;
	Workspace.printText (connectionGraphics, String.format ("%2s", circuitState.name),
				  circuitColor, center, new DimensionDouble (boxSide, boxSide));
    }

    static public void printConnection (Graphics2D connectionGraphics, double printScale, Point2D begin, Point2D end) {
	printConnection (connectionGraphics, begin, end,
			20/printScale, new BasicStroke ((float)(2/printScale), BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
    }
    static public void printConnection (Graphics2D connectionGraphics, Point2D begin, Point2D end, double boxSide) {
	printConnection (connectionGraphics, begin, end, boxSide, solidConnection);
    }
    static public void printConnection (Graphics2D connectionGraphics, Point2D begin, Point2D end,
				       double boxSide, BasicStroke solidConnection) {
        GeneralPath gp = new GeneralPath (Path2D.WIND_NON_ZERO);
        gp.moveTo (begin.getX (), begin.getY ());
	if (Math.abs (begin.getX ()-end.getX ()-1) < Math.abs (begin.getY ()-end.getY ()))
	    gp.curveTo (begin.getX (), end.getY (), end.getX (), begin.getY (), end.getX (), end.getY ());
	else
	    gp.curveTo (end.getX (), begin.getY (), begin.getX (), end.getY (), end.getX (), end.getY ());
	connectionGraphics.setPaint (connectionColor);
	connectionGraphics.setStroke (solidConnection);
	connectionGraphics.draw (gp);
    }

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