package examples.rtf2fo;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;

import javax.imageio.ImageIO;
import javax.imageio.stream.ImageOutputStream;

import de.vc.jfo.Document;
import de.vc.jfo.flow.ExternalGraphic;
import de.vc.jfo.renderer.OutputFormat;
import de.vc.jfo.renderer.Renderer;
import de.vc.jfo.renderer.RendererFactory;
import de.vc.jfo.rtf.FieldListener;
import de.vc.jfo.rtf.RTFImporter;
import de.vc.jfo.rtf.listeners.SimpleDataSource;
import de.vc.util.Measure;

/**
 * Example for inserting a dynamic images. All images are hold in memory, none
 * is serialized to disc.
 */

public class DynamicImages {

  private final static String PATH = "";

  private final static String RTF_FILE  = PATH+"docs-in/rtf2fo/dynamic_images.rtf";
  private final static String FO_FILE  = PATH+"docs-out/rtf2fo/dynamic_images.fo";
  private final static String PDF_FILE  = PATH+"docs-out/rtf2fo/dynamic_images.pdf";

  private final static String PNG_IMAGE_TYPE = "image/png";


  public static void main(String[] args) throws Exception{

    RTFImporter importer = new RTFImporter();

    importer.addFieldListener(createFieldListener());

    // Create document from RTF and write XSL-FO file
    Document doc = importer.importDocument( RTF_FILE );
    doc.writeTo( new File(FO_FILE) );

    // And now render document to PDF
    OutputFormat format = OutputFormat.PDF;
    Renderer r = RendererFactory.instance().getRenderer( format );
    if (r==null)
      // If FOP is not available we cannot render... :-(
      System.err.println("No renderer found for "+format+". Is FOP in classpath?");
    else
      // Render the FO-document into a PDF-file
      doc.render( r, format, new File(PDF_FILE) );

  }


  /**
   * Creates a field listener for our image fields.
   * @return FieldListener
   */
  private static FieldListener createFieldListener(){
  	SimpleDataSource p = new SimpleDataSource();
    p.setValue("image 1", createRandomGraphic());
    p.setValue("image 2", createRandomGraphic());
    return p;
  }

  /**
   * Creates a dynamic graphic.
   * @return ExternalGraphic
   */
  private static ExternalGraphic createRandomGraphic(){
    final int imageWidth = 300;
    final int imageHeight = 300;

    // We use a simple buffered image
    BufferedImage image =new BufferedImage(imageWidth,imageHeight,BufferedImage.TYPE_INT_RGB);
    Graphics g = image.getGraphics();
    g.setColor(new Color(230,240,255));
    g.fillRect(0,0,imageWidth,imageHeight);
    g.setColor(Color.BLACK);
    g.drawRect(0,0,imageWidth-1,imageHeight-1);

    // draw some lines into image
    for (int i=0;i<300;i++){
      g.setColor(new Color((float)Math.random(),(float)Math.random(),(float)Math.random()));
      g.drawLine(
      (int)(Math.random()*(imageWidth-2)+1),
      (int)(Math.random()*198+1),
      (int)(Math.random()*(imageHeight-2)+1),
      (int)(Math.random()*(imageHeight-2)+1)
      );
    }

    // encode image into PNG using javax.imageio
    byte[] png = createPNG(image);

    // and now create an XSL-FO external graphic
    ExternalGraphic foGraphic = new ExternalGraphic();

    // set image data using the data-scheme of URL
    // the image url looks like: url(data:image/png;base64,[image data])
    foGraphic.setSourceAsBase64Data( png , PNG_IMAGE_TYPE);

    // set size of image to 6cm x 6cm
    foGraphic.setSize(new Measure("6cm"),new Measure("6cm"));

    return foGraphic;
  }


  /**
   * Creates a PNG from a buffered image using javax.imageio
   * @param image BufferedImage
   * @return byte[]
   */
  private static byte[] createPNG(BufferedImage image){
    Iterator writers = ImageIO.getImageWritersByMIMEType(PNG_IMAGE_TYPE);
    if (!writers.hasNext())
      throw new RuntimeException("Format "+PNG_IMAGE_TYPE+" not supported.");
    javax.imageio.ImageWriter writer = (javax.imageio.ImageWriter) writers.next();
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    try {
      ImageOutputStream imageOut = ImageIO.createImageOutputStream(baos);
      writer.setOutput(imageOut);
      writer.write(image);
      imageOut.close();
    }
    catch (IOException ex) {
      ex.printStackTrace();
    }
    return baos.toByteArray();
  }

}
