package kiyut.sketsa.modules.symbollibrary.general;

import java.awt.Point;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.PathIterator;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import kiyut.sketsa.canvas.VectorCanvas;
import kiyut.sketsa.undo.DOMUndoManager;
import kiyut.sketsa.util.ColorConvertion;
import kiyut.sketsa.util.DOMUtilities;
import kiyut.sketsa.util.GeomUtilities;
import kiyut.sketsa.util.SVGConstants;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.svg.SVGDocument;
import org.w3c.dom.svg.SVGElement;
import org.w3c.dom.svg.SVGEllipseElement;
import org.w3c.dom.svg.SVGGElement;
import org.w3c.dom.svg.SVGPathElement;
import org.w3c.dom.svg.SVGPathSegClosePath;
import org.w3c.dom.svg.SVGPathSegCurvetoCubicAbs;
import org.w3c.dom.svg.SVGPathSegLinetoAbs;
import org.w3c.dom.svg.SVGPathSegMovetoAbs;
import org.w3c.dom.svg.SVGStylable;

/** 
 * Implementation of YinYang Symbol
 *
 * @author Kiyut
 */
public class YinYangSymbol extends GeneralSymbol {
    
    /** Icon */
    protected Icon icon;
    
    /** Tooltip Text */
    protected String tooltipText;
    
    /**
     * Creates a new instance of YinYangSymbol
     */
    public YinYangSymbol() {
        icon = new ImageIcon(getClass().getResource("/kiyut/sketsa/modules/symbollibrary/general/yinyang32.png"));
        tooltipText = "Yin Yang";
        //strokeColor = null;
        //fillColor = new Color(0,0,255);
    }
    
   /** {@inheritDoc} */
    public Icon getIcon() {
        return icon;
    }
    
    /** {@inheritDoc} */
    public String getTooltipText() {
        return tooltipText;
    }
    
    /** {@inheritDoc} */
    public void insertSymbol(VectorCanvas canvas, Point location) {
        SVGElement elt = createSVGElement(canvas,location);
        SVGDocument doc = canvas.getSVGDocument();
        Element svgRoot = doc.getDocumentElement();
        
        DOMUndoManager undoManager = canvas.getUndoManager();
        undoManager.start("Add " + tooltipText);
        try {
            svgRoot.appendChild(elt);
        } finally {
            undoManager.end();
        }
        
        List<SVGElement> newList = new ArrayList<SVGElement>();
        newList.add(elt);
        
        canvas.getCanvasSelection().setSelectionList(newList);
        canvas.refresh();
    }
    
    /** Create SVGElement
     * @param canvas VectorCanvas
     * @param location The location where the insertion should take place
     * @return SVGElement
     */
    protected SVGElement createSVGElement(VectorCanvas canvas, Point location) {
        SVGDocument doc = canvas.getSVGDocument();
        
        float[] coords = new float[6];
        coords[0] = (float)location.getX();
        coords[1] = (float)location.getY();
        
        AffineTransform at = canvas.getTransform(true);
        try {
            at = at.createInverse();
        } catch (NoninvertibleTransformException e) {}
        at.transform(coords,0,coords,0,2);
        
        float cx = (float)coords[0];
        float cy = (float)coords[1];
        
        float radius = 50;
        
        SVGGElement gElt = (SVGGElement)doc.createElementNS(SVGConstants.SVG_NAMESPACE_URI, SVGConstants.SVG_G_TAG);
        
        List<SVGElement> list = new ArrayList<SVGElement>(3);
                
        ////////////////////
        // elp1 outer black
        
        SVGElement elt1 = (SVGEllipseElement)doc.createElementNS(SVGConstants.SVG_NAMESPACE_URI, SVGConstants.SVG_ELLIPSE_TAG);
        elt1.setAttributeNS(null, SVGConstants.SVG_CX_ATTRIBUTE, Float.toString(cx));
        elt1.setAttributeNS(null, SVGConstants.SVG_CY_ATTRIBUTE, Float.toString(cy));
        elt1.setAttributeNS(null, SVGConstants.SVG_RX_ATTRIBUTE, Float.toString(radius));
        elt1.setAttributeNS(null, SVGConstants.SVG_RY_ATTRIBUTE, Float.toString(radius));
        DOMUtilities.updateProperty((SVGStylable)elt1, null, SVGConstants.SVG_STROKE_ATTRIBUTE,SVGConstants.SVG_NONE_VALUE);
        DOMUtilities.updateProperty((SVGStylable)elt1, null, SVGConstants.SVG_FILL_ATTRIBUTE,ColorConvertion.toHexString(java.awt.Color.BLACK));
        list.add(elt1);
        
        /////////////////////////
        // path white with hole
        
        String pathString = "M 50.0 75.0 C 52.76143 75.0 55.0 77.23859 55.0 80.0 C 55.0 82.76141 " +
        "52.76143 85.0 50.0 85.0 C 47.23857 85.0 45.0 82.76141 45.0 80.0 C 45.0 77.23859 47.23857 " +
        "75.0 50.0 75.0 z M 50.0 0.0 C 65.0 0.0 75.0 10.0 75.0 25.0 C 75.0 40.0 65.0 50.0 50.0 50.0 C " +
        "35.0 50.0 25.0 60.0 25.0 75.0 C 25.0 90.0 35.0 100.0 50.0 100.0 C 120.0 100.0 120.0 0.0 50.0 " +
        "0.0 z";
        Shape shape = GeomUtilities.createShape(pathString);
        /* Set shape the location into Center Mouse Coord */
        Rectangle2D bounds = shape.getBounds2D();
        //double tx = cx - bounds.getCenterX() - (radius/2);
        //double ty = cy - bounds.getCenterY() - (radius/2);
        double tx = cx - bounds.getCenterX() + (radius/2);
        double ty = cy - bounds.getCenterY();
        AffineTransform coordAt = AffineTransform.getTranslateInstance(tx, ty);
        PathIterator pi = shape.getPathIterator(coordAt);
        
        SVGPathElement eltPath = (SVGPathElement)doc.createElementNS(SVGConstants.SVG_NAMESPACE_URI, SVGConstants.SVG_PATH_TAG);
        
        // adding the path seg
        while (!pi.isDone()) {
            int segment = pi.currentSegment(coords);
            if (segment == PathIterator.SEG_MOVETO) {
                SVGPathSegMovetoAbs svgPathSeg = eltPath.createSVGPathSegMovetoAbs(coords[0],coords[1]);
                eltPath.getPathSegList().appendItem(svgPathSeg);
            } else if (segment == PathIterator.SEG_CLOSE) {
                SVGPathSegClosePath svgPathSeg = eltPath.createSVGPathSegClosePath();
                eltPath.getPathSegList().appendItem(svgPathSeg);
            } else if (segment == PathIterator.SEG_LINETO) {
                SVGPathSegLinetoAbs svgPathSeg = eltPath.createSVGPathSegLinetoAbs(coords[0],coords[1]);
                eltPath.getPathSegList().appendItem(svgPathSeg);
            } else if (segment == PathIterator.SEG_CUBICTO) {
                SVGPathSegCurvetoCubicAbs svgPathSeg = eltPath.createSVGPathSegCurvetoCubicAbs(coords[4],coords[5],coords[0],coords[1],coords[2],coords[3]);
                eltPath.getPathSegList().appendItem(svgPathSeg);
            }
            
            pi.next();
        }
        
        DOMUtilities.updateProperty((SVGStylable)eltPath, null, SVGConstants.SVG_STROKE_ATTRIBUTE,ColorConvertion.toHexString(java.awt.Color.BLACK));
        DOMUtilities.updateProperty((SVGStylable)eltPath, null, SVGConstants.SVG_FILL_ATTRIBUTE,ColorConvertion.toHexString(java.awt.Color.WHITE));
        list.add(eltPath);
        
        
        ///////////////////////////
        // elp 2 inner small white
        SVGElement elt2 = (SVGEllipseElement)doc.createElementNS(SVGConstants.SVG_NAMESPACE_URI, SVGConstants.SVG_ELLIPSE_TAG);
        elt2.setAttributeNS(null, SVGConstants.SVG_CX_ATTRIBUTE, Float.toString(cx));
        elt2.setAttributeNS(null, SVGConstants.SVG_CY_ATTRIBUTE, Float.toString(cy - (radius/2)));
        elt2.setAttributeNS(null, SVGConstants.SVG_RX_ATTRIBUTE, Float.toString(radius/10));
        elt2.setAttributeNS(null, SVGConstants.SVG_RY_ATTRIBUTE, Float.toString(radius/10));
        DOMUtilities.updateProperty((SVGStylable)elt2, null, SVGConstants.SVG_STROKE_ATTRIBUTE,SVGConstants.SVG_NONE_VALUE);
        DOMUtilities.updateProperty((SVGStylable)elt2, null, SVGConstants.SVG_FILL_ATTRIBUTE,ColorConvertion.toHexString(java.awt.Color.WHITE));
        list.add(elt2);
        
        for (int i=0; i<list.size(); i++) {
            gElt.appendChild((Node)list.get(i));
        }
        
        return gElt;
    }
}
