/*
 * 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 java.awt.Color;
import javax.swing.JFrame;
import java.awt.BorderLayout;
import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;
import java.awt.event.ComponentListener;
import java.awt.event.ComponentEvent;
import javax.swing.Timer;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

/**
   Crop the source image if either the width or height of the
   framebuffer is < SIZE (the initial size for the framebuffer).
<p>
   Letterbox the viewport, without scaling, if either the width
   or height of the framebuffer is > SIZE (the initial size for the
   framebuffer).
<p>
   This program has nine modes for how it places the viewport within
   the framebuffer (that is, nine letterboxing modes).
<p>
  This program has nine modes for how it anchors the circle within the
  camera's view rectangle (that is, nine cropping modes).
*/
@SuppressWarnings("serial")
public class Circle_v6_CropAndLetterbox extends Circle_v0_Abstract
{
   private boolean chooseCropMode = true;
   private int cropMode = 1;
   private int letterboxMode = 1;

   /**
      This constructor instantiates the Scene object
      and initializes it with appropriate geometry.
      Then this constructor instantiates the GUI.
   */
   private Circle_v6_CropAndLetterbox()
   {
      super("Renderer 5 - Crop & Letterbox");
      print_help_message();
   }


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

      // Set the size of the viewport. (SIZE is
      // the initial size of the framebuffer.)
      final int wVP = Math.min(SIZE, wFB);
      final int hVP = Math.min(SIZE, hFB);

      // Compute a displacement for the viewport within the framebuffer.
      final int hOffset = (wVP < wFB) ? (wFB - wVP) / 2 : 0;
      final int vOffset = (hVP < hFB) ? (hFB - hVP) / 2 : 0;

      // When the framebuffer is smaller than SIZE x SIZE,
      // compute the width and height of the largest possible
      // sub-rectangle of the unit square,
      //     -1 <= x <= 1, -1 <= y <= 1,
      // with the same aspect ratio as the viewport, wVP/hVP.
      final double w;
      final double h;
      // Compute the view rectangle's width.
      if (wVP < SIZE) // crop on the left and/or right
      {
         w = 2.0 * ((double)wVP / (double)SIZE);
      }
      else // don't crop horizontally
      {
         w = 2.0;
      }
      // Compute the view rectangle's height.
      if (hVP < SIZE) // crop on the top and/or bottom
      {
         h = 2.0 * ((double)hVP / (double)SIZE);
      }
      else // don't crop vertically
      {
         h = 2.0;
      }

      // If the framebuffer is smaller than SIZE x SIZE, then
      // crop the view rectangle to match the framebuffer.
      if (cropMode == 1)
      {
         // 1. upper left-hand corner
         scene = scene.changeCamera(
                     Camera.projOrtho(
                             -1.0,     // left
                             -1.0 + w, // right
                              1.0 - h, // bottom
                              1.0));   // top
      }
      else if (cropMode == 2)
      {
         // 2. center of the top edge
         scene = scene.changeCamera(
                     Camera.projOrtho(
                             -w / 2.0, // left
                              w / 2.0, // right
                              1.0 - h, // bottom
                              1.0));   // top
      }
      else if (cropMode == 3)
      {
         // 3. upper right-hand corner
         scene = scene.changeCamera(
                     Camera.projOrtho(
                              1.0 - w, // left
                              1.0,     // right
                              1.0 - h, // bottom
                              1.0));   // top
      }
      else if (cropMode == 4)
      {
         // 4. center of the right edge
         scene = scene.changeCamera(
                     Camera.projOrtho(
                              1.0 - w,   // left
                              1.0,       // right
                             -h / 2.0,   // bottom
                              h / 2.0)); // top
      }
      else if (cropMode == 5)
      {
         // 5. lower right-hand corner
         scene = scene.changeCamera(
                     Camera.projOrtho(
                              1.0 - w,   // left
                              1.0,       // right
                             -1.0,       // bottom
                             -1.0 + h)); // top
      }
      else if (cropMode == 6)
      {
         // 6. center of the bottom edge
         scene = scene.changeCamera(
                     Camera.projOrtho(
                             -w / 2.0,   // left
                              w / 2.0,   // right
                             -1.0,       // bottom
                             -1.0 + h)); // top
      }
      else if (cropMode == 7)
      {
         // 7. lower left-hand corner
         scene = scene.changeCamera(
                     Camera.projOrtho(
                             -1.0,       // left
                             -1.0 + w,   // right
                             -1.0,       // bottom
                             -1.0 + h)); // top
      }
      else if (cropMode == 8)
      {
         // 8. center of the left edge
         scene = scene.changeCamera(
                     Camera.projOrtho(
                             -1.0,       // left
                             -1.0 + w,   // right
                             -h / 2.0,   // bottom
                              h / 2.0)); // top
      }
      else if (cropMode == 9)
      {
         // 9. center of the framebuffer
         scene = scene.changeCamera(
                     Camera.projOrtho(
                             -w / 2.0,   // left
                              w / 2.0,   // right
                             -h / 2.0,   // bottom
                              h / 2.0)); // top
      }

      // If the framebuffer is larger than SIZE x SIZE, then
      // letterbox the viewport within the framebuffer.
      if (letterboxMode == 1)
      {
         // 1. upper left-hand corner
         fb.setViewport(0, 0, wVP, hVP);
      }
      else if (letterboxMode == 2)
      {
         // 2. center of the top edge
         fb.setViewport(hOffset, 0, wVP, hVP);
      }
      else if (letterboxMode == 3)
      {
         // 3. upper right-hand corner
         fb.setViewport(wFB - wVP, 0, wVP, hVP);
      }
      else if (letterboxMode == 4)
      {
         // 4. center of the right edge
         fb.setViewport(wFB - wVP, vOffset, wVP, hVP);
      }
      else if (letterboxMode == 5)
      {
         // 5. lower right-hand corner
         fb.setViewport(wFB - wVP, hFB - hVP, wVP, hVP);
      }
      else if (letterboxMode == 6)
      {
         // 6. center of the bottom edge
         fb.setViewport(hOffset, hFB - hVP, wVP, hVP);
      }
      else if (letterboxMode == 7)
      {
         // 7. lower left-hand corner
         fb.setViewport(0, hFB - hVP, wVP, hVP);
      }
      else if (letterboxMode == 8)
      {
         // 8. center of the left edge
         fb.setViewport(0, vOffset, wVP, hVP);
      }
      else if (letterboxMode == 9)
      {
         // 9. center of the framebuffer
         fb.setViewport(hOffset, vOffset, wVP, hVP);
      }

      super.setupViewing();
   }


   // Implement the KeyListener interface.
   @Override public void keyTyped(KeyEvent e)
   {
      //System.out.println( e );

      final char c = e.getKeyChar();
      if ('0' == c)
      {
         chooseCropMode = ! chooseCropMode;
         System.out.println("Choosing "
                          + (chooseCropMode ? "crop" : "letterbox")
                          + " mode.");
      }
      else if ('1' == c)
      {
         if (chooseCropMode)
            cropMode = 1;
         else
            letterboxMode = 1;
      }
      else if ('2' == c)
      {
         if (chooseCropMode)
            cropMode = 2;
         else
            letterboxMode = 2;
      }
      else if ('3' == c)
      {
         if (chooseCropMode)
            cropMode = 3;
         else
            letterboxMode = 3;
      }
      else if ('4' == c)
      {
         if (chooseCropMode)
            cropMode = 4;
         else
            letterboxMode = 4;
      }
      else if ('5' == c)
      {
         if (chooseCropMode)
            cropMode = 5;
         else
            letterboxMode = 5;
      }
      else if ('6' == c)
      {
         if (chooseCropMode)
            cropMode = 6;
         else
            letterboxMode = 6;
      }
      else if ('7' == c)
      {
         if (chooseCropMode)
            cropMode = 7;
         else
            letterboxMode = 7;
      }
      else if ('8' == c)
      {
         if (chooseCropMode)
            cropMode = 8;
         else
            letterboxMode = 8;
      }
      else if ('9' == c)
      {
         if (chooseCropMode)
            cropMode = 9;
         else
            letterboxMode = 9;
      }

      if ('0' == c || '1' == c || '2' == c || '3' == c || '4' == c ||
          '5' == c || '6' == c || '7' == c || '8' == c || '9' == c )
      {
         System.out.println("letterboxMode = " + letterboxMode);
         System.out.println("cropMode = " + cropMode);
      }

      super.keyTyped(e);
   }


   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 '0' key to toggle choosing letterbox/crop mode.");
      System.out.println("Use the '1' through '9' keys to choose a letterbox/crop mode.");
      System.out.println("Use the 'h' key to redisplay this help message.");
      System.out.println();
      System.out.println("The nine letterbox/crop modes are:");
      System.out.println("  1 - top left-hand corner");
      System.out.println("  2 - top center");
      System.out.println("  3 - top right-hand corner");
      System.out.println("  4 - right center");
      System.out.println("  5 - botton right-hand corner");
      System.out.println("  6 - bottom center");
      System.out.println("  7 - botton left-hand corner");
      System.out.println("  8 - left center");
      System.out.println("  9 - center");
      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_v6_CropAndLetterbox()
      );
   }
}
