import java.awt.*;
import java.applet.*;

public class JBill2 extends Applet implements Runnable {
   static final int scrwidth = 400;
   static final int scrheight = 400;

   static final int INTRO = 4;
   static final int PLAYING = 1;
   static final int BETWEEN = 2;
   static final int END = 3;

   static final int WAITING = 5;

   static final int DEFAULTC = 0;               /* cursors */
   static final int DOWNC = -1;
   static final int BUCKETC = -2;
   static final int ENDGAME = 200;              /* dialog window IDs */
   static final int ENTERNAME = 201;
   static final int HIGHSCORE = 202;
   static final int SCORE = 203;
   static final int ENDLEVEL = -1;              /* Codes for updating score */
   static final int BILLPOINTS = 5;
   static final int EMPTY = -2;         /* Grabbed object */
   static final int BUCKET = -1;

   static String version="2.0";

   Boolean syncOnMe = new Boolean(true);
   
   Thread gamethread = new Thread(this);
   UI ui=new UI(this);
   Horde bill=new Horde(this);
   Bucket bucket=new Bucket(this);
   Library OS=new Library(this);
   Network net=new Network(this);
   Spark spark=new Spark(this);
   Scorelist scores=new Scorelist(this);
   int state=-1;
   int prevstate=-10000;
   int stateAge=0;
   int efficiency;
   int score, level, iteration;
   Picture logo = new Picture(this);
   int grabbed;

   public void run() {
      ui.restart_timer();
      while (true) {
	 synchronized (syncOnMe) {
	    update();
	 }
         ui.idle_timer();
      }
   }

   int RAND(int lb, int ub) {
      int a;
      do {
         a=(int)(Math.floor(Math.random()*(ub-lb+1)) + lb);
      } while ((a>ub)||(a<lb));
      return a;
   }

   int MAX(int x, int y) {
      return Math.max(x,y);
   }

   int MIN(int x, int y) {
      return Math.min(x,y);
   }

   boolean INTERSECT(int x1, int y1, int w1, int h1, int x2, int y2, int w2,
        int h2)
     {
        return (((x2-x1<=w1 && x2-x1>=0) || (x1-x2<=w2 && x1-x2>=0))
                && ((y2-y1<=h1 && y2-y1>=0) || (y1-y2<=h2 && y1-y2>=0)));
     }

   void setup_level (int lev) {
      level = lev;
      bill.setup();
      grabbed = EMPTY;
      ui.set_cursor(DEFAULTC);
      net.setup();
      iteration = efficiency = 0;
   }

   void start(int lev) {
      score = 0;
      setup_level(lev);
      state = INTRO;
   }

   void quit() {
//      scores.write();
      System.exit(0);
   }

   void update_info() {
      String str =  "Bill:"+bill.on_screen+"/"+bill.off_screen+"  System:"+
        net.base+"/"+net.off+"/"+net.win+"  Level:"+level+"  Score:"+score;
      ui.draw_str(str, 5, scrheight-5);
      efficiency += ((100*net.base-10*net.win)/net.units);
   }

   void update_score (int action) {
      switch (action){
       case ENDLEVEL:
         score+=(level*efficiency/iteration);
         break;
       default:
         score+=(action*action*BILLPOINTS);
      }
   }

   void warp_to_level (int lev) {
      if (state==PLAYING) {
         if (lev <= level)
           return;
         setup_level(lev);
      }
      else {
         if (lev<=0)
           return;
         start(lev);
      }
   }

   void button_press(int x, int y) {
      int i, counter=0, flag=0;
      synchronized (syncOnMe) {
	 if (state == WAITING) {
	    level = 1;
	    start(level);
	    return;
	 }
	 if (state != PLAYING)
	   return;
	 ui.set_cursor(DOWNC);
	 if (bucket.clicked(x, y)) {
	    ui.set_cursor(BUCKETC);
	    grabbed = BUCKET;
	 }
	 for (i=0; i < bill.MAX_BILLS && (flag==0); i++) {
	    if (bill.list[i].state == bill.list[i].OFF
		|| bill.list[i].state == bill.list[i].DYING)
	      continue;
	    if (bill.list[i].state == bill.list[i].STRAY &&
		bill.list[i].clickedstray(x, y))
	      {
		 ui.set_cursor (bill.list[i].cargo);
		 grabbed = i;
		 flag = 1;
	      }
	    else if (bill.list[i].state != bill.list[i].STRAY &&
		     bill.list[i].clicked(x, y))
	      {
		 if (bill.list[i].state == bill.list[i].AT)
		   net.computers[bill.list[i].target_c].busy=false;
		 bill.list[i].index = -1;
		 bill.list[i].cels = bill.dcels;
		 bill.list[i].x_offset = -2;
		 bill.list[i].y_offset = -15;
		 bill.list[i].state = bill.list[i].DYING;
		 counter++;
	      }
	 }
	 if (counter!=0) update_score(counter);
      }
   }
   
   void button_release(int x, int y) {
      int i;      
      ui.set_cursor (DEFAULTC);
      synchronized (syncOnMe) {
	 if (state != PLAYING || grabbed == EMPTY)
	   return;
	 if (grabbed == BUCKET) {
	    grabbed = EMPTY;
	    for (i=0; i<net.ncables; i++)
	      if (net.cables[i].onspark(x, y)) {
		 net.cables[i].active=false;
		 net.cables[i].delay = spark.delay(level);
	      }
	    return;
	 }
	 for (i=0; i<net.units; i++)
	   if (net.computers[i].oncomputer(x, y)
	       &&
	       net.computers[i].compatible (bill.list[grabbed].cargo)
	       &&
	       (net.computers[i].os == OS.WINGDOWS ||
		net.computers[i].os == OS.OFF))
	   {
	      net.base++;
	      if (net.computers[i].os == OS.WINGDOWS)
		net.win--;
	      else
		net.off--;
	      net.computers[i].os = bill.list[grabbed].cargo;
	      bill.list[grabbed].state = bill.list[grabbed].OFF;
	      grabbed = EMPTY;
	      return;
	   }
	 grabbed = EMPTY;
      }
   }
   public void start() {
      ui.paused=false;
   }
   public void stop() {
      ui.paused=true;
   }

   void update(){
      if (state!=prevstate) {
         prevstate=state;
         stateAge=0;
      }
      else {
         stateAge++;
      }
      switch (state) {
       case PLAYING:
         ui.clear();
         bucket.draw();
         net.update();
         net.draw();
         bill.update();
         bill.draw();
         update_info();
         if ((bill.on_screen+bill.off_screen)==0) {
            update_score(ENDLEVEL);
            state = BETWEEN;
         }
         if ((net.base+net.off)<=1) state = END;
         break;
       case END:
         ui.cursor=-3;
         ui.clear();
         net.toasters();
         net.draw();
         ui.set_pausebutton (false);
         ui.drawTextCentered("GAME OVER     Level "+level+"     Score:"+score,Color.red);
         ui.repaint();
         if (stateAge>=12)
           state = WAITING;
         break;
       case BETWEEN:
         ui.cursor=-3;
         state = INTRO;
         setup_level(++level);
         break;
       case INTRO:
         ui.clear();
         bucket.draw();
         net.update();
         net.draw();
         ui.drawTextCentered("Level "+level+"     Score:"+score,Color.white);
         ui.repaint();
         if (stateAge>=6)
           state=PLAYING;
         break;
       case WAITING:
         ui.clear();
         ui.draw_centered(logo);
         int numsteps = (400+bill.width)/4;
         bill.list[0].y_offset=-15;
         bill.list[0].x_offset=-2;
         bill.list[0].cargo=0;
         bill.list[0].y=315;
         bill.list[0].x=stateAge%numsteps*4-bill.width;
         bill.list[0].index=stateAge%4;
         bill.list[0].cels = bill.rcels;
         bill.list[0].draw_std();
         bill.list[1].y_offset=-15;
         bill.list[1].x_offset=-2;
         bill.list[1].cargo=(stateAge/numsteps)%OS.NUM_OS+1;
         bill.list[1].y=85-bill.height;
         bill.list[1].x=400-(stateAge%numsteps*4);
         bill.list[1].index=stateAge%4;
         bill.list[1].cels = bill.lcels;
         bill.list[1].draw_std();

         ui.draw_str_centered("Click to begin the Game",Color.white,275);
         ui.repaint();
         break;
      }
      ui.repaint();
      iteration++;
   }

   public void init() {
      JBill2main(new String[0]);
   }

   void JBill2main(String[] argv) {
      int c;
      setLayout(null);
      add(ui);
      ui.reshape(0,0,400,400);
      ui.show();
      show();

      level = 0;
      ui.initialize(argv);
      ui.make_mainwin();
      ui.graph_init();
      ui.clear();
      ui.draw_str_centered("JBill2",Color.white,200);
      ui.draw_str_centered("Loading Title Screen...",Color.white,275);
      ui.repaint();
      logo.load("logo");
      ui.clear();
      ui.draw_centered(logo);
      ui.draw_str_centered("Loading Bill Sprites...",Color.white,275);
      ui.repaint();
      ui.make_windows();
/*      scores.read();
      scores.update();*/
      bill.load_pix();
      ui.clear();
      ui.draw_centered(logo);
      ui.draw_str_centered("Loading OS Sprites...",Color.white,275);
      ui.repaint();
      OS.load_pix();
      ui.clear();
      ui.draw_centered(logo);
      ui.draw_str_centered("Loading Computer Sprites...",Color.white,275);
      ui.repaint();
      net.load_pix();
      ui.clear();
      ui.draw_centered(logo);
      ui.draw_str_centered("Loading Bucket Sprites...",Color.white,275);
      ui.repaint();
      bucket.load_pix();
      ui.clear();
      ui.draw_centered(logo);
      ui.draw_str_centered("Loading Spark Sprites...",Color.white,275);
      ui.repaint();
      spark.load_pix();

      state = WAITING;
      gamethread.start();
   }

   public static void main(String[] argv) {
      if (argv.length==1 && argv[0].equals("-v")) {
         System.out.println ("JBill version "+version+"\n\n");
         return;
      }
      if (argv.length==1 && argv[0].equals("-h")) {
         System.out.println ("JBill version "+version+"\n");
         System.out.println ("Options:\n");
         System.out.println ("-v\t\tPrint version number and exit.\n");
         System.out.println ("-h\t\tPrint help and exit.\n");
         System.out.println ("leaves the window.\n\n");
         return;
      }
      new AppletShell("JBill v"+version,400,400, false, false, new JBill2(), argv);
   }
}
