/** ImageManipulatorCanvas Class
   * @version 2.0  18 Dec 2000
   * @author Lawrence Rodrigues
   **/
package com.vistech.jai.render;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import javax.swing.*;
import java.awt.geom.*;
import java.awt.image.renderable.*;
import javax.swing.*;

import javax.media.jai.*;
import com.vistech.imageviewer.*;
import com.vistech.imageviewer.DisplayMode;
import com.vistech.util.*;

/** A component class for displaying and manipulating rendered images.
  * @version 2.0 18 Dec 2001
  * @author Lawrence Rodrigues
  **/
public class ImageManipulatorCanvas extends RenderedImageCanvas
                   implements  ImageManipulator{
   transient protected Image awtImage;
   protected int imageType =0;

   protected Point panOffset = new Point(0,0);

   protected boolean magOn = true;
   protected double magFactor = 1.0;
   protected double magFactorX =1.0, magFactorY=1.0;

   protected int magCenterX = 0;
   protected int magCenterY =0;
   protected double rotationAngle = 0.0;
   protected boolean rotateOn = true;
   protected int rotationCenterX = 0;
   protected int rotationCenterY = 0;

   protected boolean shearOn = true;
   protected double shearFactor = 0.0;
   protected double shearX =0.0, shearY=0.0;

   protected int displayMode = DisplayMode.SCALED;
   protected int flipMode = FlipMode.NORMAL;
   protected int interpMode = Interpolation.INTERP_NEAREST;
   protected double diffFactor =0.0;

   private AffineTransform currentTx = new AffineTransform();
   private boolean highRes = true;

   public PlanarImage getImage() { return origImage; }
   public Dimension getImageSize() {
       return new Dimension(origImage.getWidth(), origImage.getHeight());
   }
   public synchronized void setInterpolationType(int mode){ interpMode = mode;}
   public int getInterpolationType(){ return interpMode;}

   public synchronized void setDisplayMode(int mode){
      if(mode == displayMode) return;
      int oldmode = displayMode;
      firePropertyChange("displayMode",oldmode,mode);
      this.displayMode = mode;
      repaint();
   }
   public int getDisplayMode(){ return displayMode;}

   public synchronized void setFlipMode(int mode){
      if(mode == flipMode) return;
      int oldmode = flipMode;
      firePropertyChange("flipMode",oldmode, mode);
      this.flipMode = mode;
      repaint();
   }
   public int getFlipMode(){ return flipMode;}

   public void setMagFactor(double magFactor){
      firePropertyChange("MagFactor",
                         new Double(this.magFactor),
                         new Double(magFactor));
      diffFactor = this.magFactor - magFactor;
      this.magFactor = magFactor;
   }
   public double getMagFactor(){ return magFactor;}

   public void setMagFactorX(double magFactorX){
      firePropertyChange("MagFactorX",
                          new Double(this.magFactorX),
                          new Double(magFactorX));
      this.magFactorX = magFactorX;
   }
   public double getMagFactorX(){ return magFactorX;}

   public void setMagFactorY(double magFactorY){
      firePropertyChange("MagFactorY",
                          new Double(this.magFactorY),
                          new Double(magFactorY));
      this.magFactorX = magFactorY;
   }
   public double getMagFactorY(){ return magFactorY;}

   public void setShearFactor(double shearFactor){
      firePropertyChange("ShearFactor",
                         new Double(this.shearFactor),
                         new Double(shearFactor));
      this.shearFactor = shearFactor;
   }
   public double getShearFactor(){ return shearFactor;}

   public double getShearFactorX(){ return shearX; }
   public double getShearFactorY(){return shearY;}

   public void setRotationAngle(double rotationAngle){
      firePropertyChange("RotationAngle",
                          new Double(this.rotationAngle),
                          new Double(rotationAngle));
      this.rotationAngle = rotationAngle;
   }

   public double getRotationAngle(){return rotationAngle;}
   
   public void setHighRes(boolean onOrOff){
      highRes = onOrOff;
   }

   public boolean getHighRes(){
      return highRes;
   }
  
   public void paintImage(int magCenterX, int magCenterY, double mag){
      setMagFactor(this.magFactor *mag);
      int dx = this.magCenterX -magCenterX;
      int dy = this.magCenterY-magCenterY;
      this.magCenterX = magCenterX;
      this.magCenterY = magCenterY;
      try {
        Point2D mgp = null;
        mgp = atx.inverseTransform((Point2D)(
              new Point(magCenterX-panX, magCenterY-panY)),(Point2D)mgp);
        double x = (mgp.getX()*mag)-mgp.getX();
        double y = (mgp.getY()*mag)-mgp.getY();
      }catch (Exception e) {//System.out.println(e); 
      }
   }

   protected void applyTransform(RenderedImage ri, AffineTransform atx){
      ParameterBlock pb = new ParameterBlock();
      pb.addSource(ri);
      pb.add(atx);
      pb.add(Interpolation.getInstance(interpMode));
      RenderedOp op = JAI.create("affine", pb);
      createTiledImage(op.createInstance());
      displayImage = op.createInstance();
      repaint();
   }

   public void applyTransform(AffineTransform atx){
      this.atx = atx;
      //2.0 changes 
      if(highRes) {
         applyTransform(origImage,atx);
         currentTx = new AffineTransform();
      }else {
         currentTx = atx;
         displayImage = origImage;
         repaint();
      }
   }

   public void createTiledImage(PlanarImage img){
      displayImage = makeTiledImage(img);
      sampleModel = displayImage.getSampleModel();
      colorModel = displayImage.getColorModel();
      getTileInfo(displayImage);
      fireTilePropertyChange();
      imageDrawn = false;
      repaint();
   }

   public void resetManipulation(){
      panOffset = new Point(0,0);
      magCenterX = 0; magCenterY =0;
      panX =0; panY =0;
      magFactor = 1.0;
      shearX = 0.0; shearY = 0.0;
      rotationAngle = 0.0;
      scrollAnchor = new Point(0,0);
      setRotationAngle(0.0);
      createTiledImage(origImage);
      atx = AffineTransform.getTranslateInstance(0.0,0.0);
      currentTx = new AffineTransform();
      applyTransform(atx);
      repaint();
   }

   public void paintComponent(Graphics gc){
      Graphics2D g = (Graphics2D)gc;
      Rectangle rect = this.getBounds();
      if((width != rect.width) || (height != rect.height)){
         double magx = rect.width/(double)width ;
         double magy = rect.height/(double)height ;
      }
      g.setColor(Color.black);
      g.fillRect(0,0,rect.width, rect.height);
      //2.0 changes
      //if(displayImage != null) g.drawRenderedImage(displayImage, new AffineTransform());
      if(displayImage != null) g.drawRenderedImage(displayImage, currentTx);
      imageDrawn = true;
   }
   //ImageDisplay Methods
   public void setAWTImage(Image image){ awtImage = image;}
   public Image getAWTImage(){ return awtImage;}

   public void setImageType(int imageType){
      this.imageType = imageType;
   }
   public int getImageType(){ return imageType;}
   public void setClip(Shape clip) {}
   public void setBufferedImage(BufferedImage image){}

   public BufferedImage getBufferedImage() {
      return null;
   }
   public void setOffScreenImage(BufferedImage image){}
   public BufferedImage getOffScreenImage() {
      return null;
   }
   public void setDisplayImage(BufferedImage image){}
   public BufferedImage getDisplayedImage() {
      return null;
   }
   public void draw(Shape shape){}

   public void invert(boolean on){}
   public void setInvert(boolean on){}
   public boolean getInvert(){
       return true;
   }
   public boolean paintImage() {return true;}

   //2.0 changes. These  methods were added to speed up scrolling.
   //When scrolling, low res is in effect. 
   public void scroll(int x, int y){
      scrollOn = true;
      super.startScroll(x,y);
      setHighRes(false);
   }

   public void stopScroll(){ 
      if(!scrollOn) return;
      scrollOn = false;
      setHighRes(true);
      applyTransform(atx);
      repaint();
      super.stopScroll();
   }

   public void setImage(PlanarImage img){
      setRotationAngle(0.0);
      currentTx = new AffineTransform();
      //resetManipulation();
      super.setImage(img);
   }

}
