/**
 * This applet demonstrates hidden Markov models for a particular
 * robot localization problem. It isn't designed to be general or reusable.
 * Copyright 2002 David Poole. All rights reserved.
 * @author David Poole
 * @version 0.1.2 2010-03-30 */

import java.awt.*;
import java.awt.event.*;
import java.text.*;
import javax.swing.*;


public class localization extends Frame implements ActionListener 
					  // implements TextListener
{ 
    double previous[] = new double[16];
    double current[] = new double[16];
    double obsDoor[] = {0.1,0.1,0.8,0.1,0.8,0.1,0.1,0.8,0.1,0.1,0.1,0.8,0.1,0.1,0.1,0.1};
    double obsLight[] = {0.1,0.05,0.05,0.05,0.1,0.2,0.4,0.6,0.8,0.95,0.99,0.95,0.8,0.6,0.4,0.2};
    
    int height = 250;
    int width = 46;
    String bottom = "Previous";
    Dimension gridDimension = new Dimension(width*16,2*height+30);


    //    Panel graphPanel;

  Font smallFont = new Font("Serif", Font.PLAIN, 12);
      Font bigFont = new Font("Serif", Font.BOLD, 24);

    public static void main(String[] args)
{
    localization f = new localization();
    f.setSize(900,540);
    f.setVisible(true);
    f.setLayout(new FlowLayout());
    }

    
    public localization()
    {
      this.setLayout(new BorderLayout());
       DistPanel distPanel = new DistPanel();
       this.add(new JScrollPane(distPanel),"Center");

      
	Panel pan = new Panel();
	//	pan.setLayout(new GridLayout(9,1));
	pan.setLayout(new BoxLayout(pan,BoxLayout.Y_AXIS));

    Button left = new Button("Left");
    pan.add(left);
    left.addActionListener(this);

    Button right = new Button("Right");
    pan.add(right);
    right.addActionListener(this);

    Button door = new Button("Observe Door");
    pan.add(door);
    door.addActionListener(this);

    Button nodoor = new Button("No Door");
    pan.add(nodoor);
    nodoor.addActionListener(this);

    Button light = new Button("Observe Light");
    pan.add(light);
    light.addActionListener(this);

    Button nolight = new Button("No Light");
    pan.add(nolight);
    nolight.addActionListener(this);

    Button showlight = new Button("Show Light Dist");
    pan.add(showlight);
    showlight.addActionListener(this);

    Button showdoor = new Button("Show Door Dist");
    pan.add(showdoor);
    showdoor.addActionListener(this);

    Button reset = new Button("Reset");
    pan.add(reset);
    reset.addActionListener(this);

    Button know = new Button("Know location");
    pan.add(know);
    know.addActionListener(this);

    //  TextField disccountField = new TextField("0.9",6);
    // pan.added(disccountField);

    add(pan,"East");
    doReset();
    }


    public void actionPerformed ( ActionEvent e)
    {
	String arg = e.getActionCommand();
	bottom="Previous";
	if (arg.equals("Reset") )
		doReset();
	else if (arg.equals("Right"))
		doRight();
	else if (arg.equals("Left"))
		doLeft();
	else if (arg.equals("Observe Door"))
		doDoor();
	else if (arg.equals("No Door"))
		doNoDoor();
	else if (arg.equals("Observe Light"))
		doLight();
	else if (arg.equals("No Light"))
		doNoLight();
	else if (arg.equals("Show Door Dist"))
		doShowDoor();
	else if (arg.equals("Show Light Dist"))
		doShowLight();
	else if (arg.equals("Know location"))
		doKnowLocation();
	repaint();
    }

    public void doReset()
    {     
      for (int i=0 ; i <16; i++) {
	  previous[i]=1.0/16.0;
	  current[i]=1.0/16.0;
      }
    }

    public void doRight()
    { 
	for (int i=0; i<16; i++) {
	    previous[i]=current[i];
	    current[i]=0.002;
	}
	for (int i=0; i<16; i++) {
	    current[i]+=previous[i]*0.098;
	    current[(i+1) % 16] += previous[i]*0.798;
	    current[(i+2) % 16] += previous[i]*0.072;
	}
    }

    public void doLeft()
    { 
	for (int i=0; i<16; i++) {
	    previous[i]=current[i];
	    current[i]=0.002;
	}
	for (int i=0; i<16; i++) {
	    current[i]+=previous[i]*0.098;
	    current[(i+15) % 16] += previous[i]*0.798;
	    current[(i+14) % 16] += previous[i]*0.072;
	}
    }

    public void doDoor() {
	for (int i=0; i<16; i++) {
	    previous[i]=current[i];
	    current[i]*=obsDoor[i];
	}
	normalizeCurrent();
    }

    public void doNoDoor() {
	for (int i=0; i<16; i++) {
	    previous[i]=current[i];
	    current[i]*=(1-obsDoor[i]);
	}
	normalizeCurrent();
    }

 
    public void doLight() {
	for (int i=0; i<16; i++) {
	    previous[i]=current[i];
	    current[i]*=obsLight[i];
	}
	normalizeCurrent();
    }

    public void doNoLight() {
	for (int i=0; i<16; i++) {
	    previous[i]=current[i];
	    current[i]*=(1-obsLight[i]);
	}
	normalizeCurrent();
    }

    public void doShowLight() {
	for (int i=0; i<16; i++) {
	    previous[i]=obsLight[i];
	}
	bottom="P(Observe light | location)";
    }

    public void doShowDoor() {
	for (int i=0; i<16; i++) {
	    previous[i]=obsDoor[i];
	}
	bottom="P(Observe door | location)";
    }

    public void doKnowLocation() {
	int pos=(int) (16*Math.random());
	for (int i=0; i<16; i++) {
	    current[i]=0.0;
	}
	current[pos]=1.0;
    }

   public void normalizeCurrent() {
	double sum=0;
	for (int i=0; i<16; i++) {
	    sum+=current[i];
	}
	for (int i=0; i<16; i++) {
	    current[i]/=sum;
	}
    }

private class DistPanel extends JPanel
{
    public DistPanel()
		{
			setPreferredSize(gridDimension);
		}

    public void paintComponent(Graphics g)
    {  
	g.setColor(Color.white);
	g.fillRect(0,0,16*width,height*2+30);
	drawDist(g,2*height+14,previous,bottom);
	drawDist(g,height,current,"Current");
  }

    
    public void drawDist(Graphics g, int offset, double dist[], String title ) {
	g.setColor(Color.black);
//   	setFont(smallFont);
	DecimalFormat df = new DecimalFormat("0.###");
	for (int i=0; i<16; i++) {
	    g.fillRect(i*width,offset-(int)Math.round(height*dist[i]),width,(int)Math.round(height*dist[i]));
	    g.drawString(df.format(dist[i]),i*width+10,offset+12);
	}
	g.setColor(Color.red);
//  	setFont(bigFont);
	g.drawString(title,20,offset-height*2/3);
	for (int i=0; i<16; i++) {
	    g.drawString(Integer.toString(i),i*width+10,offset-40);
	}
//  	setFont(smallFont);
    }

    public void windowClosing(WindowEvent e)
    {
	dispose();
	System.exit(0);
    }
    
}
}

