/** TiledImageViewer Class
   * @version 2.0  18 dec 2001
   * @author Lawrence Rodrigues
   **/
package app;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.border.*;
import java.awt.geom.*;
import com.vistech.util.*;
import com.vistech.jai.imageio.*;
import com.vistech.jai.render.*;

import java.awt.image.RenderedImage;
import java.beans.*;
import javax.media.jai.JAI;
import javax.media.jai.PlanarImage;
import com.sun.media.jai.codec.*;

/** An application that is capable of displaying and scrolling large rendered images.
  * @version 2.0 18 Dec 2000
  * @author Lawrence Rodrigues
  **/
public class TiledImageViewer extends JAIImageViewer{
   protected RenderedImageCanvas viewer;
   protected RenderGrid renderGrid;
   protected JTextField twidth, theight;
   protected JTextArea memoryMessageBar;

   public void createUI() {
      try {
      LookAndFeel lf = new javax.swing.plaf.metal.MetalLookAndFeel();
      // LookAndFeel lf = new javax.swing.plaf.multi.MultiLookAndFeel();
      UIManager.setLookAndFeel(lf);
      } catch (Exception e){}
      Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
      int width = (int)(dim.width *5/6.0);
      int height = (int)(dim.height*5/6.0);

      setTitle("Rendering JAI Images");
      viewer = new RenderedImageCanvas();
      Dimension d = getViewerSize(width/(double)height);
      viewer.setPreferredSize(new Dimension(d.width, d.height));

      createImageLoaderAndSaver();
      loader.addPlanarImageLoadedListener(
          new PlanarImageLoadedListener() {
             public void imageLoaded(PlanarImageLoadedEvent e) {
                PlanarImage image = e.getImage();
                if(image == null) return;
                setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
                SwingUtilities.invokeLater(new ImagePaint(image));
             }
         }
      );

      twidth = new JTextField(5);
      theight = new JTextField(5);
      renderGrid = new RenderGrid();
      renderGrid.setForeground(Color.green);
      renderGrid.setForeground(Color.blue);
      LookAndFeel.installColors(renderGrid, "blue", "green");
      JPanel rgPan = new JPanel(new GridLayout(1,1));
      rgPan.add(renderGrid);
      //renderGrid.setBorder(BorderFactory.createTitledBorder("Tile Grid"));
      //2.0 Changes
      rgPan.setBorder(BorderFactory.createTitledBorder(new EtchedBorder(),"Tile Grid"));
      theight.setText(Integer.toString(viewer.getTileHeight()));
      twidth.setText(Integer.toString(viewer.getTileWidth()));

      JPanel gridpan = new JPanel();

      GridBagLayout gb = new GridBagLayout() ;
      GridBagConstraints c = new GridBagConstraints();
      gridpan.setLayout(gb);
      c.fill = GridBagConstraints.BOTH;
       c.gridwidth = GridBagConstraints.REMAINDER;
      c.weighty = 1.0; c.weightx = 1.0;
      gb.setConstraints(rgPan, c);
      gridpan.add(rgPan);
      c.fill = GridBagConstraints.HORIZONTAL;
      c.weighty = 0.0; c.weightx = 1.0;
      c.gridwidth = 1;
      c.insets = new Insets(1,1,1,1);
      JPanel tilesetpan = createTileSetPanel();
      gb.setConstraints(tilesetpan, c);
      gridpan.add(tilesetpan);
      JTabbedPane jtp = new JTabbedPane();
      jtp.add("Load", flBrowser);
      jtp.add("Save",  saver);
      JSplitPane hsp = new JSplitPane(JSplitPane.VERTICAL_SPLIT, jtp,gridpan);
      JSplitPane vsp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, hsp,viewer);
      getContentPane().setLayout(new GridLayout(1,1));
      getContentPane().add(vsp);
      pack();
      setSize(new Dimension(d.width+170, d.height+20));
      show();
      hsp.setDividerLocation(0.6);
      vsp.setDividerLocation(0.32);
      hsp.setDividerSize(5);
      vsp.setDividerSize(6);
      addEventAdapters();
      initializeScroll();
      viewer.repaint();
      renderGrid.setTileDimension(viewer.getTileWidth(), viewer.getTileHeight());
      updateRenderGrid();
      flBrowser.revalidate();
   }

   protected JTextArea createMemoryMessageBar(){
      JTextArea messageBar = new JTextArea();
      messageBar.setBackground(Color.black);
      messageBar.setForeground(Color.green);
      updateMemoryMessageBar(messageBar);
      return messageBar;
   }

   protected void updateMemoryMessageBar(JTextArea mbar) {
      Runtime rt = Runtime.getRuntime();
      long totalMemory = rt.totalMemory();
      rt.gc();
      long freemem = rt.freeMemory();
      mbar.setText("Total = "+ totalMemory+  "\n" +
                   "Free  = " + freemem);
   }

   protected void initializeScroll(){
      scroll = new com.vistech.imageviewer.ScrollGUI(viewer);
      viewer.addMouseListener(scroll);
      viewer.addMouseMotionListener(scroll);
   }

   public JPanel createTileSetPanel(){
      memoryMessageBar = createMemoryMessageBar();
      JPanel mmPan = new JPanel(new GridLayout(1,1));
      mmPan.add(memoryMessageBar);

      mmPan.setBorder(BorderFactory.createTitledBorder("Memory Usage"));
      GridBagLayout gb = new GridBagLayout() ;
      GridBagConstraints c = new GridBagConstraints();
      JPanel pan = new JPanel();
      pan.setLayout(gb);
      c.fill = GridBagConstraints.BOTH;
      c.weighty = 0.0; c.weightx = 1.0;
      c.gridwidth = 1;
      c.insets = new Insets(1,1,1,1);
      //c.gridwidth = GridBagConstraints.REMAINDER;
      //gb.setConstraints(mmPan, c);
      //pan.add(mmPan);
      c.gridwidth = 1;
      JLabel wdl = new JLabel("Tile Width");
      gb.setConstraints(wdl, c);
      pan.add(wdl);
      gb.setConstraints(twidth, c);
      pan.add(twidth);
      JLabel htl  = new JLabel("Tile Height");
      gb.setConstraints(htl, c);
      pan.add(htl);
      c.gridwidth = GridBagConstraints.REMAINDER;
      gb.setConstraints(theight, c);
      pan.add(theight);
      //c.gridwidth = GridBagConstraints.REMAINDER;
      gb.setConstraints(mmPan, c);
      pan.add(mmPan);

      return pan;
   }

   protected void addEventAdapters() {
      addTileParamsEventAdapters();
      addPropertyChangeEventAdapters();
   }

   protected void addTileParamsEventAdapters(){
      twidth.addActionListener(
         new ActionListener(){
            public void actionPerformed(ActionEvent e) {
               try {
                  String str = ((JTextField) e.getSource()).getText();
                  int wid = Integer.parseInt(str);
                  viewer.setTileWidth(wid);
                  str = theight.getText();
                  int ht = Integer.parseInt(str);
                  viewer.setTileHeight(ht);
                  if(renderGrid != null) updateRenderGrid();
               } catch (Exception e2){}
             }
          } );
      theight.addActionListener(
         new ActionListener(){
            public void actionPerformed(ActionEvent e) {
               try {
                  String str = ((JTextField) e.getSource()).getText();
                  int ht = Integer.parseInt(str);
                  viewer.setTileHeight(ht);
                  str = twidth.getText();
                  int wid = Integer.parseInt(str);
                  viewer.setTileWidth(wid);
                  if(renderGrid != null) updateRenderGrid();
               } catch (Exception e1){}
             }
          });

      viewer.addMouseListener(
         new MouseAdapter() {
           public void mouseReleased(MouseEvent e){
              updateMemoryMessageBar(memoryMessageBar);
           }
         });
   }

   protected void addPropertyChangeEventAdapters(){
       viewer.addPropertyChangeListener(
          new PropertyChangeListener() {
             public void propertyChange(PropertyChangeEvent e) {
                if(e.getPropertyName().equals("viewportPosition")){
                   twidth.setText(Integer.toString(viewer.getTileWidth()));
                   theight.setText(Integer.toString(viewer.getTileHeight()));
                   if(renderGrid != null) updateRenderGrid();
                   Point p =(Point)e.getNewValue();
                   renderGrid.setViewportPosition(p);
                }
                if(e.getPropertyName().equals("maxTileIndexX")){
                   renderGrid.setMaxTileIndexX(((Integer)e.getNewValue()).intValue());
                }
                if(e.getPropertyName().equals("maxTileIndexY")){
                   renderGrid.setMaxTileIndexY(((Integer)e.getNewValue()).intValue());
                }
                if(e.getPropertyName().equals("tileWidth")){
                   renderGrid.setTileWidth(((Integer)e.getNewValue()).intValue());
                }
               if(e.getPropertyName().equals("tileHeight")){
                   renderGrid.setTileHeight(((Integer)e.getNewValue()).intValue());
               }
               if(e.getPropertyName().equals("transform")){
                  int wid = renderGrid.getViewportDimension().width;
                  int ht = renderGrid.getViewportDimension().height;
                  double scaleX = wid/(double)viewer.getSize().width;
                  double scaleY = ht/(double)viewer.getSize().height;
                  AffineTransform atx =  (AffineTransform)e.getNewValue();
                  renderGrid.setTransform(atx);
               }
            }
         }
      );

      renderGrid.addPropertyChangeListener(
          new PropertyChangeListener() {
             public void propertyChange(PropertyChangeEvent e) {
                if(e.getPropertyName().equals("viewportPosition")){
                   double scaleX, scaleY;
                   int wid = renderGrid.getViewportDimension().width;
                   int ht = renderGrid.getViewportDimension().height;
                   scaleX = viewer.getImageWidth()/wid;
                   scaleY = viewer.getImageHeight()/ht;
                   if(e.getNewValue() instanceof Point){
                      Point p =(Point)e.getNewValue();
                      viewer.pan(-p.x*scaleX, -p.y*scaleY);
                  }
                }

            }
         }
      );
   }

   protected void updateRenderGrid() {
      if((viewer == null)|| (renderGrid == null)) return;
      int tw1 = viewer.getTileWidth();
      int th1 = viewer.getTileHeight();
      int xInd1 = viewer.getMaxTileIndexX();
      int yInd1 = viewer.getMaxTileIndexY();
      renderGrid.setTileDimension(tw1,th1);
      renderGrid.setTileIndices(xInd1, yInd1);
      int wid = renderGrid.getViewportDimension().width;
      int ht = renderGrid.getViewportDimension().height;
      double scaleX = viewer.getSize().width/(double)viewer.getImageWidth();
      double scaleY = viewer.getSize().height/(double)viewer.getImageHeight();
      double scaledVpX = wid*scaleX;
      double scaledVpY = ht*scaleY;
      renderGrid.setViewportSize(new Dimension((int)scaledVpX,(int)scaledVpY));
      renderGrid.repaint();
   }

   class ImagePaint implements Runnable {
      PlanarImage image;
      boolean firstTime = true;
      public ImagePaint(PlanarImage image){this.image = image;}
      public void run() {
         if(firstTime) {
            try {
             firstTime = false;
             setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
             viewer.setImage(image);
             saver.setDisplayImage(viewer.getDisplayImage());
             viewer.repaint();
             SwingUtilities.invokeLater(this);
            } catch(Exception e){SwingUtilities.invokeLater(this);}
         }
         else {
            if(!viewer.isImageDrawn()) SwingUtilities.invokeLater(this);
            else{
               setCursor(Cursor.getDefaultCursor());
               updateRenderGrid();
               updateMemoryMessageBar(memoryMessageBar);
           }
         }
      }
   }
   public static void  main(String[] args){
      TiledImageViewer ip = new TiledImageViewer();
      if(args.length <1) {
         ip.createUI();
      }else ip.loadAndDisplay(args[0]);
  }
}