
// Clock.java
// Howard Jones, ha.jones@ic.ac.uk, Sept. 1994
// Modified by Andrew Davison, ad@coe.psu.ac.th, March 2023

/* An analog clock showing the hour, minute, and second 
   hands.

   The hands are drawn as lines using a TextGraphics object. 

   Uses Lanterna 3
   https://github.com/mabe02/lanterna

   Usage (Windows):
     > compile.bat Clock.java
     > run.bat Clock

   Usage (Linux):
     > ./compile.sh Clock.java
     > ./run.sh Clock

*/


import java.io.*;
import java.util.*;
import java.time.*;  

import com.googlecode.lanterna.*;
import com.googlecode.lanterna.screen.*;
import com.googlecode.lanterna.terminal.*;
import com.googlecode.lanterna.graphics.*;
import com.googlecode.lanterna.input.*;



public class Clock
{
  private static final double ASPECT = 2.2;
         // used to compensate for the rectangular
         // shape of character cells in a window
  private static final double TWO_PI = 2.0 * Math.PI;


  public static void main(String[] args)
  {
    Screen scr = Utils.createScreen();
    scr.setCursorPosition(null);
    
    TerminalSize termSz = scr.getTerminalSize();
    int numCols = termSz.getColumns();
    int numRows = termSz.getRows();

    // clock center and radius
    int cx = (numCols - 1)/2;
    int cy = numRows/2; 
    double clockRadius = 0;
    if (cx/ASPECT < cy)
      clockRadius = ((double)cx)/ASPECT;
    else
      clockRadius = (double)cy;

    // lengths of the three hands
    double secRadius = (4 * clockRadius)/6.0;
    double minRadius = (3 * clockRadius)/4.0;
    double hrRadius = clockRadius/2.0;

    // draw clock numerals
    double numsRadius = (5 * clockRadius)/6.0;
    for (int i = 0; i < 12; i++) {
      double angle = (i + 1) * TWO_PI/12.0;
      int dx = angleToX(angle, numsRadius);
      int dy = angleToY(angle, numsRadius);
      Utils.putString(scr, cx + dx, cy - dy, ""+(i+1),
                                TextColor.ANSI.GREEN);
    }

    TextGraphics tg = scr.newTextGraphics();  // for line drawing
    while (true) {
      KeyStroke ks = Utils.pollInput(scr);
      if (Utils.hasQuit(ks))
        break;

      LocalDateTime time = LocalDateTime.now();
  
      double hours = (time.getHour() + (time.getMinute()/60.0));
      if (hours > 12.0)   // this is a 12-hour clock
        hours -= 12.0;
      
      // calculate angles for the minute, hour, and secs hands
      double minAngle = ((time.getMinute() + 
                         time.getSecond()/60.0) * TWO_PI/60.0);
      int mdx = angleToX(minAngle, minRadius);
      int mdy = angleToY(minAngle, minRadius);
      
      double hrAngle = (hours * TWO_PI/12.0);
      int hdx = angleToX(hrAngle, hrRadius);
      int hdy = angleToY(hrAngle, hrRadius);
            
      double secAngle = (time.getSecond() * TWO_PI/60.0);
      int sdx = angleToX(secAngle, secRadius);
      int sdy = angleToY(secAngle, secRadius);
      
      // draw hour hand
      tg.drawLine(cx, cy, cx+hdx, cy-hdy, 'O');

      // minute hand
      tg.drawLine(cx, cy, cx+mdx, cy-mdy, '#');

      // second hand
      tg. drawLine(cx, cy, cx+sdx, cy-sdy, '.');
      
      Utils.refresh(scr);
      
      // clear hands
      tg.drawLine(cx, cy, cx+hdx, cy-hdy, ' ');
      tg.drawLine(cx, cy, cx+mdx, cy-mdy, ' ');
      tg.drawLine(cx, cy, cx+sdx, cy-sdy, ' ');

      Utils.pause(1000);  // 1 second
    }

    Utils.close(scr);
  }  // end of main()



  private static int angleToX(double angle, double radius) 
  {  return (int) Math.round(ASPECT * radius * Math.sin(angle)); }


  private static int angleToY(double angle, double radius) 
  {  return (int) Math.round(radius * Math.cos(angle));  }


}  // end of Clock class
