// Copyright 1997, 1998,1999 Carmen Delessio (carmen@blackdirt.com)
// Black Dirt Software http://www.blackdirt.com/graphics/svg
// Free for non-commercial use

// revisions:
// May 12,1999 corrected ";" at end of color - Chris Lilley mailing list
// May 16,1999 implemented simple Java 2d infrastructure, Begin Path

import java.io.*;
import java.util.*;
import java.awt.*;
import java.net.*;
import java.applet.Applet;
import java.lang.Math;
import java.lang.String;
import java.awt.image.*;

import java.awt.geom.GeneralPath;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;



// support aframe test for main
import javax.swing.*;
import java.awt.event.*;

// XML basics
import com.ibm.xml.parser.*;
import org.w3c.dom.*;

class svgImage extends Canvas{

      int i;
      int j;
      static int offset =0;

      public short inch;

      private DataInputStream d;
     
      static boolean drawFilled;
      static short oldx;
      static short oldy;
      static short x;
      static short y;
      static short w;
      static short h;
      static int currentColor;
      static Polygon poly;

      static float oldfx;
      static float oldfy;
      static float fx;
      static float fy;
      static float fx1;
      static float fy1;
      static float fx2;
      static float fy2;


      static float fw;
      static float fh;

      static boolean negate;
      static StringTokenizer t;
      static AffineTransform a;


      short svgWidth = 400;
      short svgHeight = 300;

      // Use Java2d Basics
      static  Graphics2D svgGraphics;   
      BufferedImage svgImageBuffer;


      static String tempBuffer;
      static String colorBuffer;




      public int fontStyle;
      public int fontWeight;
      public boolean fontItalic = false;

      public      int penRed =0;
      public      int penGreen =0;
      public      int penBlue =0;

      public      int textRed =0;
      public      int textGreen =0;
      public      int textBlue =0;
      Element root;

  public svgImage(String filename)
  {


       if (filename != null) {
                InputStream is;
                try {
                    is = new FileInputStream(filename);
                } catch (FileNotFoundException notFound) {
                    System.err.println(notFound);
                    return;
                }

                Parser parser = new Parser(filename);
                Document doc = parser.readStream(is);
                root = (Element)doc.getDocumentElement();
                getSvgSize(root);
    }
  }

    public Image getImage(){
        return (svgImageBuffer);
    }
  

    public void addNotify(){
      super.addNotify();
      svgImageBuffer = (BufferedImage)createImage(svgWidth,svgHeight);    
      if (svgImageBuffer == null){
         System.out.println(" image is null");
         return;
      }
      svgGraphics = svgImageBuffer.createGraphics();
      if (svgGraphics == null) System.out.println(" graphics is null");
      renderSVG(root);  // put SVG image into svgImagebuffer
   }




   public void paint (Graphics g){
           g.drawImage(svgImageBuffer, 0, 0, this);
   }

   public void update(Graphics g){
      paint(g);
   }


//   public Dimension setSize(){
//      return new Dimension(svgWidth, svgHeight);
//   }

   public Dimension getPreferredSize(){
      return new Dimension(svgWidth, svgHeight);
   }

   public Dimension getMinimumSize(){
      return new Dimension((int)Math.round(0.25*svgWidth), (int)Math.round(0.25*svgHeight));
   }


   public static void renderSVG(Node node) {
        if (node instanceof TXElement) {
            TXElement el = (TXElement)node;

            if (el.getTagName().equals("text")) {
              tempBuffer = el.getAttribute("x");
              x = (short)new Integer(tempBuffer).intValue();
              tempBuffer = el.getAttribute("y");
              y = (short)new Integer(tempBuffer).intValue();
              Node textNode = node.getFirstChild();
              if (textNode instanceof TXText) {
                svgGraphics.drawString( textNode.getNodeValue(),x,y);
              }
            }
            else if (el.getTagName().equals("rect")) {
              tempBuffer = el.getAttribute("x");
              x = (short)new Integer(tempBuffer).intValue();
              tempBuffer = el.getAttribute("y");
              y = (short)Integer.valueOf(tempBuffer).intValue();
              tempBuffer = el.getAttribute("width");
              w = (short)new Integer(tempBuffer).intValue();
              tempBuffer = el.getAttribute("height");
              h = (short)new Integer(tempBuffer).intValue();
              if (drawFilled){
                svgGraphics.fillRect(x,y,w,h);
              }
              else{
                svgGraphics.drawRect(x,y,w,h);
              }
            }
            else if (el.getTagName().equals("g")) {
              tempBuffer = el.getAttribute("style");
              offset = tempBuffer.indexOf("stroke:");
              if (offset >=0){
                 tempBuffer = tempBuffer.substring(offset+7);
                 tempBuffer = tempBuffer.trim();
                 if (tempBuffer.startsWith("#")) {
                   tempBuffer = tempBuffer.substring(1);
                 }
                 // Chris Lilley fix 5/11/99

                int semi_colon_index = tempBuffer.indexOf(';');
                if (semi_colon_index > 0) {
                  tempBuffer = tempBuffer.substring(0,semi_colon_index);
                }

                 // put default colors here
                 currentColor = Integer.valueOf(tempBuffer,16).intValue();
                 svgGraphics.setColor( new Color (currentColor));
                 drawFilled = false;
              }
              offset = tempBuffer.indexOf("fill:");
              if (offset >=0){
                 tempBuffer = tempBuffer.substring(offset+5);
//                 System.out.println("Fill    : " + tempBuffer);
                 tempBuffer = tempBuffer.trim();
                 if (tempBuffer.startsWith("#")) {
                   tempBuffer = tempBuffer.substring(1);
                   int semi_colon_index = tempBuffer.indexOf(';');
                   if (semi_colon_index > 0) {
                     tempBuffer = tempBuffer.substring(0,semi_colon_index);
                   }
                   currentColor = Integer.valueOf(tempBuffer,16).intValue();
                 }
                 if (tempBuffer.startsWith("none")) {
                   currentColor = 0; // what does none mean?
                 }
                 drawFilled = true;
                 svgGraphics.setColor( new Color (currentColor));

              }
              offset = tempBuffer.indexOf("transform:");
              if (offset >=0){
                 tempBuffer = tempBuffer.substring(offset+10);
                 tempBuffer = tempBuffer.trim();
//                 System.out.println ("Tranform " + tempBuffer);
                 // tempBuffer is matrix(1 0 0 -1 -174.67 414)
                 offset = tempBuffer.indexOf("matrix(");
                 if (offset >=0){
                   tempBuffer = tempBuffer.substring(offset+7);
//                   System.out.println ("Tranform " + tempBuffer);
                   StringTokenizer t = new StringTokenizer(tempBuffer," ,)");

                   tempBuffer = t.nextToken();
                   fx = (float)new Float(tempBuffer).floatValue();
                   tempBuffer = t.nextToken();
                   fy = (float)new Float(tempBuffer).floatValue();
                   tempBuffer = t.nextToken();
                   fx1 = (float)new Float(tempBuffer).floatValue();
                   tempBuffer = t.nextToken();
                   fy1 = (float)new Float(tempBuffer).floatValue();
                   tempBuffer = t.nextToken();
                   fx2 = (float)new Float(tempBuffer).floatValue();
                   tempBuffer = t.nextToken();
                   fy2 = (float)new Float(tempBuffer).floatValue();

                  a = new AffineTransform(fx, fy, fx1, fy1,fx2,fy2);

                 }




//                 <g id="Calque_1" style="transform:matrix(1 0 0 -1 -174.67 414);">

              }

            }
            else if (el.getTagName().equals("ellipse")) {
              tempBuffer = el.getAttribute("major");
              short major = (short)new Integer(tempBuffer).intValue();
              tempBuffer = el.getAttribute("minor");
              short minor = (short)new Integer(tempBuffer).intValue();
              tempBuffer = el.getAttribute("angle");
              short angle = (short)new Integer(tempBuffer).intValue();
              tempBuffer = el.getAttribute("cx");
              x = (short)new Integer(tempBuffer).intValue();
              tempBuffer = el.getAttribute("cy");
              y = (short)new Integer(tempBuffer).intValue();

              if (angle == 90){
                h = major;
                w =minor;
              } else{
                w = major;
                h =minor;
              }
              y = (short)(y - Math.round(0.5 * h));
              x = (short)(x - Math.round(0.5 * w));

              if (drawFilled){
                 svgGraphics.fillOval (x,y,w,h);
              }
              else{
                 svgGraphics.drawOval (x,y,w,h);
              }
            }
            else if (el.getTagName().equals("polyline")) {
              poly = new Polygon();
              tempBuffer = el.getAttribute("verts");
              StringTokenizer t = new StringTokenizer(tempBuffer," ,");
              while(t.hasMoreElements()){
                tempBuffer = t.nextToken();
                x = (short)new Integer(tempBuffer).intValue();
                tempBuffer = t.nextToken();
                y = (short)new Integer(tempBuffer).intValue();
                poly.addPoint( x , y );
              }

              if (drawFilled){
                 svgGraphics.fillPolygon (poly);
              }
              else{
              svgGraphics.drawPolyline( poly.xpoints, poly.ypoints, poly.npoints);
              }
            }
            else if (el.getTagName().equals("path")) {
              tempBuffer = el.getAttribute("style");
              offset = tempBuffer.indexOf("stroke:");
              if (offset >=0){
                 tempBuffer = tempBuffer.substring(offset+7);
                 tempBuffer = tempBuffer.trim();
                 if (tempBuffer.startsWith("#")) {
                   tempBuffer = tempBuffer.substring(1);
                 }
                 // Chris Lilley fix 5/11/99
                int semi_colon_index = tempBuffer.indexOf(';');
                if (semi_colon_index > 0) {
                  tempBuffer = tempBuffer.substring(0,semi_colon_index);
                }

                 // put default colors here
                 currentColor = Integer.valueOf(tempBuffer,16).intValue();
                 svgGraphics.setColor( new Color (currentColor));
                 drawFilled = false;
              }
              offset = tempBuffer.indexOf("fill:");
              if (offset >=0){
                 tempBuffer = tempBuffer.substring(offset+5);
//                 System.out.println("Fill    : " + tempBuffer);
                 tempBuffer = tempBuffer.trim();
                 if (tempBuffer.startsWith("#")) {
                   tempBuffer = tempBuffer.substring(1);
                   int semi_colon_index = tempBuffer.indexOf(';');
                   if (semi_colon_index > 0) {
                     tempBuffer = tempBuffer.substring(0,semi_colon_index);
                   }
                   currentColor = Integer.valueOf(tempBuffer,16).intValue();
                 }
                 if (tempBuffer.startsWith("none")) {
                   currentColor = 0; // what does none mean?
                 }
                 drawFilled = true;
                 svgGraphics.setColor( new Color (currentColor));

              }




/*
              if (offset >=0){
                 tempBuffer = tempBuffer.substring(offset+5);
                 tempBuffer = tempBuffer.trim();
                 if (tempBuffer.startsWith("#")) {
                   tempBuffer = tempBuffer.substring(1);
                 }
                int semi_colon_index = tempBuffer.indexOf(';');
                if (semi_colon_index > 0) {
                  tempBuffer = tempBuffer.substring(0,semi_colon_index);
                }
                 currentColor = Integer.valueOf(tempBuffer,16).intValue();
                 svgGraphics.setColor( new Color (currentColor));
                 drawFilled = true;
              }
 */


              tempBuffer = el.getAttribute("d");
//              System.out.println(tempBuffer);
              GeneralPath p = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
              /*
        GeneralPath p = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
        p.moveTo(- width / 2.0f, - height / 8.0f);
        p.lineTo(+ width / 2.0f, - height / 8.0f);
        p.lineTo(- width / 4.0f, + height / 2.0f);
        p.lineTo(+         0.0f, - height / 2.0f);
        p.lineTo(+ width / 4.0f, + height / 2.0f);
        p.closePath();
              */


              t = new StringTokenizer(tempBuffer," ,MmLlCczArSsHhVvDdEeFfGgJjQqTtz-",true);
              while(t.hasMoreElements()){
                tempBuffer = t.nextToken();
//                System.out.println(tempBuffer);
//                System.out.println(tempBuffer.charAt(0));
                negate=false;
                switch (tempBuffer.charAt(0)){
                  case 'M': //Move To
                           fx = getPathFloat();
                           fy = getPathFloat();
//                           System.out.println("fx " + fx + " fy "+ fy);
                           oldfx=fx;
                           oldfy=fy;
                           p.moveTo(fx, fy);
                           break;
                  case 'm':
                           fx = getPathFloat();
                           fy = getPathFloat();
                           fx+=oldfx;
                           fy+=oldfy;
                           oldfx=fx;
                           oldfy=fy;
                           p.moveTo(fx, fy);
                           break;

                  case 'L': // Line to
                           fx = getPathFloat();
                           fy = getPathFloat();
//                           System.out.println("fx " + fx + " fy "+ fy);
                           oldfx=fx;
                           oldfy=fy;
                           p.lineTo(fx, fy);
                           break;
                  case 'l':
                           fx = getPathFloat();
//                           System.out.println ("fx is " + fx);
                           fy = getPathFloat();
//                           System.out.println ("fy is " + fy);
                           fx+=oldfx;
                           fy+=oldfy;
                           oldfx=fx;
                           oldfy=fy;
                           p.lineTo(fx, fy);
                           break;
                  case 'C':

                           fx = getPathFloat();
                           fy = getPathFloat();
                           fx1 = getPathFloat();
                           fy1 = getPathFloat();
                           fx2 = getPathFloat();
                           fy2 = getPathFloat();
                           p.curveTo(fx,fy,fx1,fy1,fx2,fy2);
                           oldfx= fx2;
                           oldfy= fy2;


/*

            curveTo(float x1, float y1, float x2, float y2, float x3, float y3) 
                      Adds a curved segment, defined by three new points, to the path by drawing a Bézier curve that
            intersects both the current coordinates and the coordinates (x3, y3), using the specified points (x1, y1) and
            (x2, y2) as Bézier control points.
*/

                           break;
                  case 'c':

                           fx = getPathFloat();
                           fy = getPathFloat();
                           fx1 = getPathFloat();
                           fy1 = getPathFloat();
                           fx2 = getPathFloat();
                           fy2 = getPathFloat();
                           fx+=oldfx;
                           fy+=oldfy;
                           fx1+=oldfx;
                           fy1=oldfy;
                           fx2+=oldfx;
                           fy2+=oldfy;
                           p.curveTo(fx,fy,fx1,fy1,fx2,fy2);
                           oldfx= fx2;
                           oldfy= fy2;

                           break;

                  case 'z':
//                           System.out.println("closepath");
                           break;

                  case 'A':
                           System.out.println("Absolute");
                           break;
                  case 'r':
                           System.out.println("relative");
                           break;

                  case 'S':
                           System.out.println("Smooth curve");
                           break;

                  case 's':
                           System.out.println("relative smooth curve");
                           break;


                  case 'H':
                           fy = getPathFloat();
                           oldfy=fy;
                           p.lineTo(oldfx, fy);


                           break;

                  case 'h':
                           fy = getPathFloat();
                           fy+=oldfy;
                           oldfy=fy;
                           p.lineTo(oldfx, fy);

                           break;

                  case 'V':
                           fx = getPathFloat();
                           oldfx=fx;
                           p.lineTo(fx, oldfy);

                           break;

                  case 'v':
                           fx = getPathFloat();
                           fx+=oldfx;
                           oldfx=fx;
                           p.lineTo(fx, oldfy);

                           break;

                  case 'D':
                           System.out.println("arc 1 - see spec");
                           break;

                  case 'd':
                           System.out.println("relative arc 1");
                           break;
                  case 'E':
                           System.out.println("arc 2 - with line");
                           break;

                  case 'e':
                           System.out.println("relative arc 2");
                           break;
                  case 'F':
                           System.out.println("arc 3");
                           break;

                  case 'f':
                           System.out.println("relative arc 3");
                           break;
                  case 'G':
                           System.out.println("arc 4");
                           break;

                  case 'g':
                           System.out.println("relative arc 4");
                           break;


                  case 'J':
                           System.out.println("elliptical quadrant");
                           break;

                  case 'j':
                           System.out.println("relative elliptical quadrant");
                           break;
                  case 'Q':
                           fx = getPathFloat();
                           fy = getPathFloat();
                           fx1 = getPathFloat();
                           fy1 = getPathFloat();
                           p.quadTo(fx,fy,fx1,fy1);
                           oldfx= fx2;
                           oldfy= fy2;


/*

            quadTo(float x1, float y1, float x2, float y2) 
                      Adds a curved segment, defined by two new points, to the path by drawing a Quadratic curve that
            intersects both the current coordinates and the coordinates (x2, y2), using the specified point (x1, y1) as a
            quadratic parametric control point.

*/

                           break;

                  case 'q':
                           System.out.println("relative quadratic bezier curve to");
                           break;
                  case 'T':
                           System.out.println("True Type quadratic bezier curve ");
                           break;

                  case 't':
                           System.out.println("relative True Type quadratic bezier curve");
                           break;

                  case '-':
                           System.out.println("Negative value");
                           break;

                }


              }
              // render the path here
              BasicStroke bs = new BasicStroke( 1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 10.0f);
              svgGraphics.setStroke(bs);

              if (drawFilled){
                svgGraphics.fill(p);
              }
              svgGraphics.draw(p);




            } // end if path
        }
        if (node.hasChildNodes()) {
            NodeList nl = node.getChildNodes();
            int size = nl.getLength();
            for (int i = 0; i < size; i++) {
                renderSVG(nl.item(i));
            }
        }
    }

    public static float getPathFloat() {
       float pathFloat;
       tempBuffer = t.nextToken();
       while (tempBuffer.equals(",")|| tempBuffer.equals(" ")){
        tempBuffer = t.nextToken();
       }
       if (tempBuffer.equals("-")){
         pathFloat =(float) -1.0 * new Float(t.nextToken()).floatValue();
       }
       else{
            pathFloat = (float)new Float(tempBuffer).floatValue();
       }
       return(pathFloat);
    }




    public void getSvgSize(Node node) {
    int pixelsPerInch =0;


        if (node instanceof TXElement) {
            TXElement el = (TXElement)node;
            if (el.getTagName().equals("svg")) {
              String tempWidth = el.getAttribute("width");
              String tempHeight = el.getAttribute("height");

              offset = tempWidth.indexOf("px");
              if (offset >=0){
                 tempWidth = tempWidth.substring(0, offset  );


                 svgWidth = (short)new Integer(tempWidth).intValue();
              } else{
                   offset = tempWidth.indexOf("inch");
                   if (offset >=0){
                     tempWidth = tempWidth.substring(0, offset );
                     svgWidth = (short)new Integer(tempWidth).intValue();
                     pixelsPerInch =Toolkit.getDefaultToolkit().getScreenResolution(); 
                     svgWidth *= pixelsPerInch;
                   }
              }

              offset = tempHeight.indexOf("px");
              if (offset >=0){
                   tempHeight = tempHeight.substring(0,offset  );

                   svgHeight = (short)new Integer(tempHeight).intValue();
              } else{
                  offset = tempHeight.indexOf("inch");
                  if (offset >=0){
                     tempHeight = tempHeight.substring(0,offset);

                     svgHeight = (short)new Integer(tempHeight).intValue();
                     pixelsPerInch =Toolkit.getDefaultToolkit().getScreenResolution(); 
                     svgHeight *= pixelsPerInch;
                  }
              }


              // set the width and height for component;
              // set size set = true;

              return;
            }  // if it is svg
        }
        if (node.hasChildNodes()) {
            NodeList nl = node.getChildNodes();
            int size = nl.getLength();
            for (int i = 0; i < size; i++) {
                getSvgSize(nl.item(i));
            }
        }
    }




    public static void main (String args[]) {

        String filename = null;
        if (args.length > 0) {
            filename = args[0];
            svgImage svgTest = new svgImage(filename);
           JFrame frame;
           frame = new JFrame("test SVG");
           frame.addWindowListener(new WindowAdapter() {
              public void windowClosing(WindowEvent e) {System.exit(0);}
            });
           frame.getContentPane().add("Center", svgTest);
           frame.pack();
           frame.setVisible(true);
         }
         else{
             System.out.println ("Useage: java svgImage <source file>");       
         }
    } 

} //end parsesvg




