/*
 * (C) 2004 - Geotechnical Software Services
 * 
 * This code is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public 
 * License as published by the Free Software Foundation; either 
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This code is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public 
 * License along with this program; if not, write to the Free 
 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, 
 * MA  02111-1307, USA.
 */
import java.io.File;
import java.util.Iterator;
import java.text.DecimalFormat;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;

import javax.swing.*;
import javax.media.jai.JAI;
import javax.media.jai.RenderedOp;
import javax.media.jai.PlanarImage;

import no.geosoft.cc.geometry.Geometry;
import no.geosoft.cc.util.NiceNumbers;
import no.geosoft.cc.util.NiceNumber;
import no.geosoft.cc.graphics.*;



/**
 * G demo program. Demonstrates:
 *
 * <ul>
 * </ul>
 * 
 * @author <a href="mailto:info@geosoft.no">GeoSoft</a>
 */   
public class Demo18 extends JFrame
{
  /**
   * Class for creating the demo canvas and hande Swing events.
   */   
  public Demo18 (String imageFile,
                 int minCdp, int maxCdp,
                 int minTime, int maxTime)
  {
    super ("G Graphics Library - Demo 18");
    setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
    
    // Create the GUI
    JPanel topLevel = new JPanel();
    topLevel.setLayout (new BorderLayout());
    getContentPane().add (topLevel);        

    JScrollBar hScrollBar = new JScrollBar (JScrollBar.HORIZONTAL);
    getContentPane().add (hScrollBar, BorderLayout.SOUTH);

    JScrollBar vScrollBar = new JScrollBar (JScrollBar.VERTICAL);
    getContentPane().add (vScrollBar, BorderLayout.EAST);

    // Create the graphic canvas
    GWindow window = new GWindow (new Color (255, 255, 255));
    topLevel.add (window.getCanvas(), BorderLayout.CENTER);    
    
    // Definition of exact chart location inside window
    Insets insets = new Insets (80, 60, 20, 20);
    

    // Create a value specific image scene
    GScene seismicScene = new SeismicScene (window, imageFile,
                                            minCdp, maxCdp, minTime, maxTime,
                                            insets);

    // Create a "background" device oriented annotation scene
    GScene annotationScene = new GScene (window);
    GObject annotation = new Annotation (insets);
    annotationScene.add (annotation);
    annotationScene.setUserData (seismicScene);
    
    pack();
    setSize (new Dimension (500, 500));
    setVisible (true);

    // Start zoom interaction
    GStyle zoomStyle = new GStyle();
    zoomStyle.setForegroundColor (new Color (0, 0, 0));
    zoomStyle.setBackgroundColor (new Color (0.8f, 1.0f, 0.8f, 0.3f));
    window.startInteraction (new ZoomInteraction (seismicScene, zoomStyle));

    // Make sure plot can be scrolled
    seismicScene.installScrollHandler (hScrollBar, vScrollBar);
  }



  
  private class Annotation extends GObject
  {
    private Insets    insets_;
    private GSegment  title_;

    
    public Annotation (Insets insets)
    {
      insets_ = insets;
      
      title_ = new GSegment();
      GStyle titleStyle = new GStyle();
      titleStyle.setForegroundColor (new Color (0, 0, 0));
      titleStyle.setFont (new Font ("Dialog", Font.BOLD, 20));
      title_.setStyle (titleStyle);
      title_.setText (new GText ("Inline 220"));
      addSegment (title_);
      
      GStyle axisStyle = new GStyle();
      axisStyle.setForegroundColor (new Color (0.0f, 0.0f, 0.0f, 0.4f));
      axisStyle.setBackgroundColor (null);
      axisStyle.setFont (new Font ("Dialog", Font.BOLD, 10));

      Axis horizontalAxis = new Axis (true, insets_);
      horizontalAxis.setStyle (axisStyle);
      add (horizontalAxis);
      
      Axis verticalAxis = new Axis (false, insets_);
      verticalAxis.setStyle (axisStyle);
      add (verticalAxis);
    }
    

    public void draw()
    {
      GViewport viewport = getScene().getViewport();

      int x0     = insets_.left;
      int y0     = insets_.top;
      int width  = viewport.getX3() - insets_.right - insets_.left + 1;
      int height = viewport.getY3() - insets_.bottom - insets_.top + 1;

      // Draw title
      title_.setGeometry (x0 + width / 2, y0 / 2);
    }
  }



  /**
   * A GObject representing one axis with annotation.
   */   
  private class Axis extends GObject
  {
    private Insets   insets_;
    private boolean  isTop_;


    public Axis (boolean isTop, Insets insets)
    {
      isTop_  = isTop;
      insets_ = insets;
    }
    
    
    public void draw()
    {
      removeSegments();
      
      // Get device coordinates
      GViewport viewport = getScene().getViewport();

      int vx0 = insets_.left;
      int vy0 = insets_.top;
      int vx1 = viewport.getX3() - insets_.right;
      int vy1 = viewport.getY3() - insets_.bottom;

      // Get annotation range
      GObject plot = (GObject) getScene().getUserData();
      if (plot == null) return;
      
      GWorldExtent worldExtent = plot.getScene().getWorldExtent();

      double[] w0 = worldExtent.get (0);
      double[] w1 = worldExtent.get (1);
      double[] w2 = worldExtent.get (2);      

      // Prepare axis values
      double from = isTop_ ? w0[0] : w2[1];
      double to   = isTop_ ? w1[0] : w0[1];

      int x0 = vx0;
      int y0 = vy0;
      int x1 = isTop_ ? vx1 : x0;
      int y1 = isTop_ ? y0 : vy1;

      double length = Geometry.length (x0, y0, x1, y1);
      int n = (int) (length / 50.0);

      NiceNumbers niceNumbers = new NiceNumbers (from, to, n, true);      

      DecimalFormat format = new DecimalFormat ("0");
      
      for (Iterator i = niceNumbers.iterator(); i.hasNext(); ) {
        NiceNumber niceNumber = (NiceNumber) i.next();

        int rank = niceNumber.getRank();
        if (rank < 2) {
          int tickLength = rank == 0 ? 5 : 3;

          GSegment tick = new GSegment();
          int tx0 = isTop_ ? x0 + (int) Math.round (niceNumber.getPosition() * (x1 - x0)) : x0 - tickLength;
          int ty0 = isTop_ ? y0 - tickLength : y0 + (int) Math.round (niceNumber.getPosition() * (y1 - y0));
          int tx1 = isTop_ ? tx0 : (rank == 0 ? vx1 : x0);
          int ty1 = isTop_ ? (rank == 0 ? vy1 : y0) : ty0;
          tick.setGeometry (tx0, ty0, tx1, ty1);

          if (rank == 0) {
            double value = niceNumber.getValue();
            GText text = new GText (format.format (value),
                                    isTop_ ? GPosition.TOP : GPosition.LEFT);
            tick.setText (text);
          }

          addSegment (tick);
        }
      }
    }
  }
  


  private class SeismicSection extends GObject
  {
    private GSegment  anchor_;
    private BufferedImage  image_;
    
    
    SeismicSection (String seismicImage)
    {
      anchor_ = new GSegment();
      addSegment (anchor_);

      RenderedOp renderedOp = JAI.create ("FileLoad", seismicImage);
      PlanarImage planarImage = renderedOp.createInstance();
      image_ = planarImage.getAsBufferedImage();
    }


    public void draw()
    {
      GViewport viewport = getScene().getViewport();
      anchor_.setGeometry (viewport.getX0(), viewport.getY0());

      GWorldExtent worldExtent = getScene().getWorldExtent();
      double[] w2 = worldExtent.get (2);      

      int x0 = (int) w2[0] - 1;
      int y0 = ((int) w2[1] - 1000) / 4;

      int width  = (int) worldExtent.getWidth();
      int height = (int) worldExtent.getHeight() / 4;

      // Pick the part of the source image to show
      BufferedImage subImage = image_.getSubimage (x0, y0, width, height);

      // Scale it to the viewport
      int viewportWidth  = (int) viewport.getWidth();
      int viewportHeight = (int) viewport.getHeight();

      Image scaledImage = subImage.getScaledInstance (viewportWidth,
                                                      viewportHeight,
                                                      Image.SCALE_AREA_AVERAGING);
      
      GImage image = new GImage (scaledImage,
                                 GPosition.SOUTHEAST | GPosition.STATIC);
                                 
      anchor_.setImage (image);
    }
  }
  
  
  
  /**
   * Defines the geometry and presentation for a sample
   * graphic object.
   */   
  private class SeismicScene extends GScene
  {
    private Insets  insets_;

    
    SeismicScene (GWindow window, String seismicImage,
                  int minCdp, int maxCdp, int minTime, int maxTime,
                  Insets insets)
    {
      super (window);

      insets_ = insets;
      
      double w0[] = {(double) minCdp, (double) maxTime, 0.0};
      double w1[] = {(double) maxCdp, (double) maxTime, 0.0};
      double w2[] = {(double) minCdp, (double) minTime, 0.0};
      setWorldExtent (w0, w1, w2);

      SeismicSection seismicSection = new SeismicSection (seismicImage);
      add (seismicSection);
    }

    

    protected void resize (double dx, double dy)
    {
      super.resize (dx, dy);
      setViewport (insets_.left, insets_.top,
                   getWindow().getWidth() - insets_.left - insets_.right,
                   getWindow().getHeight() - insets_.top - insets_.bottom);
    }
  }

  

  public static void main (String[] args)
  {
    if (args.length != 5) {
      System.out.println ("Parameters: imageFile minCDP maxCDP minTime maxTime");
      System.exit (0);
    }
    
    new Demo18 (args[0],
                Integer.parseInt (args[1]),
                Integer.parseInt (args[2]),
                Integer.parseInt (args[3]),
                Integer.parseInt (args[4]));
  }
}