/** RenderGrid Class
   * @version 1.0  18 apr 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.*;

/** Creates a panel that draws a grid to represent the tile structure of the
  * displyed image and a movable rectangle to represent the viewport.
  * The poistion of the this rectangle reflects the relative position of the image with respect to
  * the displayed image.
  * The RenderGrid and the RenderedImageCanvas objects communicate through events.
  * 
  * @version 1.0 18 Apr 2000
  * @author Lawrence Rodrigues
  **/
public class RenderGrid extends JPanel {
   protected int maxTileIndexX, maxTileIndexY;
   protected int tileWidth, tileHeight;
   protected Point vpPos = new Point(0,0);
   protected Rectangle currentShape;
   protected int panX =0, panY =0;
   protected int width, height;
   protected boolean dragOn = false;
   private Point scrollAnchor  = new Point(0,0);
   protected AffineTransform atx = new AffineTransform();
   protected Dimension vpSize;

   public RenderGrid() {
      enableEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK |
                          AWTEvent.MOUSE_EVENT_MASK);
   }

   public Dimension getViewportDimension(){
      return new Dimension(width, height);
   }

   public void setTileIndices(int maxXIndex, int maxYIndex){
      this.maxTileIndexX = maxXIndex;
      this.maxTileIndexY = maxYIndex;
      repaint();
   }

   public void setTileDimension(int width, int height){
      tileWidth = width; tileHeight = height;
      repaint();
   }

   public void setTileWidth(int tw){
      tileWidth = tw; repaint();
   }
   public int getTileWidth(){ return tileWidth;}

   public void setTileHeight(int th){
      tileHeight = th; repaint();
   }
   public int getTileHeight(){ return tileHeight;}
   public void setMaxTileIndexX(int tix){
      maxTileIndexX = tix; repaint();
   }

   public int getMaxTileIndexX(){return maxTileIndexX;}

   public void setMaxTileIndexY(int tiy){
      maxTileIndexY = tiy; repaint();
   }
   public int getMaxTileIndexY(){return maxTileIndexY;}
   public void setTransform(AffineTransform at) {atx = at;}
   public void setViewportSize(Dimension size){vpSize = size;}

   public void  processMouseEvent(MouseEvent e){
      switch(e.getID()){
          case MouseEvent.MOUSE_PRESSED:
             setCursor(new Cursor(Cursor.MOVE_CURSOR));
             int x = e.getX();
             int y = e.getY();
             if(currentShape.contains(x,y)) {  dragOn = true;}
             break;
          case MouseEvent.MOUSE_CLICKED:
             break;
          case MouseEvent.MOUSE_RELEASED:
             setCursor(Cursor.getDefaultCursor());
             dragOn = false;
             break;
      }
   }

   public void processMouseMotionEvent(MouseEvent e){
       switch(e.getID()){
          case MouseEvent.MOUSE_DRAGGED:
             if(dragOn) scroll(e.getX(), e.getY());
             break;
      }
   }

   public void stopScroll(){ setCursor(Cursor.getDefaultCursor());}

   public void startScroll(int x, int y){
      if(dragOn) return;
      scrollAnchor.x = x- panX;
      scrollAnchor.y = y- panY;
      repaint();
   }

   public void scroll(int x, int y){
      panX = x-scrollAnchor.x;
      panY = y-scrollAnchor.y;
      setPan(new Point(panX, panY));
      repaint();
   }

   public void setPan(Point pos){
      firePropertyChange("viewportPosition",this.vpPos, pos);
      int x = (int)( pos.x * (maxTileIndexX*tileWidth)/(width-20));
      int y = (int)( pos.y * (maxTileIndexY*tileHeight)/(height-20));
      this.vpPos = new Point(x,y);
      repaint();
   }

   public void setViewportPosition(Point vpPos){
      this.vpPos = vpPos; repaint();
   }

   public void paintComponent(Graphics gc) {
      Graphics2D g = (Graphics2D)gc;
      Rectangle bounds = this.getBounds();
      g.setColor(Color.black);
      width = bounds.width-20;
      height = bounds.height-20;
      double gridWidth =  (width)/(double)maxTileIndexX;
      double gridHeight = (height)/(double)maxTileIndexY;
      g.fillRect(0,0,bounds.width, bounds.height);
      if ((maxTileIndexX == 0)|| (maxTileIndexY == 0))  return;
      g.setColor(Color.blue);
      double vertStartX = 10.0; double vertStartY = 10.0;
      double vertEndX = 10.0;
      double vertEndY = (double)maxTileIndexY*gridHeight+vertStartY;
      //horizontal lines
      for(int i= 0; i<maxTileIndexX; i++) {
          g.drawLine((int)vertStartX, (int)vertStartY, (int)vertEndX, (int)vertEndY);
          vertStartX += gridWidth;
          vertEndX   += gridWidth;
      }
      g.drawLine((int)vertStartX, (int)vertStartY,
                 (int)vertEndX, (int)vertEndY);
      double horizStartX = 10.0; double  horizStartY = 10.0;
      double horizEndX = maxTileIndexX*gridWidth+horizStartX;
      double horizEndY = 10.0;
      //horizontal lines
      for(int i=0; i<maxTileIndexY; i++) {
          g.drawLine((int)horizStartX, (int)horizStartY,
                     (int)horizEndX, (int)horizEndY);
          horizEndY += gridHeight;
          horizStartY   += gridHeight;
      }
      g.drawLine((int)horizStartX, (int)horizStartY,
                 (int)horizEndX, (int)horizEndY);
      g.setColor(Color.red);
      vertStartX = 10.0; vertStartY = 10.0;
      int vpWid, vpHt;
      if(vpSize == null){ vpWid = (int)gridWidth; vpHt = (int)gridHeight;}
      else {
         vpWid = vpSize.width; vpHt = vpSize.height;
      }
     if(dragOn) {
         currentShape = new Rectangle(-(int)vertStartX+panX,
                                      -(int)vertStartY+panY,vpWid, vpHt);
       }else {
         int x = (int)(vertStartX +
                 vpPos.x * ((width)/(double)(maxTileIndexX*tileWidth)));
         int y = (int)(vertStartY +
                 vpPos.y * ((height)/(double)(maxTileIndexY*tileHeight)));
         currentShape = new Rectangle(x,y,vpWid,vpHt);
      }
      g.draw(currentShape);
   }
}
