package edu.calpoly.csc480.Entomo.Seer;

import java.io.*;

import edu.calpoly.csc480.Entomo.Area.*;
import edu.calpoly.csc480.Entomo.Main.*;

public class Seer implements Runnable
{
	public static final int
	 waitingState  = 0,
	 runningState  = 1,
	 pausedState   = 2,
	 stoppedState  = 3,
	 finishedState = 4,
	 numStates     = 5;

	public Seer() {
		this.start = false;
		this.state = waitingState;
		this.delay = 0;

		this.area = new Area();
		this.view = new SeerView();
		
		area.setOwner(this);
		view.setDocument(this);
//		areaClosed();
	}
	
   protected void finalize() throws Throwable {
      start = false;
      state = waitingState;
      notify();

		if (thread != null) {
      	thread.join();
		}
   }
	
   final public boolean isStarted()				{return start;}
	final public int getState()					{return state;}

   final public boolean isRunnable()			{return state != waitingState;}
   final public boolean isRunning()				{return state == runningState;}
	final public boolean isPaused()				{return state == pausedState;}
	final public boolean isStopped()				{return state == stoppedState;}
	final public boolean isFinished()			{return state == finishedState;}

	final public Area getArea()					{return area;}
	final public SeerView getView()				{return view;}

	final public int getDelay()					{return delay;}
	final public int getMaximumDelay()			{return maximumDelay;}
	
	final public long getCycle()					{return cycle;}
	
	public void setOwner(Main main) {
		this.main = main;
		view.setOwner(main);
	}

	public void areaOpened(File in) throws IOException {
		stop();
		area.setFile(in);
		view.areaOpened();
	}
	
	public void areaClosed() {
		stop();
	
		state = waitingState;

		area.close();
		view.areaClosed();
	}

	public void setDelay(int delay) {
		this.delay = delay;
	}
	
	synchronized public void flip() {
		if (state == runningState)	{
			pause();
		}
		else {
			play();
		}
	}
	
	synchronized public void play() {
		if (!start) {
			cycle = 0;
			start = true;
			state = pausedState;

			area.start();
			view.start();

			thread = new Thread(this);
			thread.setPriority(Thread.MIN_PRIORITY);
			thread.start();
		}

		state = runningState;
		view.play();
		notify();
	}
	
	synchronized public void pause() {
		state = pausedState;
		view.pause();
	}
	
	public void step() {
		play();
	      
      try {next();}
      catch(InterruptedException err) {}
      
      pause();
	}
	
	synchronized public void stop() {
		start = false;
		state = stoppedState;
		view.stop();
		notify();
	}

	public void finish() {
		state = finishedState;
	}
	
	public void run() {
      try {
         while (!thread.interrupted() && start == true) {
            next();
            thread.sleep(delay);
         }
      } catch(InterruptedException err) {err.printStackTrace(System.err);}

	   if (state == finishedState) {
			view.finish();
		}
   }
	
	static final protected int maximumDelay = 2000;
	
	protected Main main;
	protected Area area;
	protected SeerView view;
	
   protected Thread thread;
	
	protected boolean start;
	protected int state;
	protected int delay;
	protected long cycle;

   synchronized protected void next() throws InterruptedException {
		final boolean gc = false;

      while (state != runningState) {
         wait();
      }

		if (gc) {
	      System.runFinalization();
	      System.gc();
		}

		area.next();
      view.next();

      if (++cycle < 0) {
         cycle = 0;
      }

      if (state == finishedState) {
         start = false;
      }
   }
}