import java.util.*;          // pour Calendar
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import java.net.*;
import java.awt.image.*;


public class Clock24 extends Applet implements Runnable
{
  /** dimension X,Y du frame */
  private static int x_size, y_size;
  /** ratio longueur/ largeur */
  private static double ratio;
  /** offset de l'horloge dans le frame */
  private static int x_offset, y_offset;
  /** centre de l'hologe */
  public static int x_center, y_center;
  /** grosseur du rectangle (carre) entourant le cadran */
  private int oval_size;
  /** le cadran */
  private Cadran cadran;
  /** largeur de la bande contenant les boutons */
  private static int bande_height;
  /** Pour tester si la dimension de l'horloge a ete changee */
  private Dimension old_dim, new_dim;
  /** flag si application ou applet */
  private static boolean bApp = false;
  /** on ne fait pas de paint quand iconifier */
  private static boolean iconified = false;

  /** Foo will be only used to put the Applet */
  private static Frame frame;
  /** The thread that display clock */
  private Thread timer;

  /** Largeur de la base de chaque aiguille */
  private int base[] = {10, 8, 6};

  /** L'heure actuelle */
  private int now[];
  /** Les 3 aiguilles des heures, minutes, secondes */
  private Aiguille aiguille_hh, aiguille_mm, aiguille_ss;

  /** Le fichier du monde */
  private static String file = "TimeZone.jpg";
  /** le decalage horaire de ces villes */
  private static int decalage[];
  /** Le .jpg de la mappemonde */
  private Image image;
  /** Les radio-buttons qui correspondent aux 24 heures */
  private static Checkbox button[];
  /** Le groupe des radio-buttons */
  private static CheckboxGroup radio;

  /** Init appele quand Applet et par main() in Application mode */
  public void init()
  {
    PixelGrabber grabber;
    MediaTracker tracker;
    URL url;                                         // to get filename
    Toolkit toolkit;

    setLayout(null);
    // on commencera par loader l'image (cela se fera en parallele)
    // grace au media tracker 

    toolkit  = Toolkit.getDefaultToolkit();   // pour loader les images
    tracker = new MediaTracker(this);

    // on load l'image
    
    url = getClass().getResource(file);    // URL du fichier
    image = toolkit.getImage(url);          // on load
    tracker.addImage(image, 0);             // on monitore
    
    // on cree les 24 checkbox et le decalage correspondant
    // (Montreal, decalge 0 est a 6)
    
    radio = new CheckboxGroup();
    button = new Checkbox[24];
    decalage = new int[24];
    int k = -6;
    for(short i = 0; i < 24; i++)
    {
      button[i] = new Checkbox("", radio, false);     // le boutton
      add(button[i]);                                 // on ajoute le boutton
      decalage[i] = k++;
      button[i].setBackground(Color.yellow);
    }
    button[6].setState(true);          // Montreal a "ON"
    
    // allocation du cadran et des aiguilles
    // l'aiguille des heures bouge aux minutes donc cadran divise en 24 * 60
    // l'aiguille des minutes bouge aux 10 secondes donc cadran divise en 60 * 6
    // l'aiguille des secondes bouge aux secondes donc cadran divise en 60

    cadran = new Cadran();
    aiguille_hh = new Aiguille(base[0], Color.black, 24 * 60);
    aiguille_mm = new Aiguille(base[1], Color.blue,  60 * 6);
    aiguille_ss = new Aiguille(base[2], Color.red,   60);

// image originale 1000x486 ... on l'etire un peu

    x_size = 800 / 3 * 2;                 // a determiner dynamiquement
    y_size = 486 / 3 * 2;                 // dans le futur
    
    // le ratio a maintenir entre x et y
    ratio = (double) y_size / (double) x_size;
    System.out.println("Ratio: " + ratio);    

    compute();            // calcul et determination de la longeur autres composants

    // Initialisation graphique

    setBackground(Color.lightGray);


// on attend que l'image soit loadee en memoire

     try
     {
     	  System.out.print("%Waiting for image to be loaded");
        tracker.waitForID(0);
        System.out.println(" " + file + " chargee en memoire");
     }
     catch (InterruptedException dontcare)
     {
     }

  }

/*------------------------- compute() ------------------------------------------*/

  private void compute()
  {
    int len;                   // pour calcul de la longeur des aiguilles
    int b_height;              // grosseur boutton
    double b_width;
    y_size = (int) Math.round((double) x_size * ratio);
  
    System.out.print("X/Y size: " + x_size + "," + y_size);
      
    // on ajoute une bande de 1/5 de la hauteur de la fenetre pour mettre les bouttons
    
    bande_height = y_size / 5;
    if(bande_height > 40) bande_height = 40;   // mais avec un maximum
    System.out.print(" BHeight: " + bande_height);
    b_width = (double) x_size / 24.0;     
    b_height = bande_height; 

    // on dimensionne et positionne les bouttons
    
    len = (int) Math.round(b_width);
    for(short i = 0; i < 24; i++)
    {
       button[i].setBounds((int) Math.round((double) i * b_width), y_size, 
                                                               len, b_height);
    }

    // on positionne le cadran a 1/5 de la fenetre
    // le centre de l'ecran est au centre de cette fenetre
    // la grosseur du cadran est en fonction du y_size qui est plus petit
    
    x_center = x_size / 2;      
    y_center = y_size / 2;
    len = (y_center / 4) * 3;          // rayon du cadran
    System.out.print("  center: " + x_center + "," + y_center + "  len: " + len);
    x_offset = x_center - len;
    y_offset = y_center - len;
    System.out.println("  Offset: " + x_offset + "," + y_offset); 
    oval_size = len * 2;
    
    // on recalcule les composantes du cadran
    // qui contrairement aux aiguilles ne sont pas recalculees a chaque seconde
     
    cadran.compute(x_offset, y_offset, oval_size);

    // puis la longueur des aiguilles
    
    len = (oval_size / 2) - (y_size / 10);
    aiguille_hh.longueur = len;
    len += (y_size / 30);
    aiguille_mm.longueur = len;
    len += (y_size / 30);
    aiguille_ss.longueur = len;

    if(bApp)                      // on re-ajuste grandeur de la fenetre
    {
      setSize(x_size, y_size + bande_height + 30);
      frame.setSize(x_size, y_size + bande_height + 30);
    }
    else
    {
    	System.out.print("Applet--->");
      setSize(x_size, y_size + bande_height + 100);
    }
    old_dim = getSize();         // et on la garde
    System.out.println("set old-dim: " + old_dim);

  }

/*------------------------------   run  ------------------------------------*/

  /** Boucle infinie avec un sleep puis appel a repaint() */
  public void run()
  {
    Thread me = Thread.currentThread();

    while(timer == me)
    {
      try
      {
      	if(iconified)
          Thread.currentThread().sleep(2500);
        else
          Thread.currentThread().sleep(1000);
      }
      catch (InterruptedException e)
      {}
      repaint();       // ou tout se fait
    }
  }

/*---------------------------  start  -------------------------------*/

/** Start appele quand Applet et par main() in Application mode pour implementer les threads */
  public void start()
  {
  	timer = new Thread(this);
  	System.out.println("%Starting thread");
  	timer.start();
  }

  public void stop()
  {
    timer = null;
  }

/*----------------------------  paint  -------------------------------*/

/** Redraw the clock */
  public void paint(Graphics g)
  {
  	int hh, mm, ss, delta;
  	
    if(iconified) return;

/**
    if(bApp)                            // if application
    {
      new_dim = getSize();              // test s'il y a eu un resize
      if(!new_dim.equals(old_dim))
      {
    	  System.out.println("Old: " + old_dim + " New: " + new_dim);
          x_size = new_dim.width;
          compute();                    // re-calcul de la position des composantes 
      }
    }
*/
    Calendar calendar = Calendar.getInstance();    
  
    g.drawImage(image, 0, 0, x_size, y_size, null);

    cadran.draw(g);

    // on determine le decalage en passant a travers les checkbox
    
    delta = 6;
    for(short i = 0; i < 24; i++)
    {
    	if(button[i].getState())
    	{
    		delta = decalage[i];
    		break;
    	}
    }
    
    // Get actual time
    hh = calendar.get(Calendar.HOUR_OF_DAY);
    hh = hh + delta;
    hh %= 24;
    mm = calendar.get(Calendar.MINUTE);
    ss = calendar.get(Calendar.SECOND);

    // aiguilles
    aiguille_hh.compute(hh * 60 + mm, x_center, y_center);
    aiguille_hh.draw(g);

    aiguille_mm.compute(mm * 6 + (ss / 10), x_center, y_center);
    aiguille_mm.draw(g);

    aiguille_ss.compute(ss, x_center, y_center);
    aiguille_ss.draw(g);

/* le centre des aiguilles */

    g.setColor(Color.lightGray);
    g.fillOval(x_center - 6, y_center - 6, 12, 12);
    g.setColor(Color.black);
    g.fillOval(x_center - 4, y_center - 4, 8, 8);

  }

/*------------------------------  update  -----------------------------*/

/** As usual in AWT update() calls paint() */
  public void update(Graphics g)
  {
  	paint(g);
  }

/*------------------------------  main  --------------------------------*/

/** procedure main() quand appele comme application */
  public static void main(String noarg[])
  {
  	bApp = true;
  	Applet applet = new Clock24();         // instance Applet de moi meme
  	frame = new Frame("Clock 24");
  	frame.addWindowListener(new CloseListener());
  	frame.add(applet);                     // put the applet in the frame

  	applet.init();                         // comme si Applet
  	frame.setSize(x_size, y_size + bande_height+ 30); // on cree le frame applicatif
  	applet.start();
  	frame.setVisible(true);                // it's a go
  }

/*---------------------------  CloseListener  -----------------------------*/

  static class CloseListener extends WindowAdapter
  {
    public void windowClosing(WindowEvent e)
    {
       System.exit(0);
    }
    public void windowIconified(WindowEvent e)
    {
    	iconified = true;
    }
    public void windowDeiconified(WindowEvent e)
    {
    	iconified = false;
    }
  }
}
