package kiyut.sketsa.modules.symbollibrary.general;

import java.awt.Component;
import java.awt.Point;
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
import kiyut.sketsa.canvas.VectorCanvas;
import kiyut.sketsa.undo.DOMUndoManager;
import kiyut.sketsa.util.ColorConvertion;
import kiyut.sketsa.util.DOMUtilities;
import kiyut.sketsa.util.SVGConstants;
import org.w3c.dom.Element;
import org.w3c.dom.svg.SVGDocument;
import org.w3c.dom.svg.SVGElement;
import org.w3c.dom.svg.SVGPoint;
import org.w3c.dom.svg.SVGPointList;
import org.w3c.dom.svg.SVGPolygonElement;
import org.w3c.dom.svg.SVGSVGElement;
import org.w3c.dom.svg.SVGStylable;

/**
 * Implementation of Polygon Symbol
 * @author Kiyut
 */
public class PolygonSymbol extends GeneralSymbol {
    /** Icon */ 
    protected Icon icon;
    
    /** Tooltip Text */ 
    protected String tooltipText;
    
    protected int numberOfPoints;
    protected double radius;
    
    /** Creates a new instance of PolygonSymbol */
    public PolygonSymbol() {
        icon = new ImageIcon(getClass().getResource("/kiyut/sketsa/modules/symbollibrary/general/polygon32.png"));
        tooltipText = "Polygon N Points";
        numberOfPoints = 6;
        radius = 50;
    }
 
    /** {@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();
        
        double[] coords = new double[4];
        coords[0] = location.getX();
        coords[1] = location.getY();
        
        AffineTransform at = canvas.getTransform(true);
        try {
            at = at.createInverse();
        } catch (NoninvertibleTransformException e) {}
        at.transform(coords,0,coords,0,2);
        
        double cx = (float)coords[0];
        double cy = (float)coords[1];

        List<Point2D> pointList = generatePoint(numberOfPoints, cx, cy, radius);
        
        SVGPolygonElement elt = (SVGPolygonElement)doc.createElementNS(SVGConstants.SVG_NAMESPACE_URI, SVGConstants.SVG_POLYGON_TAG);
        SVGPointList svgPointList = elt.getPoints();
        SVGSVGElement svgElement = doc.getRootElement();
        for (int i=0; i<pointList.size(); i++) {
            Point2D p = pointList.get(i);
            SVGPoint svgPoint = svgElement.createSVGPoint();
            svgPoint.setX((float)p.getX());
            svgPoint.setY((float)p.getY());
            svgPointList.appendItem(svgPoint);
        }
        
        SVGStylable stylable = (SVGStylable)elt;
        String str = ColorConvertion.toHexString(java.awt.Color.BLACK);
        DOMUtilities.updateProperty(stylable, null, SVGConstants.SVG_STROKE_ATTRIBUTE,str);
        DOMUtilities.updateProperty(stylable, null, SVGConstants.SVG_FILL_ATTRIBUTE,SVGConstants.SVG_NONE_VALUE);
        
        return elt;
    }
    
    /** Math stuff for generating polygon
     * @param numberOfPoints Number of Points
     * @param cx center x coordinate
     * @param cy center y coordinate
     * @param radius the radius
     * @return list of Point2D
     */
    protected List<Point2D> generatePoint(int numberOfPoints, double cx, double cy, double radius) {
        int pCount = numberOfPoints * 2;
        double angle = (360/numberOfPoints) * Math.PI / 180;
        
        List<Point2D> pointList = new ArrayList<Point2D>(pCount);
        for (int i=1; i<pCount; i=i+2) {
            double x = cx + (Math.cos((i/2+1) * angle) * radius);
            double y = cy + (Math.sin((i/2+1) * angle) * radius);
            
            Point2D p = new Point2D.Double(x,y);
            pointList.add(p);
        }
        
        return pointList;
    }
    
    /** {@inheritDoc} */
    public void showOptionDialog(Component parentComponent) {
        PolygonSymbolOptionPane option = new PolygonSymbolOptionPane();
        option.setValue(numberOfPoints,radius);
        int choice = JOptionPane.showConfirmDialog(parentComponent,option,getTooltipText(),JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
        if (choice == JOptionPane.OK_OPTION) {
            try {
                option.validateValue();
            } catch (Exception ex) {
                JOptionPane.showMessageDialog(parentComponent,ex.getMessage(),getTooltipText(), JOptionPane.ERROR_MESSAGE);
            }
            numberOfPoints = option.getNumberOfPoints();
            radius = option.getRadius();
        }
    }
}
