import java.io.*;
import java.util.*;
import java.lang.reflect.*;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.color.ColorSpace;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ComponentSampleModel;
import java.awt.image.DataBuffer;
import java.awt.image.ImageObserver;
import java.awt.image.IndexColorModel;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;

import javax.swing.JFrame;

class Picture implements ImageObserver {

  /* Necessary to force a wait for the image to
     actually be loaded before displaying it. */

  boolean imageOK;
  boolean imageLoaded = false;

  public boolean imageUpdate(Image img,
			     int infoflags,
			     int x,
			     int y,
			     int width,
			     int height) {

    
    synchronized(this) {
      // System.err.println("Infoflags = " + Integer.toHexString(infoflags));
      if ((infoflags & ALLBITS) == ALLBITS) {
	notifyAll();
	imageOK = true;
	imageLoaded = true;
	return false;
      } else if ((infoflags & (ERROR|ABORT)) != 0 ){
	notifyAll();
	imageOK = false;
	imageLoaded = true;
	return false;
      } else {
	return true;
      }
    }
  }

  public boolean waitForImage(Image image) {
    try {
      int w, h;
      synchronized(this) {
	w = image.getWidth(this);
	h = image.getHeight(this);
	while (w == -1 || h == -1 || !imageLoaded) {
	  wait();
	  w = image.getWidth(this);
	  h = image.getHeight(this);
	}
      }
      return true;
    } catch ( InterruptedException ex) {
      return false;
    }
  }

  PictureParameters parameters;
  int numberOfPanels=1;
  String originalFileName;
  String baseFileName;
  File baseDir;
  String pageFileName;
  String pageImageName;
  String thumbnailImageName;
  String descriptiveText;
  int thumbW, thumbH;

  public void makePage(Template t) throws IOException {
    PrintStream output = new PrintStream(new BufferedOutputStream(new FileOutputStream(pageFileName)));
    t.prefix(output, 1);
    output.println(pageReference());
    if (descriptiveText != null && descriptiveText.trim().length() > 0) {
      output.println("<p>");
      output.println(descriptiveText);
    }
    t.suffix(output, 1);
    output.close();
  }

  public String imageNameInPage() {
    return baseFileName + ".jpg";
  }

  public String pageReference() {
    return
      "<img src=\""+URLEncoder.encode(imageNameInPage())+"\" border=0>";
  }

  public String thumbnailReference() {
    return
      "<A href=\""+URLEncoder.encode(pageFileName)+
      "\"><img alt=\""+baseFileName+"\" src=\""+
      URLEncoder.encode(thumbnailImageName)+
      "\" width="+thumbW+" height="+thumbH+" border=0></a>";
  }

  void createScaledImage(int width_limit,
			 int height_limit,
			 Image image,
			 String file_name,
			 boolean saveSize) throws Throwable {

    File target = new File(file_name);
    int w, h;

    if (target.exists() && !saveSize) return;

    if (! waitForImage(image)) {
      throw new Exception("Could not read image " + file_name);
    }

    System.err.println("Creating scaled image " + file_name);
    
    w = image.getWidth(this);
    h = image.getHeight(this);

    int tsw, tsh;
    
    if (w <= width_limit && h <= height_limit) {
      tsw = w;
      tsh = h;
    } else if ((double)w/width_limit > (double)h/height_limit) {
      tsw = width_limit;
      tsh = (int) Math.round(h/((double)w/width_limit));
    } else {
      tsw = (int) Math.round(w/((double)h/height_limit));
      tsh = height_limit;
    }

    if (saveSize) {
      thumbW = tsw;
      thumbH = tsh;
      if (target.exists()) return;
    }

    System.err.println("Scaling from " + w + " by " + h + " to " + tsw + " by " + tsh);

    // Get scaled version of image.
    
    imageLoaded = false;
    
    Image thumb = image.getScaledInstance(tsw,
					  tsh,
					  Image.SCALE_AREA_AVERAGING); 
    
    // buffer the image
    // first force the image to be completely computed.
    waitForImage(thumb);
    
    if (! waitForImage(thumb)) {
      throw new Exception("Could not scale image " + file_name);
    }

    BufferedImage bthumb = new BufferedImage(tsw,
					     tsh,
					      BufferedImage.TYPE_INT_RGB);
     
    bthumb.createGraphics().drawImage(thumb, 0, 0, null);
     
    if (saveSize) {
      Generate.putImage(bthumb);
    }
    
    OutputStream output = new BufferedOutputStream(new FileOutputStream(file_name));
    
    com.sun.image.codec.jpeg.JPEGEncodeParam j2dEP;
    com.sun.image.codec.jpeg.JPEGImageEncoder encoder;
    
    j2dEP = com.sun.image.codec.jpeg.JPEGCodec.getDefaultJPEGEncodeParam(bthumb);
    
    encoder = com.sun.image.codec.jpeg.JPEGCodec.createJPEGEncoder(
      output, j2dEP);
    
    try {
      // Write the image data.
      encoder.encode(bthumb);
    } catch(IOException e) {
      throw new RuntimeException(e.getMessage());
    }

    //     JpegEncoder jpg = new JpegEncoder(bthumb, 80, output);
    //  jpg.Compress();
     
     output.close();
     System.err.println("Image written");
  }
  
  void createScaledImages() {
     Image image = null;

     try {
       System.err.println("Reading " + originalFileName);
       imageLoaded = false;
       image = Toolkit.getDefaultToolkit().getImage(originalFileName);
       
       createScaledImage(parameters.thumbWidthLimit,
			 parameters.thumbHeightLimit,
			 image, thumbnailImageName, true);

       createScaledImage( parameters.pageWidthLimit,
			  parameters.pageHeightLimit,
			  image, pageImageName, false);

     } catch (Throwable ex) {
       ex.printStackTrace();
     }
  }

  String pageFileReferenceNoDir() {
    return URLEncoder.encode(baseFileName) + ".html";
  }

  Picture (Pictures p, PictureParameters pp) {
    parameters = pp;
    String s = p.lastLine;
    baseFileName = s.substring(0, s.lastIndexOf('.'));
    baseDir  = p.dir;

    originalFileName  = baseDir + "/" + s;

    pageFileName      = p.pageDir + "/" + baseFileName + ".html";
    pageImageName      = p.pageDir + "/" + baseFileName + ".jpg";
    thumbnailImageName = p.thumbDir + "/" + baseFileName + ".jpg";

    createScaledImages();

    StringBuffer sb = new StringBuffer();
    try {
      p.read();
      while (p.lastLine != null && !p.empty()) {
	sb.append(p.lastLine);
	sb.append('\n');
	p.read();
      } 
    } catch (IOException ex) {
      ex.printStackTrace();
    }

    descriptiveText = sb.toString();
    System.err.println("Picture text is \n" + descriptiveText);
  }
}
