// Copyright 1997, 1998 Carmen Delessio (carmen@blackdirt.com)
// Black Dirt Software http://www.blackdirt.com/graphics
// Free for non-commercial use

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.*;

class wmfImage extends Canvas{


      private byte[] bytebuffer;
      private int i;
      private int j;
      private int bytes_read;

      private int rdSize;
      private int windowLong;
      private short windowInt;

      public short inch;

      private static MetaRecord mRecord;
      private java.util.Vector MetaRecordVector;
      private java.util.Enumeration MetaRecordInfo;
      private DataInputStream d;

      private int recordIndex;
      private int handleIndex;
      public WMFHandleTable ht;
      private int[] ncount;
      
      byte[] byteData;                // Unpacked data: one byte per pixel
      byte[] rawData;                 // the raw unpacked data
      int[] intData;                  // Unpacked data: one int per pixel

      public WMFToolkit cvtTool = new WMFToolkit();
      private boolean drawFilled;
      private short oldx;
      private short oldy;
      private String javaGraphic = new String("");
      private String javaDeclare = new String("");
      private String javaInit = new String("");
      private String javaClass = new String("");

      private short numRectangles;
      private short numPolygons;
      private short numOvals;
      private short numLines;
      
      public short WMFWidth;
      public short WMFHeight;

      private short htmlWidth = 800;
      private short htmlHeight = 600;


      public short logExtX;
      public short logExtY;

      public short logOrgX = 0;
      public short logOrgY = 0;


      public short devExtX;
      public short devExtY;


      public int AppletWidth;
      public int AppletHeight;

      public  float d_x;
      public  float d_y;
      public  Graphics wmfGraphics;              
      public  Image wmfImageBuffer;                  

      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;


  public wmfImage(InputStream is, int w, int h) throws IOException
  {

        this.AppletWidth = w;
        this.AppletHeight = h;
        this.devExtX = (short) w;
        devExtY = (short) h;
        mRecord = new MetaRecord( windowLong, windowInt, null);
        d = new DataInputStream(is);
        parseit();
        System.out.println("after parseit");
  }


    public Image getImage(){
        return (wmfImageBuffer);
    }
  
/*
    public void resize(int width, int height){
      Dimension d = size();
      System.out.println(" Dimension resize"+ d.width + " " + d.height);
      wmfImageBuffer = createImage(width,height);
      if (wmfImageBuffer == null){
         System.out.println(" image is null");
         return;
      }
      wmfGraphics = wmfImageBuffer.getGraphics();
      System.out.println(" Get Graphics ");
      if (wmfGraphics == null) System.out.println(" graphics is null");
      try{
           WMFPlay( width, height);
           System.out.println(" resize"+ width + " " + height);
      }catch(IOException e){ System.err.println(e);}
      AppletWidth = width;
      AppletHeight = height;
      repaint();
      super.resize(width,height);
      System.out.println(" Resize ");
    }
*/
    public void addNotify(){
      super.addNotify();
      wmfImageBuffer = createImage(AppletWidth,AppletHeight);
      if (wmfImageBuffer == null){
         System.out.println(" image is null");
         return;
      }
      wmfGraphics = wmfImageBuffer.getGraphics();
      if (wmfGraphics == null) System.out.println(" graphics is null");
      try{
           WMFPlay( AppletWidth, AppletHeight);
//           System.out.println(" resize"+ width + " " + height);
      }catch(IOException e){ System.err.println(e);}



   }

   public void paint (Graphics g){
           g.drawImage(wmfImageBuffer, 0, 0, this);
   }

   public void update(Graphics g){
      paint(g);
   }

   public Dimension preferredSize(){
      return new Dimension(AppletWidth, AppletHeight);
   }

   public Dimension minimumSize(){
      return new Dimension((int)Math.round(0.25*AppletWidth), (int)Math.round(0.25*AppletHeight));
   }


  public synchronized void  parseit()throws IOException {

       byte[] f_long =new byte[4];
       byte[] f_int = new byte[2];
       byte[] parmBuffer;
       short x;
       short y;
       short x2;
       short y2;
       short count = 0;
       MetaRecord locMetaRecord;

//begin metafile header

        windowLong = readLong(d); //key  4 bytes
        if (windowLong == -1698247209){
           windowInt = readInt(d); // unused
           x2 = readInt(d);
           y2 = readInt(d);
           x = readInt(d);
           y = readInt(d);
           WMFWidth = (short) Math.abs(x2-x);
           WMFHeight = (short) Math.abs(y2-y);

           x = cvtTool.twip2pixel(x);  // add inch stuff here
           y = cvtTool.twip2pixel(y);

           d_x = (float) AppletWidth/WMFWidth;
           d_y =  (float)AppletHeight/WMFHeight;

           windowInt = readInt(d); // inch
           inch = windowInt;

           x = (short)(inch/cvtTool.getScreenResolution());
           if (x < 1){
             x =1;
           }
           WMFWidth = (short)(WMFWidth /x);
           WMFHeight = (short)(WMFHeight/x);


           htmlWidth = WMFWidth;
           htmlHeight = WMFHeight;

           devExtX = htmlWidth;
           devExtY = htmlHeight;


           windowLong = readLong(d); // reserved
           windowInt = readInt(d);// checksum

           //metaheader

           for ( i = 0; i < 3; i++){
            windowInt = readInt(d);
           }
           windowLong = readLong(d);
           windowInt = readInt(d);
           windowLong = readLong(d);
           windowInt = readInt(d);
        }
        else {
        // not placeable- no metafile header
        // already read long to check for key

        windowInt = readInt(d);

        windowLong = readLong(d);
        windowInt = readInt(d);
        windowLong = readLong(d);
        windowInt = readInt(d);


        }


        MetaRecordVector = new java.util.Vector();
        while(true){
           count++;
           try{
                 d.readFully(f_long);
              }
           catch(EOFException e){ System.out.println("**** eof");break;}

           if (bytes_read == -1)break;
           windowLong = flipLong(f_long);

           windowInt = readInt(d);

           if (windowInt == 0){
           break;}

           if (windowLong >= 3){
             windowLong = (windowLong*2) -6;
           }

           parmBuffer = null;
           parmBuffer = new byte[windowLong];
           d.readFully(parmBuffer);
           MetaRecordVector.addElement( new MetaRecord( windowLong, windowInt, parmBuffer));

        }
  }



  public  void WMFPlay( int w, int h) throws IOException{
      AppletWidth = w;
      AppletHeight = h;
      devExtX = (short) w;
      devExtY = (short) h;

      ht = new WMFHandleTable();
      drawFilled = false;
      MetaRecordInfo = MetaRecordVector.elements();
      handleIndex = 0;
      recordIndex = 0;




      while(MetaRecordInfo.hasMoreElements()){
           mRecord = (MetaRecord) MetaRecordInfo.nextElement();
           WMFlistRecord(mRecord, false, true, wmfGraphics);

           recordIndex++;
      }
   }



   public synchronized  void WMFlistRecord(MetaRecord mRecord , boolean fromSelect, boolean play, Graphics g){
     short x;
     short y;
     short x2;
     short y2;
     short numChars;
     short wOptions;
     int selColor;
     short w; 
     short h; 
     short lbhatch;
     short lbstyle;
     short numPoints;
     DataInputStream parmStream;
     ByteArrayInputStream  parmIn;
     String polyName;
     String shapeName;
     String tempBuffer;
     String currentFont = "Dialog";
     byte[] textBuffer;
     float fontHeight = 10;
     short fontHeightShort = 10;
     Polygon drawPoly = new Polygon();
     Polygon poly = new Polygon();

     Image BMPimage = null;



     String this_one;


      if (g == null) System.out.println(" graphics is null");

      parmIn = new ByteArrayInputStream(mRecord.getParm());
      parmStream = new DataInputStream(parmIn);
 

     switch(mRecord.getFunction()){



            case 0x2fa: // create pen indirect
                 if (!fromSelect){
                   ht.addObject(recordIndex,mRecord );
                 } else {
                    lbstyle = readInt(parmStream); //if 5 outline is off
                    x = readInt(parmStream);
                    y = readInt(parmStream);
                    selColor = readLong(parmStream);
                    cvtTool.setColors(selColor);
                    penRed = cvtTool.getRed();
                    penGreen =cvtTool.getGreen();
                    penBlue =cvtTool.getBlue();
                    g.setColor( new Color (penRed , penGreen, penBlue));
                 }
                 break;

            case 0x6ff: // create region
                 if (!fromSelect){
                   ht.addObject(recordIndex ,mRecord );
                 }
                 break;


            case 0x2fb: //createFontIndirect
                 if (!fromSelect){  // if not selecting it, just add it to table
                   ht.addObject(recordIndex,mRecord );
                  } else{
                   fontHeightShort = readInt(parmStream);
                   fontHeight = fontHeightShort;
                   fontHeightShort = (short)fontHeight;
                   if (fontHeightShort < 0) {
                     fontHeightShort *= -1;
                     fontHeightShort = mapY(fontHeightShort);
                   }
                   else{
                     fontHeight = (fontHeight/inch);
                     fontHeight = (fontHeight*72);
                     fontHeightShort = (short)fontHeight;
                     if (fontHeightShort < 5){
                        fontHeightShort = 9;
                     }
                   }
                   x2 = readInt(parmStream); // width
                   y2 = readInt(parmStream); //esc
                   y2 = readInt(parmStream); // orientation
                   y2 = readInt(parmStream); //weight
                   fontWeight = y2;
                   textBuffer = new byte[1];
                   try{
                     parmStream.read(textBuffer);
                   }
                   catch(IOException e){ System.err.println(e);}
                     
                   x = (short)textBuffer[0]; // italic
                   fontItalic = false;
                   if (x < 0){
                      fontItalic = true;
                   }


                   textBuffer = new byte[7];
                   try{
                     parmStream.read(textBuffer);
                   }
                   catch(IOException e){ System.err.println(e);}
                   tempBuffer = new String(textBuffer,0); 


                   textBuffer = new byte[32];  // name of font
                   try{
                     parmStream.read(textBuffer);
                   }
                   catch(IOException e){ System.err.println(e);}
                   tempBuffer = new String(textBuffer,0); 

                   currentFont = "Dialog";
                   if (tempBuffer.startsWith("Courier")){
                     currentFont = "Courier";
                   }
                   else if (tempBuffer.startsWith("MS Sans Serif")) {
                     currentFont = "Dialog";
                   }
                   else if (tempBuffer.startsWith("Arial")) {
                     currentFont = "Helvetica";
                   }
                   else if (tempBuffer.startsWith("Arial Narrow")) {
                     currentFont = "Helvetica";
                   }
                   else if (tempBuffer.startsWith("Arial Black")) {
                     currentFont = "Helvetica";
                     fontWeight = 700;
                   }
                   else if (tempBuffer.startsWith("Times New Roman")) {
                     currentFont = "TimesRoman";
                   }
                   else if (tempBuffer.startsWith("Wingdings")) {
                     currentFont = "ZapfDingbats";
                   }
                   if (fontItalic) {
                       fontStyle = Font.ITALIC;
                       if (fontWeight >= 700){ // bold + italic
                         fontStyle = 3;
                       }
                   }
                   else{
                      fontStyle = Font.PLAIN;  // plain
                       if (fontWeight >= 700){ // bold
                         fontStyle = Font.BOLD;
                       }
                   } 
                   g.setFont(new Font (currentFont, fontStyle, fontHeightShort));
                  }
                  break;
            case 0x2fc: //createBrushIndirect

                 if (!fromSelect){  // if not seleceting it, just add it to table
                   ht.addObject(recordIndex,mRecord );  
                  }
                  else{  // selected - use it
                    lbstyle = readInt(parmStream);
                    selColor = readLong(parmStream);
                    lbhatch = readInt(parmStream);
                    if (lbstyle > 0 ){
                       drawFilled = false;
                    }
                    else{
                       drawFilled = true; //filled
                    }
                    cvtTool.setColors(selColor);
                    if (play){
                        g.setColor( new Color( cvtTool.getRed(), cvtTool.getGreen(),cvtTool.getBlue() ));
                    }
                    else {
                         javaGraphic = javaGraphic + "    g.setColor( new Color( " + cvtTool.getRed() + "," + cvtTool.getGreen()+ "," + cvtTool.getBlue() +"));" +"\n";
                    }
                 }
                 break;

            case 0x12d: //select object
                 windowInt = readInt(parmStream);
                 mRecord = ht.selectObject(windowInt);
                 WMFlistRecord(mRecord, true, play, g);
                 break;

            case 0x1f0:
                 windowInt = readInt(parmStream);
                 ht.deleteObject(windowInt);
                 break;

            case 0x41b: //rectangle
                 numRectangles++;
                 shapeName = "rectangle" + numRectangles;
                 y2 = readInt(parmStream);
                 x2 = readInt(parmStream);
                 y = readInt(parmStream);
                 x = readInt(parmStream);
                 x = mapX(x);
                 x2 = mapX(x2);
                 y = mapY(y);
                 y2 = mapY(y2);
                 w = (short) Math.abs(x2-x);
                 h = (short) Math.abs(y2-y);

                 tempBuffer = "" + "( " + x + ", " + y + ", " + w + ", " + h + ");//  rectangle" ;
                   if (drawFilled){
                      g.fillRect(x,y,w,h);
                   }
                   else{
                      g.drawRect(x,y,w,h);
                   }


                 break;

            case 0x418: //Oval
                 numOvals++;
                 shapeName = "Oval" + numOvals;
                 y2 = readInt(parmStream);
                 x2 = readInt(parmStream);
                 y = readInt(parmStream);
                 x = readInt(parmStream);

                 x = mapX(x);
                 x2 = mapX(x2);
                 y = mapY(y);
                 y2 = mapY(y2);



                 w = (short) Math.abs(x2-x);
                 h = (short) Math.abs(y2-y);

                 tempBuffer = "" + "( " + x + ", " + y + ", " + w + ", " + h + ");//  rectangle" ;
                 if (drawFilled){
                    g.fillOval (x,y,w,h);
                 }
                 else{
                    g.drawOval (x,y,w,h);

                 }

                 break;



            case 0x325: //polyline
                 poly = new Polygon();
                 numPoints = readInt(parmStream);

                 for (i = 0; i < numPoints; i++){
                    x = readInt(parmStream);
                    y = readInt(parmStream);
                    x = mapX(x);
                    y = mapY(y);
                    poly.addPoint( x , y );
                 }
                 g.drawPolygon( poly);
                 break;


            case 0x324: //polygon
                 poly = new Polygon();
                 numPoints = readInt(parmStream);

                 oldx = readInt(parmStream);
                 oldy = readInt(parmStream);

                 oldx = mapX(oldx);
                 oldy = mapY(oldy);


                 poly.addPoint( oldx ,oldy );
                 for (i = 0; i < numPoints-1; i++){
                    x = readInt(parmStream);
                    y = readInt(parmStream);
                    x = mapX(x);
                    y = mapY(y);
                    poly.addPoint( x,y);
                 }
                 poly.addPoint(oldx , oldy );

                 if (drawFilled){
                     g.fillPolygon( poly);
                 }
                 else{
                     g.drawPolygon( poly);
                 }



            case 0x538: //polypolygon
                 int numPolys = readInt(parmStream);

                 ncount = new int[numPolys];
                 for (j = 0; j < numPolys ; j++){

                  ncount[j] = readInt(parmStream);

                 }
                

                 for (j = 0; j < numPolys ; j++){
                   poly = new Polygon();


                   numPoints = (short) ncount[j];


                   oldx = readInt(parmStream);
                   oldy = readInt(parmStream);

                   oldx = mapX(oldx);
                   oldy = mapY(oldy);

                   poly.addPoint( oldx ,oldy );
     
                   for (i = 0; i < numPoints-1; i++){
                      x = readInt(parmStream);
                      y = readInt(parmStream);
                      x = mapX(x);
                      y = mapY(y);
                      poly.addPoint( x ,y );

                   }
                   poly.addPoint( oldx ,oldy );

                   if (drawFilled){
                       g.fillPolygon( poly);
                   }
                   else{
                       g.drawPolygon( poly);
                   }
                 }

                 break;




            case 0x214: //moveto
                 oldy = readInt(parmStream);
                 oldx = readInt(parmStream);
                 oldx = mapX(oldx);
                 oldy = mapY(oldy);

                 break;

   
            case 0x213: //lineto
                 numLines++;
                 shapeName = "line" + numLines;
                 javaDeclare = javaDeclare + "    Polygon " + shapeName + "= new Polygon();" +"\n";
                 y = readInt(parmStream);
                 x = readInt(parmStream);
                 x = mapX(x);
                 y = mapY(y);


                 g.drawLine(oldx, oldy, x,y);

                 break;

            case 0x209://set text color
                       // save text color
                       // when writing text, switch to text colors
                       // when done writing, switch back

                    selColor = readLong(parmStream);
                    cvtTool.setColors(selColor);
                    textRed = cvtTool.getRed();
                    textGreen =cvtTool.getGreen();
                    textBlue =cvtTool.getBlue();

                    g.setColor( new Color (textRed , textGreen, textBlue));
                    break;
 

            case 0x201://set BK color
                    g.setColor( new Color(penRed , penGreen, penBlue));
                    break;


            case 0xa32: // exttext...
                    g.setColor( new Color (textRed , textGreen, textBlue));

                    y = readInt(parmStream);
                    x = readInt(parmStream);
  
                    x = mapX(x);
                    y = mapY(y);
                    numChars = readInt(parmStream);
                    wOptions = readInt(parmStream);
                    textBuffer = new byte[numChars];
                    try{
                     parmStream.read(textBuffer);
                    }
                    catch(IOException e){ System.err.println(e);}
                    tempBuffer = new String(textBuffer,0); 
                    g.drawString( tempBuffer , x, y );
                    g.setColor( new Color(penRed , penGreen, penBlue));
                    break;

  

            case 0x521: // TEXTOUT
                   g.setColor( new Color(textRed , textGreen, textBlue));
                   numChars = readInt(parmStream);
                    textBuffer = new byte[numChars+1];
                    try{
                     parmStream.read(textBuffer);
                    }
                    catch(IOException e){ System.err.println(e);}

                    tempBuffer = new String(textBuffer,0);

                    y = readInt(parmStream);
                    x = readInt(parmStream);

                    x = mapX(x);
                    y = mapY(y);
                    g.drawString( tempBuffer , x, y );
                    g.setColor( new Color(penRed , penGreen, penBlue));
 
            break;

            case 0xF43: //stretch DIB
                    Image image;
                    bmpImage bmp = null;
                    tempBuffer = new String(mRecord.getParm(),0);
                    tempBuffer= tempBuffer.substring(22);
                    bmp = new bmpImage(tempBuffer, 1);
                    System.out.println(" instantiated");
                    image = bmp.getImage();
                    g.drawImage(image, 0, 0, this);
                    break;



            case 0x20B: //set_window_org
                    logOrgY = readInt(parmStream);
                    logOrgX = readInt(parmStream);
                    break;


            case 0x20C: //set_window_ext
                    logExtY = readInt(parmStream);
                    logExtX = readInt(parmStream);
                    break;
            default:
                 javaGraphic = javaGraphic + "// unrecognized function " + mRecord.getFunction() + "\n";
          } // end switch

          try{
                       parmStream.close();
                    }
          catch(IOException e){ System.err.println(e);}




   }







   public short mapX(short x){
       d_x = (float)devExtX/logExtX;
       x = (short)(x - logOrgX);
       x = (short) (x*d_x);
       return (x);
   }
   public short mapY(short y){
       d_y = (float)devExtY/logExtY;
       y = (short)(y - logOrgY);
       y = (short) (y*d_y);
       return (y);
   }


   public int flipLong( byte[] byteFlip){
         DataInputStream dl;
         ByteArrayInputStream  b_in;
         byte[] bytebuffer;
         bytebuffer = new byte[4];
         bytebuffer[0] = byteFlip[3];
         bytebuffer[1] = byteFlip[2];  
         bytebuffer[2] = byteFlip[1];  
         bytebuffer[3] = byteFlip[0];  

         b_in = new ByteArrayInputStream(bytebuffer);
         dl = new DataInputStream(b_in);
         try{
           return dl.readInt();
         }
          catch(IOException e){System.err.println(e);}
            return 0;

  }


   public int readLong( DataInputStream d){
       byte[] longBuf =new byte[4];

        try{
            d.read(longBuf);
//            d.readFully(longBuf);
            return flipLong(longBuf);
         }  catch(IOException e){
            System.err.println(e);
            return 99;
         }

   }

   public short readInt( DataInputStream d){
        byte[] intBuf =new byte[2];

        try{
            d.read(intBuf);
//            d.readFully(intBuf);
            return flipInt(intBuf);
         }  catch(IOException e){
            System.err.println(e);
            return 99;
         }

   }



   public short flipInt( byte[] byteFlip){
         DataInputStream d;
         ByteArrayOutputStream b_out;
         ByteArrayInputStream  b_in;
         byte[] bytebuffer;

         bytebuffer = new byte[2];
         bytebuffer[0] = byteFlip[1];
         bytebuffer[1] = byteFlip[0];  

         b_in = new ByteArrayInputStream(bytebuffer);
         d = new DataInputStream(b_in);
         try{
           return d.readShort();
         }
         catch(IOException e){ System.err.println(e);}
            return 0;

  }



} //end parsewmf


    class MetaRecord extends Object {
    
    private   int         rdSize;
    private   short       rdFunction;
    private   byte[]      rdParm;


    
    public MetaRecord(int rdSize, short rdFunction, byte[] rdParm) {
        this.rdSize = rdSize;
        this.rdFunction = rdFunction;
        this.rdParm = rdParm; // arraycopy
        //rdParm = new byte[4];
    }
    
    public void initialize(int rdSize, short rdFunction, byte[] rdParm) {
        this.rdSize = rdSize;
        this.rdFunction = rdFunction;
        this.rdParm = rdParm; // arraycopy
        //rdParm = new byte[4];
    }

    public int getSize() {
        return rdSize;
    }
   
    public short getFunction() {
        return rdFunction;
    }

    public byte[] getParm() {
        return rdParm;
    }

}
