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

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

import javax.swing.JFrame;
import java.awt.Color;
import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;
import java.awt.event.ComponentListener;
import java.awt.event.ComponentEvent;
import java.awt.BorderLayout;

/**
   Simultaneously compare the aspect ratios of the
   JFrame, its ContentPane, the JPanel, its FrameBuffer,
   and the Camera's view rectangle.
<p>
   This program responds to only componentResized events.
*/
public class TestAspectRatios implements ComponentListener
{
   private final int WINDOW_SIZE = 512;

   private final Scene scene;
   private final JFrame jf;
   private final FrameBufferPanel fbp;

   public TestAspectRatios()
   {
      scene = new Scene("TestAspectRatios",
                        Camera.projOrtho());

      final Model model = new Disk(1.0, 10, 40);
      ModelShading.setRandomColor(model);
      scene.addPosition(new Position(model));

      // Create a FrameBufferPanel that holds a FrameBuffer.
      final int width  = WINDOW_SIZE;
      final int height = WINDOW_SIZE;
      fbp = new FrameBufferPanel(width, height, Color.darkGray);
      fbp.getFrameBuffer().getViewport().setBackgroundColorVP(Color.black);

      // Register this object as the event listener for FrameBufferPanel events.
      fbp.addComponentListener(this);

      // Create a JFrame that will hold the FrameBufferPanel.
      jf = new JFrame("Renderer 5 - Test Aspect Ratios");
      jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      jf.getContentPane().add(fbp, BorderLayout.CENTER);
      jf.pack();
      jf.setLocationRelativeTo(null);
      jf.setVisible(true);
   }


   // Implement the ComponentListener interface.
   @Override public void componentMoved(ComponentEvent e){}
   @Override public void componentHidden(ComponentEvent e){}
   @Override public void componentShown(ComponentEvent e){}
   @Override public void componentResized(ComponentEvent e)
   {
      // Get the new size of the JFrame.
      final int wJF = jf.getWidth();
      final int hJF = jf.getHeight();

      // Get the new size of the JFrame's content pane.
      final int wCP = jf.getContentPane().getWidth();
      final int hCP = jf.getContentPane().getHeight();

      // Get the new size of the FrameBufferPanel.
      final int wFBP = fbp.getWidth();
      final int hFBP = fbp.getHeight();

      // Get the old size of the FrameBuffer.
      final FrameBuffer fb = fbp.getFrameBuffer();
      final int wFB = fb.getWidthFB();
      final int hFB = fb.getHeightFB();

      // Create a new FrameBuffer that fits the FrameBufferPanel.
//      final FrameBuffer fb2 = new FrameBuffer(wFBP, hFBP);
//      fbp.setFrameBuffer(fb2);

      // The view volume is centered on left edge.
      final Scene scene2 = scene.changeCamera(
               Camera.projOrtho(-1,                              // left
                                -1 + (2.0 * wFBP) / WINDOW_SIZE, // right
                                -hFBP / (double)WINDOW_SIZE,     // bottom
                                 hFBP / (double)WINDOW_SIZE));   // top

      System.out.printf("JFrame [w = %d, h = %d] w/h = %.2f.\n",
                        wJF, hJF, (double)wJF / (double)hJF);

      System.out.printf("ContentPane [w = %d, h = %d] w/h = %.2f.\n",
                        wCP, hCP, (double)wCP / (double)hCP);

      System.out.printf("JPanel [w = %d, h = %d] w/h = %.2f.\n",
                        wFBP, hFBP, (double)wFBP / (double)hFBP);

      System.out.printf("Framebuffer [w = %d, h = %d] w/h = %.2f.\n",
                        wFB, hFB, (double)wFB / (double)hFB);

      System.out.println( scene2.camera );
      System.out.println("=================================");

      // Render again.
      final FrameBuffer fb3 = fbp.getFrameBuffer();
      fb3.clearFB();
      Pipeline.render(scene2, fb3);
      fbp.repaint();
      System.out.flush(); // Because System.out is buffered by renderer.pipeline.PipelineLogger
   }


   /**
      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 TestAspectRatios()
      );
   }
}
