/*
 * @(#) ROIManagerJAI.java 1.0 99/10/4
 * Copyright (c) 1999 Larry Rodrigues
 */
package com.vistech.jai.roi;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.awt.geom.*;
import java.awt.image.renderable.*;
import java.io.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.*;
import com.vistech.roi.*;
import com.vistech.util.*;
import com.vistech.jai.render.*;
import javax.media.jai.*;
import com.vistech.imageviewer.*;
import com.vistech.jai.imageio.*;

/** Creates a number of ROI-related objects required by the ROIAnalyzer application,
  * and facilitates communication between them through events.
  *
  * @version 1.0  4 Oct 2000
  * @author Lawrence Rodrigues
  */
public class ROIManagerJAI implements ShapeEventListener, ActionListener, ChangeListener{
   protected int imageWidth, imageHeight;
   protected int viewerWidth, viewerHeight;
   protected CompositeCanvasJAI sourceCanvas, destCanvas;
   protected ROIContextJAI roiContext;
   protected ROIStatsPanel roiPan;
   protected ROIShape shapeROI;
   protected int roiCount = 0;
   protected boolean roiOn = false;
   protected ShapeMarker roiMarker;
   protected ThresholdAdjPanel threshAdjuster;
   protected ROI backgroundROI[]=null, baseroi=null, roiCollection;
   protected ImageSaverPanel saver;
   protected PanZoom destPanZoom, sourcePanZoom;
   protected int currentThreshold = 255;

   public ROIManagerJAI(int wid, int ht){
      viewerWidth = wid;
      viewerHeight = ht;
   }

   public void setROIContext(ROIContextJAI roic){
      if(roiPan != null) {
         roiPan.reset();
         roiPan.setROIContext(roic);
      }
      roiContext = roic;
      SwingUtilities.invokeLater(new ImagePaint(roiContext.getOriginalImage()));
      setSliderValues(null);
   }

   public boolean isImageDrawn(){ return  sourceCanvas.isImageDrawn();}

   public JPanel createUI() {
      JPanel roiPanel = new JPanel();
      int width = viewerWidth/2;
      int height = viewerHeight/2;

      sourceCanvas = new CompositeCanvasJAI();
      roiMarker = new ShapeMarker(sourceCanvas);
      roiMarker.addShapeEventListener(this);
      roiMarker.setRoiOn(false);

      destCanvas = new CompositeCanvasJAI();
      destCanvas.addMouseListener(
         new MouseAdapter() {
            public void mouseReleased(MouseEvent e){
               if(currentThreshold != 255) thresholdROI(currentThreshold);
            }
         }

      );
      destPanZoom = new PanZoom((ImageManipulator)destCanvas);
      sourcePanZoom = new PanZoom((ImageManipulator)sourceCanvas);
      sourcePanZoom.setPanZoomOn(false);

      destPanZoom.setPanZoomOn(true);
      JScrollPane dsp = new JScrollPane(destCanvas);
      dsp.setBorder(BorderFactory.createTitledBorder("Destination Canvas"));
      JPanel viewerpan = new JPanel();
      viewerpan.setSize(2*width, height);
      viewerpan.setLayout(new GridLayout(1,2));
      JScrollPane ssp = new JScrollPane(sourceCanvas);
      ssp.setBorder(BorderFactory.createTitledBorder("Source Canvas"));
      viewerpan.add(ssp);
      viewerpan.add(dsp);

      roiPan = new ROIStatsPanel();
      roiPan.setWidHt(new Dimension(2*width, height));
      roiPanel.setLayout(new GridLayout(2,1));
      roiPanel.add(viewerpan);
      roiPanel.add(roiPan);
      sourceCanvas.repaint();
      saver = new ImageSaverPanel();
      setRoiOn(true);
      return roiPanel;
   }

   public void setSourceCanvas(CompositeCanvasJAI sc){ sourceCanvas = sc; }
   public CompositeCanvasJAI getSourceCanvas(){ return sourceCanvas;}
   public ImageSaverPanel getImageSaver(){ return saver;}

   public JPanel createROIPanel() {
      ROIPanel roiPanel = new ROIPanel(this);
      threshAdjuster = (ThresholdAdjPanel)(roiPanel.getThresholdAdjuster());
      threshAdjuster.addChangeListener(this);
      threshAdjuster.addActionListener(this);
      return roiPanel;
   }

   public void setRoiOn(boolean onOrOff){
      roiOn = onOrOff;
      if(roiMarker != null)roiMarker.setRoiOn(roiOn);
      if(sourcePanZoom != null) sourcePanZoom.setPanZoomOn(!onOrOff);
      if(sourceCanvas != null) sourceCanvas.setDrawOn(onOrOff);
   }

   public void setShapeType(int mode){ roiMarker.setShapeType(mode);}

   public void shapeDrawn(ShapeEvent e){
      Shape shape = e.getShape();
      updateROI(shape);
   }

   public void updateROI(Shape shape) {
      if(shape == null) return;
      drawROINum(shape);
      destCanvas.setDrawOn(false);
      if((roiPan == null)||(shape == null)) return;
      Point pan = sourceCanvas.getPanOffset();
      int panX = pan.x;
      int panY = pan.y;

      AffineTransform at =   new AffineTransform();
      at.translate(panX, panY);
      at.concatenate(sourceCanvas.getTransform());

      Shape txShape = AffineTransformUtil.inverseTransform(shape,at );
      if(txShape == null) return;
      TiledImage tl = roiContext.getDisplayImage();
      Rectangle bounds = txShape.getBounds();
      TiledImage tl1 = tl.getSubImage(bounds.x, bounds.y, bounds.width, bounds.height);
      if(tl1 == null) return;
      backgroundROI = JAIROIUtil.createROIFromImage(tl);
      //AffineTransform atx = new AffineTransform(destCanvas.getTransform());
      //Shape destShape =  atx.createTransformedShape(txShape);
      shapeROI = new ROIShape(txShape);
      roiContext.setCurrentROI(shapeROI);
      roiContext.addROI(shapeROI);

      roiPan.addROI(shapeROI);
      TiledImage destImage = (TiledImage)roiContext.getDisplayImage();
      Graphics2D tg = destImage.createGraphics();
      tg.setColor(Color.white);
      tg.draw(txShape);
      destCanvas.paintImage(destImage);
      setSliderValues(shapeROI);
      destCanvas.repaint();
  }

   public void depositCurrentROI() {
      if(shapeROI != null)  roiContext.depositROI(shapeROI);
      saver.setDisplayImage(roiContext.getDisplayImage());
      saver.setImage(roiContext.getOriginalImage());
   }

   public void stateChanged(ChangeEvent e){
      int threshValue = ((JSlider)(e.getSource())).getValue();
      currentThreshold = threshValue;
      thresholdROI(threshValue);
   }

   public void actionPerformed(ActionEvent e){
      String str = ((JTextField)e.getSource()).getText();
      int threshValue = (Integer.valueOf(str)).intValue();
      currentThreshold = threshValue;
      thresholdROI(threshValue);
   }

   protected  void thresholdROI(int thresh){
      ROI[] roiT =  JAIROIUtil.createThresholdROI(backgroundROI, shapeROI, thresh);
      if(roiT == null) return;
      Rectangle bounds = shapeROI.getBounds();
      TiledImage origimage = JAIROIUtil.createTiledImage(roiContext.getDisplayImage());
      TiledImage image = origimage.getSubImage(bounds.x, bounds.y,
                                               bounds.width, bounds.height);
      TiledImage thImage = JAIROIUtil.createThresholdImage(image, roiT, shapeROI);
      origimage.set(thImage, shapeROI);
      //paintImage()retain the manipulation parameters.
      destCanvas.paintImage(origimage);
      destCanvas.repaint();
   }

   private void drawROINum(Shape shape){
      Graphics2D g = sourceCanvas.getDisplayedImageGC();
      if(shape == null) return;
      Rectangle bounds = shape.getBounds();
      int x = bounds.x;
      int y = bounds.y;
      int wid = bounds.width;
      int ht = bounds.height;
      g.drawString((new Integer(roiCount)).toString(), x+wid/2,y+ht+15);
      roiCount++;
   }

    protected void setSliderValues(ROI roi){
      PlanarImage image = roiContext.getOriginalImage();
      double[][] minmax = ROIStats.getMinMax(image, roi);
      double min = minmax[0][0];
      double max = minmax[1][0];
      for(int j=0; j<minmax[0].length;j++){
          if(min > minmax[0][j]) min =  minmax[0][j];
          if(max <  minmax[1][j]) max = minmax[1][j];
      }
      threshAdjuster.setSliderValues((int)min, (int)max, (int)(max-min)/2);
      thresholdROI((int)((max-min)/2));
   }

   public void eraseShapes() {
      roiMarker.eraseShapes();
      roiCount = 0;
      if(sourceCanvas != null) sourceCanvas.reset();
      if(roiContext != null) roiContext.reset();
      if(destCanvas != null) {
        destCanvas.reset();
        destCanvas.setImage(roiContext.getOriginalImage());
      }
      shapeROI = null;
      backgroundROI = null;
      baseroi = null;
  }

   public void reset(){
      roiCount = 0;
      currentThreshold = 255;
      shapeROI = null;
      backgroundROI = null;
      if(sourceCanvas != null) sourceCanvas.reset();
      if(roiContext != null) roiContext.reset();
      if(destCanvas != null)  {
        destCanvas.reset();
        destCanvas.setImage(roiContext.getOriginalImage());
      }
      if(roiPan != null) roiPan.reset();
   }

   public Dimension getViewerSize(){ return new Dimension(viewerWidth, viewerHeight);}

   private Dimension getViewerSize(double imageAspectRatio){
      Dimension d= Toolkit.getDefaultToolkit().getScreenSize();
      int maxWidth = (int)(d.width *4/5.0);
      int maxHeight = (int)(d.height*4/5.0);
      double screenAspectRatio = maxWidth/(double)maxHeight;
      int viewerWidth,viewerHeight;
      if(imageAspectRatio  > screenAspectRatio){
         viewerWidth =   maxWidth;
         viewerHeight = (int)( maxHeight* screenAspectRatio/imageAspectRatio);
      }else{
         viewerHeight =   maxHeight;
         viewerWidth = (int)(maxWidth* imageAspectRatio/screenAspectRatio);
      }
      return new Dimension(viewerWidth, viewerHeight);
   }

   class ImagePaint implements Runnable {
      PlanarImage image;
      boolean firstTime = true;
      public ImagePaint(PlanarImage image){this.image = image;}
      public void run() {
         if(firstTime) {
            try {
             firstTime = false;
             sourceCanvas.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
             sourceCanvas.setImage(image);
             destCanvas.setImage(roiContext.getOriginalImage());
             SwingUtilities.invokeLater(this);
            } catch(Exception e){SwingUtilities.invokeLater(this);}
         }
         else {
            if(!sourceCanvas.isImageDrawn()) SwingUtilities.invokeLater(this);
            else{sourceCanvas.setCursor(Cursor.getDefaultCursor());}
         }
      }
   }
 }
