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.util.ArrayList;
import java.util.List;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
import kiyut.sketsa.api.symbollibrary.Symbol;
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.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.SVGTransform;
import org.w3c.dom.svg.SVGTransformList;
import org.w3c.dom.svg.SVGTransformable;


/**
 * Implementation of Atom Symbol
 * @author Kiyut
 */
public class AtomSymbol extends GeneralSymbol {
    /** Icon */
    protected Icon icon;
    
    /** Tooltip Text */
    protected String tooltipText;
    
    protected double radius;
    
    /** Creates a new instance of AtomSymbol */
    public AtomSymbol() {
        icon = new ImageIcon(getClass().getResource("/kiyut/sketsa/modules/symbollibrary/general/atom32.png"));
        tooltipText = "Atom";
        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];
        
        double rx = radius/5;
        double ry = radius;
        
        SVGGElement elt = (SVGGElement)doc.createElementNS(SVGConstants.SVG_NAMESPACE_URI, SVGConstants.SVG_G_TAG);
        
        List<SVGEllipseElement> list = new ArrayList<SVGEllipseElement>(4);
        for (int i=0; i<4; i++) {
            SVGEllipseElement ellipseElt = (SVGEllipseElement)doc.createElementNS(SVGConstants.SVG_NAMESPACE_URI, SVGConstants.SVG_ELLIPSE_TAG);
            ellipseElt.setAttributeNS(null, SVGConstants.SVG_CX_ATTRIBUTE, Float.toString((float)cx));
            ellipseElt.setAttributeNS(null, SVGConstants.SVG_CY_ATTRIBUTE, Float.toString((float)cy));
            ellipseElt.setAttributeNS(null, SVGConstants.SVG_RX_ATTRIBUTE, Float.toString((float)rx));
            ellipseElt.setAttributeNS(null, SVGConstants.SVG_RY_ATTRIBUTE, Float.toString((float)ry));
            DOMUtilities.updateProperty(ellipseElt, null, SVGConstants.SVG_STROKE_ATTRIBUTE,ColorConvertion.toHexString(java.awt.Color.BLACK));
            DOMUtilities.updateProperty(ellipseElt, null, SVGConstants.SVG_FILL_ATTRIBUTE,SVGConstants.SVG_NONE_VALUE);
            list.add(ellipseElt);
        }
        
        SVGEllipseElement ellipseElt;
        
        ellipseElt = list.get(1);
        rotateSVGElement(doc,ellipseElt,45,cx,cy);
        
        ellipseElt = list.get(2);
        rotateSVGElement(doc,ellipseElt,90,cx,cy);
        
        ellipseElt = list.get(3);
        rotateSVGElement(doc,ellipseElt,315,cx,cy);
        
        for (int i=0; i<list.size(); i++) {
            elt.appendChild((Node)list.get(i));
        }
        
        return elt;
    }
    
    private void rotateSVGElement(SVGDocument doc, SVGElement elt, double degree, double cx, double cy) {
        SVGTransform transform = doc.getRootElement().createSVGTransform();
        transform.setRotate((float)degree, (float)cx, (float)cy);
        
        SVGTransformList transformList = ((SVGTransformable)elt).getTransform().getBaseVal();
        transformList.appendItem(transform);
        transformList.consolidate();
        
    }
    
    /** {@inheritDoc} */
    public void showOptionDialog(Component parentComponent) {
        AtomSymbolOptionPane option = new AtomSymbolOptionPane();
        option.setValue(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);
            }
            radius = option.getRadius();
        }
    }
}
