/*
 * @(#) ImageDataViewer.java 1.0 99/10/4
 * Copyright (c) 1999 Larry 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 java.awt.color.*;
import java.beans.*;
import com.vistech.util.*;
import vis.beans.plotter.*;

import java.util.*;

import com.sun.image.codec.jpeg.*;
 /** An application that displays image information.
   * @version 1.0  10 April 1999
   * @author Lawrence Rodrigues
   */
public class ImageDataViewer extends JPanel {
   ImagePanel viewer;
   BufferedImage image = null;

   JTable imageInfoTable;
   JTable imageStatsTable;

   int imageWidth, imageHeight;
   JFrame plotFrame, histoFrame;

   public static BufferedImage readAsBufferedImage(String filename) {
      try {
         FileInputStream fis = new FileInputStream(filename);
         JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder(fis);
         BufferedImage bi = decoder.decodeAsBufferedImage();
         return bi;
      } catch(Exception e) {
         System.out.println(e);
         return null;
      }
   }

   public void displayStats(ColorModel cm, SampleModel sm, DataBuffer db){
       ColorSpace cs = cm.getColorSpace();
       int numComponents = sm.getNumBands();
       String name[] = new String[numComponents];
       //System.out.println("num components = "+ numComponents);

       for(int i=0;i<numComponents;i++){
           name[i] = cs.getName(i);
           //System.out.println("name = "+ name[i]);
       }
       int[][] imstats = ImageInfoUtil.getImageStats(sm, db, new Dimension(imageWidth, imageHeight));
       String[] colnames = new String[] {"Sample", "Min", "Max", "Mean"};
       String rowdata[][] = new String[imstats.length][colnames.length+1];

       for(int i=0; i<imstats.length;i++){
           rowdata[i][0] = name[i];
           //columns
           for(int j=0;j<imstats[0].length;j++){
               rowdata[i][j+1] = Integer.toString(imstats[i][j]);
           }
       }
       imageStatsTable = new JTable(rowdata, colnames);
   }

   public void displayImageInfo(BufferedImage img){
      String prop[] = img.getPropertyNames();
      if(prop != null) {
         for(int i=0;i< prop.length; i++) {
             //System.out.println(prop[i] + "   "+ img.getProperty(prop[i]));
         }
      }
      SampleModel sm = img.getSampleModel();
      WritableRaster wr = img.getRaster();
      DataBuffer db = wr.getDataBuffer();
      ColorModel cm = img.getColorModel();
      //String rowdata[][] = ImageInfoUtil.getImageInfo(img);
      String rowdata[][] = getImageInfo(img);
      if(rowdata == null) return;
      String colnames[] = {"Properties ", "value"};
      imageInfoTable = new JTable(rowdata, colnames);
      imageWidth = img.getWidth();
      imageHeight = img.getHeight();
      displayStats(cm,sm,db);
   }

   public void displayHistogram(BufferedImage img) {
      if(histoFrame != null){
         histoFrame.show();
         return;
      }
      try {
         int[][] pix = ImageInfoUtil.getPixelSamples(img);
         ClassLoader cl = (MultiHistogram.class).getClassLoader();
         MultiHistogram histo = (MultiHistogram)Beans.instantiate(cl, "vis.beans.plotter.MultiHistogram");
         histo.setSize(400,300);
         histoFrame = new JFrame();
         histoFrame.addWindowListener(
         new WindowAdapter() {
            public void windowClosing(WindowEvent e){
               histoFrame.hide();
            }
         } );
         histoFrame.setTitle("Histogram");
         Container cp = histoFrame.getContentPane();
         histoFrame.getContentPane().setLayout(new GridLayout(1,1));
         cp.add(histo);
         histoFrame.pack();
         histoFrame.setSize(new Dimension(400, 300));
         histoFrame.show();
         String[] colstr = {"red sample", "green sample", "blue sample", "yellow"};
         Color[]  col = {Color.red, Color.green, Color.blue, Color.yellow};
         histo.setLegendOn(true);
         for (int i=0; i<pix.length;i++) {
           histo.addGraph(null, pix[i]);
           histo.addLegend(col[i], colstr[i]);
         }
         histo.setNumBars(6);
         histo.setTitleString("Histogram ");
         histo.setXLabelString("Pixel sample values");
         histo.setYLabelString("Frequency");
         histo.repaint();
      }catch (Exception e) {
         System.out.println(e);
      }
   }

    public void displayPlot(BufferedImage img) {
      if(plotFrame != null){
         plotFrame.show();
         return;
      }
      try {
      int[][] pix = ImageInfoUtil.getPixelSamples(img);
      ClassLoader cl = (MultiXYPlot.class).getClassLoader();
      MultiXYPlot xyp = (MultiXYPlot)Beans.instantiate(cl, "vis.beans.plotter.MultiXYPlot");
      plotFrame = new JFrame();
      plotFrame.addWindowListener(
         new WindowAdapter() {
            public void windowClosing(WindowEvent e){
               plotFrame.hide();
            }
         } );
      plotFrame.setTitle("XY Plot");
      Container cp = plotFrame.getContentPane();
      plotFrame.getContentPane().setLayout(new GridLayout(1,1));
      cp.add(xyp);
      plotFrame.pack();
      plotFrame.setSize(new Dimension(400, 300));
      plotFrame.show();
      String[] colstr = {"red sample", "green sample", "blue sample", "yellow"};
      Color[]  col = {Color.red, Color.green, Color.blue, Color.yellow};
      xyp.setLegendOn(true);
      int binWidth = 20;
      int numBins = 16;

      int[] x = new int[numBins];
      for (int i=0;i< numBins;i++)   x[i] = i*binWidth;
      int[] y = new int[numBins];
      for(int i=0; i<pix.length;i++){
           int k = 0;
           for (int j=0; j < pix[0].length;j++) {
                k = pix[i][j] /binWidth;
                if(k >= numBins) y[numBins-1]++;
                y[k]++;
           }
           xyp.addGraph(x, y);
           xyp.addLegend(col[i], colstr[i]);
           y = new int[numBins];
      }
      xyp.setTitleString(" ");
      xyp.setXLabelString("Sample Values");
      xyp.setYLabelString("Frequency");
      xyp.repaint();
      }catch (Exception e) {
          System.out.println(e);
      }
   }

   
   public void loadAndDisplay(String filename){
      image = readAsBufferedImage(filename);
      if(image != null) displayImage(image);
      else System.out.println("Error in image reading");
   }

   public void displayImage(BufferedImage img) {
      image = img;
      int width = img.getWidth();
      int height = img.getHeight();
      displayImageInfo(img);
      displayImage(img, width, height);
   }

   public void displayImage(BufferedImage img, int width, int height) {
      JFrame fr = new JFrame();
      fr.addWindowListener(
         new WindowAdapter() {
            public void windowClosing(WindowEvent e){
               System.exit(0);
            }
         } );
      fr.setTitle("Image Data Viewer");
      viewer = new ImagePanel(img);
      viewer.addMouseListener(new LaunchMenuAdapter());
      JScrollPane infojs = new JScrollPane(imageInfoTable);
      infojs.setBorder(BorderFactory.createTitledBorder("Image Info"));
      JScrollPane statsjs = new JScrollPane(imageStatsTable);
      statsjs.setBorder(BorderFactory.createTitledBorder("Image Statistics"));
      JSplitPane vsp = new JSplitPane(JSplitPane.VERTICAL_SPLIT, statsjs,infojs);
      vsp.setDividerLocation((int)(height/4));
      viewer.setPreferredSize(new Dimension(width, height));
      JSplitPane sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, viewer, vsp);
      Container cp = fr.getContentPane();
      fr.getContentPane().setLayout(new GridLayout(1,1));
      cp.add(sp);
      fr.pack();
      fr.setSize(new Dimension(width+ (int)(width/2), height));
      fr.show();
      sp.setDividerLocation(0.6);
      viewer.repaint();
   }

   public static  String[][] getImageInfo(BufferedImage img) {
      SampleModel sm = img.getSampleModel();
      WritableRaster wr = img.getRaster();
       DataBuffer db = wr.getDataBuffer();
      ColorModel cm = img.getColorModel();
      String str = ImageInfoUtil.getColorModelAsText(ImageInfoUtil.getColorModelType(cm));
      ColorSpace cs = cm.getColorSpace();
      String[][] rowData = new String[10][2];
      int i =0;
      rowData[i][0] = "Color Model";
      rowData[i++][1] =  str;
      rowData[i][0] = "Color space";
      rowData[i++][1] = ImageInfoUtil.getColorSpaceAsText(cs.getType());

      rowData[i][0] = "Sample Model";
      rowData[i++][1] = ImageInfoUtil.getSampleModelAsText(ImageInfoUtil.getSampleModelType(sm));
      //DataBuffer db = wr.getDataBuffer();
      rowData[i][0] = "Data type";
      rowData[i++][1] =  ImageInfoUtil.getDataTypeAsText(db.getDataType());
      int numbands = sm.getNumBands();
      rowData[i][0] = "Number of Bands";
      rowData[i++][1] =  Integer.toString(numbands);
      int numbanks = db.getNumBanks();
      rowData[i][0] = "Number of Banks";
      rowData[i++][1] =  Integer.toString(numbanks);

      rowData[i][0] = "Width";

      rowData[i++][1] = Integer.toString(img.getWidth());
      rowData[i][0] = "Height";
      rowData[i++][1] = Integer.toString(img.getHeight());
      int scanlineStride=0;
      if(sm instanceof ComponentSampleModel) {
          ComponentSampleModel csm = (ComponentSampleModel)sm;
          scanlineStride = csm.getScanlineStride();
          rowData[i][0] = "Scanline stride";
          rowData[i++][1] = Integer.toString(scanlineStride);
          int pixelStride =   csm.getPixelStride();
          rowData[i][0] = "Pixel stride";
          rowData[i++][1] = Integer.toString(pixelStride);
          //int[] bankIndices = csm.getBankIndices();
          //System.out.println("bank indices = " );
          //for(int j=0; j<bankIndices.length;j++)
          //    System.out.println(bankIndices[j]);
          //int[] bandOffsets = csm.getBandOffsets();
          //System.out.println("bank offsets = " );
          //for(int j=0; j<bandOffsets.length;j++)
          //System.out.println(bandOffsets[j]);
      } else {
          if( sm  instanceof SinglePixelPackedSampleModel){
              SinglePixelPackedSampleModel  ssm = (SinglePixelPackedSampleModel)sm;
              scanlineStride = ssm.getScanlineStride();
              rowData[i][0] = "Scanline stride";
               rowData[i++][1] = Integer.toString(scanlineStride);
              rowData[i][0] = "Pixel stride";
              rowData[i++][1] = "N/A";
          } else if ( sm  instanceof MultiPixelPackedSampleModel){
              MultiPixelPackedSampleModel  msm = (MultiPixelPackedSampleModel)sm;
               scanlineStride = msm.getScanlineStride();
               rowData[i][0] = "Scanline stride";
               rowData[i++][1] = Integer.toString(scanlineStride);
              int pixelBitStride = msm.getPixelBitStride();
              rowData[i][0] = "Pixel bit stride";
              rowData[i++][1] = Integer.toString(pixelBitStride);;
           }
        }
       return rowData;
   }

   protected void popupMenu(JComponent comp,int x, int y){
      JPopupMenu jp = new JPopupMenu("");
      jp.setLightWeightPopupEnabled(true);
      comp.add(jp);
      JMenuItem histo = new JMenuItem("Histogram");
      histo.addActionListener(
         new ActionListener(){
           public void actionPerformed(ActionEvent e){
              if(image != null)displayHistogram(image);
           }
         }
      );
      JMenuItem plot = new JMenuItem("XY Plot");
      plot.addActionListener(
         new ActionListener(){
           public void actionPerformed(ActionEvent e){
              if(image != null) displayPlot(image);
           }
         }
      );

      jp.add(histo);
      jp.add(plot);
      jp.addSeparator();
      jp.show(comp,x,y);
   }

   class LaunchMenuAdapter extends java.awt.event.MouseAdapter {
       public void mousePressed(MouseEvent e) {
         if(SwingUtilities.isRightMouseButton(e)){
            popupMenu((JComponent)e.getSource(), e.getX(), e.getY());
        }
   }
  }

  class ImagePanel extends JComponent {
      BufferedImage image;
      public ImagePanel(BufferedImage img){
         image = img;
      }

      public void paintComponent(Graphics g){
         Rectangle rect = this.getBounds();
         if(image != null) {
            g.drawImage(image, 0,0,rect.width, rect.height, null);
        }
      }
   }
   public static void  main(String[] args){
      ImageDataViewer ip = new ImageDataViewer();
       if(args.length <1) {
         System.out.println("Enter a valid JPEG file name");
         System.exit(0);
      } else ip.loadAndDisplay(args[0]);
   }
}
