package state;

import java.util.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;
import tools.*;

class WeatherPanel extends JPanel {
  JPanel temperature, barometer, wind;

  // Variables for Thermometer
  Thermometer inTherm, outTherm;       // thermometer panels
  JLabel inTLabel, outTLabel;          // labels for current temperature
  volatile double inTemp, outTemp;     // values of current temperature
  
  // Variables for Barometer
  volatile double pressure;            // barometric pressure
  Barometer baro;                      // barometer panel
  JLabel pressLabel;                   // label for pressure

  // Variables for Wind Panel
  volatile short wspeed, wgust;                   // speed, gust
  volatile int wdir;                              // direction
  volatile double wchill;                         // chill
  JLabel spdLabel, gstLabel, chlLabel, dirLabel;  // value labels
  CompassPanel windDir;                           // wind direction panel
  
  Color textColor = new Color(102,102,153);

  WeatherPanel() {
    GridBagLayout gridbag = new GridBagLayout();
    GridBagConstraints c = new GridBagConstraints();

    setLayout(gridbag);
    c.anchor = GridBagConstraints.NORTHWEST;

    // Temperature panel
    c.gridwidth = 1; c.gridheight = 2;
    c.gridx = 0; c.gridy = 0;
    temperature = getTempPanel();
    gridbag.setConstraints(temperature, c);
    add(temperature);

    c.gridx = 1;
    c.gridheight = 1;
    add(Box.createHorizontalStrut(25));

    // Barometer Panel
    c.gridx = 2;
    barometer = getBarometerPanel();
    gridbag.setConstraints(barometer, c);
    add(barometer);

    c.gridx = 3;
    add(Box.createHorizontalStrut(10));

    // Wind Panel
    c.gridwidth = 3; c.gridheight = 1;
    c.gridx = 1; c.gridy = 1;
    wind = getWindPanel();
    gridbag.setConstraints(wind, c);
    add(wind);
  }

  synchronized public void setTemp(int in, int out) {
    // temp comes in as 10ths of a degree, farenheit
    int i = (int)((in - 320) * (5.0/9.0)); // convert to 10ths of a d, celsius
    int o = (int)((out - 320) * (5.0/9.0)); // convert to 10ths of a d, celsius
    inTemp = ((double)i)/10.0;
    outTemp = ((double)o)/10.0;
    
    inTherm.setTemp(inTemp, (in<200 || in>900));
    outTherm.setTemp(outTemp);
    inTLabel.setText(Format.round(inTemp,1)+" C");
    if (in<200 || in>900) inTLabel.setForeground(Color.red);
    else inTLabel.setForeground(textColor);
    outTLabel.setText(Format.round(outTemp,1)+" C");
    repaint();
  }
  synchronized public void setPressure(int p) {
    pressure = Format.round(((double)p)/1000.0, 3);
    baro.setPressure(pressure);
    pressLabel.setText(pressure+" in");
    repaint();
  }
  synchronized public void setWind(short s, short g, int c, short d) {
    wspeed = s;
    spdLabel.setText(s+" mph");
    wgust = g;
    gstLabel.setText(g+" mph");
    int ch = (int)((c - 320) * (5.0/9.0)); // convert to 10ths of a d, celsius
    wchill = ((double)ch)/10.0;
    chlLabel.setText(wchill+" C");
    setDirection(d);
    repaint();
  }
  synchronized private void setDirection(short h) {
    wdir = (int)h;
    windDir.setHeading(wdir);
    
    // change based on heading input method...
    
    if(wdir == 0 || wdir == 360) {
      dirLabel.setText(wdir+" N");
      wdir = 0;
    } else if (wdir == 180) {
      dirLabel.setText(wdir+" S");
      wdir = 0;
    } else if (wdir == 90) {
      dirLabel.setText(wdir+" E");
      wdir = 0;
    } else if (wdir == 270) {
      dirLabel.setText(wdir+" W");
      wdir = 0;
    } else if (wdir < 90) {
      dirLabel.setText(wdir+" E of N");
    } else if (wdir < 180) {
      wdir = 180 - wdir;
      dirLabel.setText(wdir+" E of S");
    } else if (wdir < 270) {
      wdir = wdir - 180;
      dirLabel.setText(wdir+" W of S");
    } else {
      wdir = 360 - wdir;
      dirLabel.setText(wdir+" W of N");
    }
  }

  JPanel getTempPanel() {
    JPanel result = new JPanel();
    
    result.setBorder(BorderFactory.createTitledBorder("Temperature"));
    result.setPreferredSize(new Dimension(250,370));

    GridBagLayout gridbag = new GridBagLayout();
    GridBagConstraints c = new GridBagConstraints();

    result.setLayout(gridbag);

    c.gridwidth = 1; c.gridheight = 1;
    c.gridx = 0; c.gridy = 0;
    JLabel ins = new JLabel("Inside");
    ins.setPreferredSize(new Dimension(60,15));
    result.add(ins, c);

    c.gridwidth = 1; c.gridheight = 1;
    c.gridx = 1; c.gridy = 0;
    result.add(Box.createHorizontalStrut(40), c);

    c.gridwidth = 1; c.gridheight = 1;
    c.gridx = 2; c.gridy = 0;
    JLabel outs = new JLabel("Outside");
    outs.setPreferredSize(new Dimension(60,15));
    result.add(new JLabel("Outside"), c);

    c.gridwidth = 1; c.gridheight = 5;
    c.gridx = 0; c.gridy = 1;
    inTherm = new Thermometer();
    gridbag.setConstraints(inTherm, c);
    result.add(inTherm);

    c.gridwidth = 1; c.gridheight = 5;
    c.gridx = 2; c.gridy = 1;
    outTherm = new Thermometer();
    gridbag.setConstraints(outTherm, c);
    result.add(outTherm);

    c.gridwidth = 1; c.gridheight = 1;
    c.gridx = 1; c.gridy = 1;
    JLabel fifty = new JLabel(" 50");
    fifty.setPreferredSize(new Dimension(40,40));
    fifty.setHorizontalAlignment(JLabel.CENTER);
    fifty.setVerticalAlignment(JLabel.CENTER);
    result.add(fifty, c);

    c.gridwidth = 1; c.gridheight = 1;
    c.gridx = 1; c.gridy = 2;
    result.add(Box.createVerticalStrut(120), c);

    c.gridx = 1; c.gridy = 3;
    result.add(new JLabel(" 0"), c);

    c.gridx = 1; c.gridy = 4;
    result.add(Box.createVerticalStrut(90), c);

    c.gridx = 1; c.gridy = 5;
    result.add(new JLabel("-40"), c);

    c.gridx = 0; c.gridy = 6;
    inTLabel = new JLabel("0.0 C");
    inTLabel.setPreferredSize(new Dimension(70,20));
    inTLabel.setHorizontalAlignment(JLabel.CENTER);
    inTLabel.setBorder(BorderFactory.createLoweredBevelBorder());
    result.add(inTLabel, c);

    c.gridx = 1; c.gridy = 6;
    result.add(Box.createHorizontalStrut(40), c);

    c.gridx = 2; c.gridy = 6;
    outTLabel = new JLabel("0.0 C");
    outTLabel.setPreferredSize(new Dimension(70,20));
    outTLabel.setHorizontalAlignment(JLabel.CENTER);
    outTLabel.setBorder(BorderFactory.createLoweredBevelBorder());
    result.add(outTLabel, c);

    return result;
  }

  JPanel getBarometerPanel() {
    JPanel result = new JPanel();
    result.setBorder(BorderFactory.createTitledBorder("Barometer"));
    result.setPreferredSize(new Dimension(200,120));

    GridBagLayout gridbag = new GridBagLayout();
    GridBagConstraints c = new GridBagConstraints();

    result.setLayout(gridbag);

    c.gridwidth = 1; c.gridheight = 2;
    c.gridx = 0; c.gridy = 0;
    baro = new Barometer();
    result.add(baro, c);
    
    c.gridwidth = 1; c.gridheight = 1;
    c.gridx = 1; c.gridy = 0;
    JLabel pres = new JLabel("Pressure");
    pres.setPreferredSize(new Dimension(90,40));
    pres.setHorizontalAlignment(JLabel.CENTER);
    pres.setVerticalAlignment(JLabel.BOTTOM);
    result.add(pres, c);
    
    c.gridx = 1; c.gridy = 1;
    pressLabel = new JLabel("29.000 in");
    pressLabel.setPreferredSize(new Dimension(90,20));
    pressLabel.setHorizontalAlignment(JLabel.CENTER);
    pressLabel.setBorder(BorderFactory.createLoweredBevelBorder());
    result.add(pressLabel, c);
    
    return result;
  }

  JPanel getWindPanel() {
    JPanel result = new JPanel();
    result.setBorder(BorderFactory.createTitledBorder("Wind"));

    GridBagLayout gridbag = new GridBagLayout();
    GridBagConstraints c = new GridBagConstraints();

    result.setPreferredSize(new Dimension(250, 250));
    result.setLayout(gridbag);

    c.anchor = GridBagConstraints.WEST;
    
    c.gridwidth = 1; c.gridheight = 1;
    c.gridx = 0; c.gridy = 0;
    JLabel spd = new JLabel("Speed");
    spd.setPreferredSize(new Dimension(100,20));
    gridbag.setConstraints(spd, c);
    result.add(spd);

    c.gridx = 1;
    result.add(Box.createHorizontalStrut(10));
    
    c.gridx = 2;
    spdLabel = new JLabel("0 mph");
    spdLabel.setPreferredSize(new Dimension(105,20));
    spdLabel.setHorizontalAlignment(JLabel.CENTER);
    gridbag.setConstraints(spdLabel, c);
    spdLabel.setBorder(BorderFactory.createLoweredBevelBorder());
    result.add(spdLabel);

    c.gridx = 0; c.gridy = 1;
    JLabel gst = new JLabel("Gust");
    gridbag.setConstraints(gst, c);
    result.add(gst);

    c.gridx = 1;
    result.add(Box.createHorizontalStrut(10), c);
    
    c.gridx = 2;
    gstLabel = new JLabel("0 mph");
    gstLabel.setPreferredSize(new Dimension(105,20));
    gstLabel.setHorizontalAlignment(JLabel.CENTER);
    gridbag.setConstraints(gstLabel, c);
    gstLabel.setBorder(BorderFactory.createLoweredBevelBorder());
    result.add(gstLabel);

    c.gridx = 0; c.gridy = 2;
    JLabel chl = new JLabel("Chill");
    gridbag.setConstraints(chl, c);
    result.add(chl);

    c.gridx = 1;
    result.add(Box.createHorizontalStrut(10), c);
    
    c.gridx = 2;
    chlLabel = new JLabel("0.0 C");
    chlLabel.setPreferredSize(new Dimension(105,20));
    chlLabel.setHorizontalAlignment(JLabel.CENTER);
    gridbag.setConstraints(chlLabel, c);
    chlLabel.setBorder(BorderFactory.createLoweredBevelBorder());
    result.add(chlLabel);

    c.gridx = 0; c.gridy = 3;
    result.add(Box.createVerticalStrut(15), c);
    
    c.anchor = GridBagConstraints.EAST;
    c.gridx = 0; c.gridy = 4;
    c.gridwidth = 3;
    windDir = new CompassPanel();
    result.add(windDir,c);
    
    c.anchor = GridBagConstraints.WEST;
    c.gridwidth = 1;
    c.gridx = 0; c.gridy = 5;
    JLabel dir = new JLabel("Direction");
    gridbag.setConstraints(dir, c);
    result.add(dir);

    c.gridx = 1;
    result.add(Box.createHorizontalStrut(10), c);

    c.gridx = 2;
    dirLabel = new JLabel("0.0 N");
    dirLabel.setPreferredSize(new Dimension(105,20));
    dirLabel.setHorizontalAlignment(JLabel.CENTER);
    gridbag.setConstraints(dirLabel, c);
    dirLabel.setBorder(BorderFactory.createLoweredBevelBorder());
    result.add(dirLabel);

    return result;
  }
}

class Thermometer extends JPanel {

  volatile double temp;
  Color bulbColor = Color.blue;
  
  Thermometer() {
    setPreferredSize(new Dimension(40,300));
    temp = 0;
  }

  synchronized public void setTemp(double t) {
    temp = t;
    repaint();
  }
  synchronized public void setTemp(double t, boolean red) {
    temp = t;
    if (red) bulbColor = Color.red;
    else bulbColor = Color.blue;
    repaint();
  }
  
  public void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2 = (Graphics2D) g;
    setOpaque(true);

    RoundRectangle2D.Double bulb =
      new RoundRectangle2D.Double(5, 15, 30, 270, 20, 20);

    g2.setColor(Color.white);
    g2.fill(bulb);                  // draw background of bulb
    
    Rectangle2D.Double mercury = new Rectangle2D.Double();
    mercury.setFrame(5, (50-temp)*3+15, 30, (temp+40)*3);
    Area th1 = new Area(mercury);
    Area th2 = new Area(bulb);
    th1.intersect(th2);
    g2.setColor(bulbColor);
    g2.fill(th1);                   // draw mercury (intersected with bulb)

    g2.setColor(Color.black);
    g2.setStroke(new BasicStroke(3.0f));
    g2.draw(bulb);                  // draw outline of bulb

    g2.setStroke(new BasicStroke(1.0f));
    for (int i=45; i<=255; i+=30) { // draw ticks
      g2.draw(new Line2D.Double(5, i, 35, i));
    }
  }
}

class Barometer extends JPanel {
  volatile double inches = 29.0;
  Point2D.Double origin = new Point2D.Double(50, 40);
  Point2D.Double end = new Point2D.Double(75, 40);

  Barometer() {
    setPreferredSize(new Dimension(100,90));
  }

  synchronized void setPressure(double i) {
    inches = i;
    repaint();
  }

  public void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2 = (Graphics2D) g;

    setOpaque(true);

    g2.setColor(Color.white);
    g2.fill(new Ellipse2D.Double(20, 10, 60, 60));
      
    g2.setColor(Color.black);

    g2.drawString("26", 17, 74);
    g2.drawString("27", 4, 45);
    g2.drawString("28", 17, 16);
    g2.drawString("29", 43, 8);
    g2.drawString("30", 68, 16);
    g2.drawString("31", 83, 45);
    g2.drawString("32", 68, 74);
    
    g2.setStroke(new BasicStroke(2.0f));
    g2.draw(new Ellipse2D.Double(20, 10, 60, 60));

    g2.setColor(Color.blue);
    g2.setStroke(new BasicStroke(3.0f));
    g2.transform(AffineTransform.getRotateInstance(Math.toRadians((inches-26)
								  *45-225),
						   origin.x, origin.y));
    g2.draw(new Line2D.Double(origin, end));
  }
  
}
