/*
 * Renderer 5. The MIT License.
 * Copyright (c) 2022 rlkraft@pnw.edu
 * See LICENSE for details.
*/

import renderer.scene.*;
import renderer.models_L.Disk;
import renderer.pipeline.*;
import renderer.framebuffer.*;

import java.awt.Color;
import java.awt.BorderLayout;
import java.awt.event.AdjustmentListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.Scrollbar;
// https://docs.oracle.com/en/java/javase/21/docs/api/java.desktop/java/awt/Scrollbar.html

/**
  The example demonstrates a form of "pan-and-scan".
<p>
  This program keeps the aspect ratio and the size of
  the complete circle at a constant SIZE by SIZE pixels.
  The program window can be any size. If the program
  window is smaller than SIZE by SIZE pixels, then only
  part of the complete circle is shown in the program
  window (the view of our circle in the camera's view
  rectangle gets "cropped" to fit inside of the program
  window). But the user is given a pair of scroll bars
  so that the user can "pan" their view of the (cropped)
  circle.
*/
@SuppressWarnings("serial")
public class Circle_v5_PanAndScan_Scrollbar extends Circle_v0_Abstract
                                            implements AdjustmentListener
{
   final private Scrollbar sbV;
   final private Scrollbar sbH;
   private int sliderValueH = 50;
   private int sliderValueV = 50;

   /**
      This constructor instantiates the Scene object
      and initializes it with appropriate geometry.
      Then this constructor instantiates the GUI.
   */
   public Circle_v5_PanAndScan_Scrollbar()
   {
      super("Renderer 5 - Pan And Scan_AWT");

      // Create Scrollbars for this JFrame.
      sbV = new Scrollbar(Scrollbar.VERTICAL,   50, 2, 0, 100);
      sbH = new Scrollbar(Scrollbar.HORIZONTAL, 50, 2, 0, 100);
      // Place the Scrollbars in this JFrame.
      this.getContentPane().add(sbV, BorderLayout.EAST );
      this.getContentPane().add(sbH, BorderLayout.SOUTH );
      this.pack();

      // Create event handler objects for the scroll events.
      sbV.addAdjustmentListener(this);
      sbH.addAdjustmentListener(this);

      // Let the FrameBufferPanel regain keyboard focus after a slider
      // is clicked on. Click on the panel to give it keyboard focus.
      fbp.addMouseListener(new MouseAdapter(){
         @Override public void mouseClicked(MouseEvent e){
            fbp.requestFocusInWindow();}});

      print_help_message();
   }


   // Implement the AdjustmentListener interface for the scrollbars.
   @Override public void adjustmentValueChanged(AdjustmentEvent e)
   {
    //super.adjustmentValueChanged(e);
      sliderValueV = sbV.getValue();
      sliderValueH = sbH.getValue();
      System.out.println("slider_H = " + sliderValueH + ", "
                       + "slider_V = " + sliderValueV);
      viewDataChanged = true;
      setupViewing();
   }


   /**
      Get in one place the code to set up
      the viewport and the view volume.
   */
   @Override protected void setupViewing()
   {
      // Get the size of the FrameBuffer.
      final FrameBuffer fb = this.fbp.getFrameBuffer();
      final int w = fb.getWidthFB();
      final int h = fb.getHeightFB();

      // Create a viewport.
      int vpX = 0;
      int vpY = 0;
      int vpW = w;
      int vpH = h;
      if (w > SIZE)
      {
         vpW = SIZE;
         vpX = (w - SIZE)/2;
      }
      if (h > SIZE)
      {
         vpH = SIZE;
         vpY = (h - SIZE)/2;
      }
      fb.setViewport(vpX, vpY, vpW, vpH);

      // Create a view volume whose aspect ratio matches the
      // viewport's aspect ratio.
      double left   = -(vpW/(double)SIZE);
      double right  =  (vpW/(double)SIZE);
      double bottom = -(vpH/(double)SIZE);
      double top    =  (vpH/(double)SIZE);
      // Use the slider value to pan the view volume across the scene.
      left   += (sliderValueH - 50.0)/50.0 * (1.0 - vpW/(double)SIZE);
      right  += (sliderValueH - 50.0)/50.0 * (1.0 - vpW/(double)SIZE);
      bottom += (50.0 - sliderValueV)/50.0 * (1.0 - vpH/(double)SIZE);
      top    += (50.0 - sliderValueV)/50.0 * (1.0 - vpH/(double)SIZE);
      scene = scene.changeCamera(
                       Camera.projOrtho(left, right, bottom, top));

      super.setupViewing();
   }


   @Override
   protected void print_help_message()
   {
      System.out.println("Use the 'd' key to debug one frame of animation.");
      System.out.println("Use the 'Alt-d' key combination to print the Scene data structure.");
      System.out.println("Use the 'a' key to toggle anti-aliasing on and off.");
      System.out.println("Use the 'g' key to toggle gamma correction on and off.");
      System.out.println("Use the 'v' key to toggle showing the view data.");
      System.out.println("Use the 's' key to stop/start the rotation.");
      System.out.println("Use the 'h' key to redisplay this help message.");
      System.out.flush();
   }


   /**
      Create an instance of this class which has
      the affect of creating the GUI application.
   */
   public static void main(String[] args)
   {
      // We need to call the program's constructor in the
      // Java GUI Event Dispatch Thread, otherwise we get a
      // race condition between the constructor (running in
      // the main() thread) and the very first ComponentEvent
      // (running in the EDT).
      javax.swing.SwingUtilities.invokeLater(
         () -> new Circle_v5_PanAndScan_Scrollbar()
      );
   }
}
