package adecWatt.model;

import java.awt.BasicStroke;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.Collection;
import misc.DimensionDouble;
import adecWatt.model.unit.NonWorkspace;
import adecWatt.model.unit.Workspace;
import adecWatt.model.xml.XmlSegm;

public class Segm extends Item<XmlSegm, Permanent.SegmTypeEnum, Permanent.SegmAttrEnum> {
    // ========================================
    public Collection<String>	getModifiersSet ()			{ return SegmModifiersSet; }
    public SegmTypeEnum		getTypeToken ()				{ return SegmTypeEnum.Segment; }
    public SegmAttrEnum		getNameToken ()				{ return SegmAttrEnum.Name; }
    public SegmAttrEnum		getModifierToken ()			{ return SegmAttrEnum.Modifier; }
    public SegmAttrEnum		getPlaceIdToken ()			{ return SegmAttrEnum.Placeid; }
    public SegmAttrEnum		getModelToken ()			{ return SegmAttrEnum.Model; }
    public Workspace		getStoryUnit ()				{ return container; }

    public Segm	getLink (Editable<?, ?, ?, ?> workspace)	{ return new Segm (name, placeId, (Workspace) workspace, model); }

    // ========================================
    public Segm (Workspace workspace, XmlSegm xmlSegm) {
	super (workspace, xmlSegm);
	// XXX collectEmbedded ();
    }
    public Segm (String name, String placeName, Workspace workspace, NonWorkspace model) {
	super (name, placeName, workspace, model);
    }
    public Segm (Workspace workspace, NonWorkspace model) {
	super (null, null, workspace, model);
    }
    public Segm clone (Workspace workspace) {
	Segm result = new Segm (workspace, model);
	result.importFrom (this);
	return result;
    }

    // ========================================
    public DimensionDouble getSize () {
	return new DimensionDouble (getLength (), Math.max (getWidth (), getLabelSize ()));
    }
    public double getThetaDegree () {
	return getAngle ();
    }
    public void changeThetaDegree (double thetaDegree) {
	if (isSticky ())
	    return;
	getLocalProp (Prop.PropAngle, Prop.PropTypeEnum.Number).setAngle (thetaDegree);
    }
    public void changeSize (DimensionDouble size) {
	if (isSticky ())
	    return;
	getLocalProp (Prop.PropLength, Prop.PropTypeEnum.Number).setLength (size.width);
    }

    // ========================================
    public void print (Graphics2D printGraphics, Workspace workspace, String plugId) {
	print (printGraphics, workspace, getPos (), new DimensionDouble (getLength (), getWidth ()), getAngle ());
    }

    public void print (Graphics2D printGraphics, Workspace workspace, Point2D pos, DimensionDouble size, double thetaDegree) {
	double length = size.width;
	float width = (float) getWidth (); // size.height; // XXX force
	Paint color = getColor ();
	Workspace.printLine (printGraphics, color, createStroke (getStyle (), width), pos, length, thetaDegree,
			     createArrowStroke (width), createEnd (getBegin (), width), createEnd (getEnd (), width));
	Workspace.printText (printGraphics, getLabel (), getLabelColor (), pos, getSize (), thetaDegree);
   }

    // ========================================
    static public float []
	plain = null,
	dot = {1f, 1f},
	dash = {3f, 3f},
	dashdot = {3f, 4f, 1f, 4f},
	dashdotdot = {3f, 4f, 1f, 1f, 1f, 4f};
    static public float [] createScaleStyle (float [] tab, double width) {
	if (tab == null || width == 1)
	    return tab;
	float [] result = new float [tab.length];
	for (int i = 0; i < tab.length; i++)
	    result[i] = (float) (tab [i]*width);
	return result;
    }
    static public float [] createStyleStroke (String style, double width) {
	try {
	    switch (style) {
	    case "dot" : return createScaleStyle (dot, width);
	    case "dash" : return createScaleStyle (dash, width);
	    case "dashdot" : return createScaleStyle (dashdot, width);
	    case "dashdotdot" : return createScaleStyle (dashdotdot, width);
	    }
	} catch (Exception e) {
	}
	return null;
    }
    static public Stroke createStroke (String style, float width) {
	return new BasicStroke (width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 1f, createStyleStroke (style, width), 0);
    }
    static public Shape createEnd (String style, float width) {
 	try {
	    switch (style) {
	    case "arrow" : return createArrow (width);
	    case "dot" : return createDot (width);
	    case "square" : return createSquare (width);
	    case "stop" : return createStop (width);
	    }
	} catch (Exception e) {
	}
	return null;
    }
    static public Stroke createArrowStroke (float width) {
	return new BasicStroke (width, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER);
    }
    static public Shape createArrow (double width) {
        double barb = 4*width;
        double angle = Math.toRadians (20);
        Path2D.Double path = new Path2D.Double ();

        double x = -barb*Math.cos (angle);
        double y = barb*Math.sin (angle);
        path.moveTo (0, 0);
        path.lineTo (x, y);
        path.lineTo (-3*width, 0);
        x = -barb*Math.cos (-angle);
        y = barb*Math.sin (-angle);
        path.lineTo (x, y);
	path.closePath();
        return path;
    }
    static public Shape createStop (double width) {
        double barb = 3*width;
        Path2D.Double path = new Path2D.Double ();
        path.moveTo (0, barb);
        path.lineTo (0, -barb);
        return path;
    }

    static public Shape createDot (double width) {
        double barb = 2*width;
        return new Ellipse2D.Double (-width, -width, barb, barb);
    }

    static public Shape createSquare (double width) {
        double barb = 2*width;
        return new Rectangle2D.Double (-width, -width, barb, barb);
    }

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