// *********************************************************************
// Volcano.java
// ** This class draws a "volcano" to a specified Graphics context **
//
// Murphy Stein
// NYU Computer Graphics
// 2006
// *********************************************************************
import java.awt.*;
import java.awt.geom.PathIterator;
import java.util.LinkedList;
import java.util.*;


public class Volcano {

	Polygon p;
	LinkedList PointList;
	int x, y;
	int bottom;
	
	static Color BROWN = new Color(200, 100, 50);
	
	Color lavaColor;

	ActionTimer myTimer;
	
	double VolatilityLevel = 0;

	static int QUIET = 0;
	static int IS_IRRITATED = 1;
	static int IS_EXPLODING = 2;
	static int IS_ERUPTING = 3;
	static int FINISHED_ERUPTING = 4;

	int state = QUIET;

	LinkedList Lava1;
	LinkedList Lava2;
	LinkedList Lava3;
	
	
   
	// ** Constuctor **
	// Creates a "triangular" volcano from three points
	
	public Volcano (int tx, int ty, int brx, int bry, int blx, int bly) {

		x = tx;
		y = ty;

		if (brx > blx) {
			bottom = brx;
		} else {
			bottom = blx;
		}
		
		myTimer = new ActionTimer(0.1);
		
		p = new Polygon();
		
		int newx = tx;
		int newy = ty;
		
		
		PointList = new LinkedList();
		
		Point newPoint;
		
		Lava1 = new LinkedList();
		Lava2 = new LinkedList();
		Lava3 = new LinkedList();
		
		//assemble right face
		while ((newx < brx) || (newy < bry)) {
			newx += (int)(Math.random()*9 + 3);
			newy += (int)(Math.random()*9 + 3);
			newPoint = new Point(newx, newy);
			PointList.addLast(newPoint);
//			System.out.println("p.addPoint(" + newx + "," + newy + ");");
		}
	
		// assemble bottom face
		while (newx > blx) {
			newx -= (int)(Math.random()*9 + 3);
			newPoint = new Point(newx, newy);
			PointList.addLast(newPoint);
//			System.out.println("p.addPoint(" + newx + "," + newy + ");");
	
		}
		
		// assemble left face
		while ((newx < tx) && (newy > ty)) {
			newx += (int)(Math.random()*9 + 3);
			newy -= (int)(Math.random()*9 + 5);
			newPoint = new Point(newx, newy);
			PointList.addLast(newPoint);
	
		}
		
		ConstructPolygon();
	}



	// draw the Volcano to the specified Graphics Context
	public void draw(Graphics g) {

		double time = System.currentTimeMillis() / 1000.0;

		int deltaX, deltaY;
		if (VolatilityLevel > 2) {
			deltaX = (int)(Math.random()*2);
   			p.translate(deltaX, 0);
			g.setColor(BROWN);	
			g.fillPolygon(p);
   			p.translate(-1*deltaX, 0);
		} else { 
			g.setColor(BROWN);	
			g.fillPolygon(p);
		}
		VolatilityLevel *= (0.9);
// 		System.out.println(VolatilityLevel);

		if (myTimer.isAGo()) {
			if (state == IS_EXPLODING) {		
				Explode();
			} else if (state == IS_ERUPTING) {
				MakeLava(Lava1);
				MakeLava(Lava2);
				MakeLava(Lava3);

			}
		}
		
		lavaColor = new Color( (float)Math.abs(Math.sin(0.1 * Math.PI * time)), (float)0.0, (float)0.0);
		g.setColor(lavaColor);

		if (Lava1.size() > 0) {
			ListIterator l1 = Lava1.listIterator();
			Point curPoint = (Point) Lava1.getFirst();
			while (l1.hasNext()) {
				g.fillOval((int)curPoint.getX(),(int)curPoint.getY(),3,3);
				curPoint = (Point) l1.next();
			}
		}
		if (Lava2.size() > 0) {
			ListIterator l2 = Lava2.listIterator();
		
			Point curPoint = (Point) Lava1.getFirst();
			while (l2.hasNext()) {
				g.fillOval((int)curPoint.getX(),(int)curPoint.getY(),3,3);
				curPoint = (Point) l2.next();
			}
		}
		if (Lava3.size() > 0) {
			ListIterator l3 = Lava3.listIterator();
			Point curPoint = (Point) Lava3.getFirst();
			while (l3.hasNext()) {
				g.fillOval((int)curPoint.getX(),(int)curPoint.getY(),3,3);
				curPoint = (Point) l3.next();
			}
		}

	}
	
	public void MakeLava(LinkedList L) {
		Point curPoint;
		Point newPoint;
		int x, y;
		int range;
		
		if (L.size() <=0 ) {
			curPoint = (Point) PointList.getLast();
			x = (int)curPoint.getX();
			y = (int)curPoint.getY();
			curPoint = (Point) PointList.getFirst();
			range = (int)curPoint.getX() - x;
			x += (int)(Math.random()*range);
			if (y < curPoint.getY()) {
				y = (int)curPoint.getY();
			}
		} else {
			curPoint = (Point) L.getLast();
			x = (int)(curPoint.getX() + (Math.random()*4-2));
			y = (int)(curPoint.getY() + (Math.random()*4));
			//System.out.println("(x,y) is " + x + "," + y);
		}
		newPoint = new Point(x, y);
		if (p.contains(x, y) == true) {
			L.addLast(newPoint);
		}
		if (x > bottom) {
			increaseState();
		}
	}
      
   public Polygon MyExtent( ) {
	   return this.p;
   }
   
 	public double VolatilityLevel() {
   		return this.VolatilityLevel;
   }
   
   public void Irritate() {
			if (this.VolatilityLevel <= 2) {
				this.VolatilityLevel = 2;
			}
			this.VolatilityLevel *= 1.2;
			if (VolatilityLevel > 5) {
				state = IS_EXPLODING;
			}
   	}
   	
   	public void Explode() {
   		Point curPoint, lastPoint;

   	   	lastPoint = (Point) PointList.getLast();
		if (PointList.size() > 0) { 
			curPoint = (Point) PointList.getFirst();
			if (lastPoint.getY() > curPoint.getY()) {
				PointList.removeFirst();
			} else {
				increaseState();
			}
		}
		ConstructPolygon();

   	}
   	
   	public void ConstructPolygon()
   	{
   		Point curPoint;
   		p.reset();
   		ListIterator i = PointList.listIterator();
   		while ( i.hasNext() ) { 
   			curPoint = (Point) i.next();
   			p.addPoint((int)(curPoint.getX()),(int)(curPoint.getY()));
   		}
   	}
   	   	
   	   	
   	public void increaseState() {
   		
   		if (state == 0) {
   			state++;
   		} else if (state + 1 == IS_EXPLODING) {
   			state++;
   		} else if (state + 1 == IS_ERUPTING) {
   			state++;
   		} else if (state + 1 == FINISHED_ERUPTING) {
   			state++;
   		}
   	}
   	
   	public boolean isExploding() {
   		return (state == IS_EXPLODING);
   	}

   	public boolean isErupting() {
   		return (state == IS_ERUPTING);
   	}
   
 }
