/***********************************************************************************************
	Klassenavn: dog
	Arver: sprite
	Beskrivelse:	styrer gangen til en hund
************************************************************************************************/
import java.awt.*;
import java.applet.*;
import java.awt.image.*;
import java.util.*;
import java.io.*;
import java.net.*;
import java.lang.Math;
import sprite;

public class dog extends sprite {
           
	private final String rawImageName = "doggy.gif";
	private final int totalPics = 12;		// Totalt antall animasjonsbilder
	private final int picWidth = 40;		// Bredden..
	private final int picHeight = 40; 		// ..og høyden på animasjonsbildene
			
	private Image pics[];					// Animasjonsbilder av clifford
	private Image rawImage;				// Animasjonsbilder uoppstykket
	private int picnr = 4;					// Det aktive animasjonsbildet som skal vises 
	private boolean swingUp = true;		// Om armsvingen skal være opp/ned i animasjon
	private int moveStatus = 0;				
	private boolean resetMoves = true;		// true hvis en forandrer retning uten å slippe opp taster
	
	private AudioClip barkSound = null;	// Bjeffe-lyd
	private final int timeBetweenBarks = 800; // Ant. ms bjeffe-lyden varer
	private long timeSinceBark;

	private static Random random;
	
	private int stepsToWalk; // Antall skritt mellom hver retningsforandring (eller stillstand)
	private final int maxStepsToWalk = 100;
	
	private final int leap = 4;			// Antall pixels pr. bevegelse i en vilkårlig retning       

	private Polygon moveLimit;		  		// Begrenser bevegelighet til hunden
		
	private int timeBetweenMoves;		 //	Tidsintervall mellom hver bevegelse i ms 
	private final int maxTimeBetweenMoves = 120;
	private long timeSinceLastMove;							
		
	static {
		random = new Random();
	}
	
	/***********************************************************************************************
		Metodenavn: dog (konstruktør)
		Beskrivelse:	gir hunden en tilfeldig retning/posisjon innenfor bevegelses-polygonet
									henter inn lyd og bilde, og deler bildet i 12 animasjonsbilder
	************************************************************************************************/
	public dog(Polygon p,MediaTracker mt,int mt_id, Graphics g, Applet applet){
		
		parentApplet = applet;
		offScrGC = g;		
		moveLimit = p;
	
		Rectangle r = moveLimit.getBoundingBox();
		
		// Setter hunden et tilfeldig sted innenfor polygonets grenser:
		collision = new Rectangle(13,13,15,15);			
					
		do {
			x_pos = Math.abs(random.nextInt()) % r.width+r.x;
			y_pos = Math.abs(random.nextInt()) % r.height+r.y;
		} while (!insideLimits(x_pos,y_pos));
			
		pics = new Image[totalPics];
		tracker = mt;
		
		barkSound = parentApplet.getAudioClip(parentApplet.getCodeBase(),"bark.au");
		barkSound.play(); barkSound.stop(); // For å starte nedlasting (Netscape venter til lyden skal spilles)

		timeSinceBark = System.currentTimeMillis();	
								
		// Henter inn og deler opp bildet i animasjonsbilder:

		try {
		
			// Henter inn:
			rawImage = parentApplet.getImage(parentApplet.getCodeBase(), rawImageName);
		  tracker.addImage(rawImage, mt_id);
		   		   	
			// Stykker opp:
			for (int i = 0; i < totalPics; i++){
				pics[i] = parentApplet.createImage(new FilteredImageSource(rawImage.getSource(),new CropImageFilter(i*picWidth,0,picWidth,picHeight)) );		 		
				tracker.addImage(pics[i], mt_id);		
			}
		
		} catch (Exception e) {e.printStackTrace();}
		
		timeSinceLastMove = System.currentTimeMillis();
	}
	
	/***********************************************************************************************
		Metodenavn: bark
		Beskrivelse: lager en bjeffelyd
	************************************************************************************************/
	public void bark(){
		if (System.currentTimeMillis() - timeSinceBark > timeBetweenBarks){
			timeSinceBark = System.currentTimeMillis();
			barkSound.play();
		}
	}

	/***********************************************************************************************
		Metodenavn: insideLimits
		Beskrivelse: sjekker om x og y er innenfor spritens kollisjons-polygon
	************************************************************************************************/
	private boolean insideLimits(int x,int y){
		if (moveLimit.inside(x+collision.x, y+collision.y) &&
			  moveLimit.inside(x+collision.x, y+collision.y+collision.height) &&
		    moveLimit.inside(x+collision.x+collision.width, y+collision.y) && 
		    moveLimit.inside(x+collision.x+collision.width, y+collision.y+collision.height)) 
			return true;
		else 	return false;
	}
	
	/***********************************************************************************************
		Metodenavn: checkMoves
		Beskrivelse: bestemmer hundens tilfeldige gange 
	************************************************************************************************/
	public void checkMoves(){
	
		if (!insideLimits(x_pos,y_pos)){ // I de tilfeller der Cliff går over grensen..
			
			switch (moveStatus){
				case 1: do {x_pos++;} while (!insideLimits(x_pos,y_pos)); break;
				case 2: do {x_pos--;} while (!insideLimits(x_pos,y_pos)); break;
				case 3: do {y_pos++;} while (!insideLimits(x_pos,y_pos)); break;
				case 4: do {y_pos--;} while (!insideLimits(x_pos,y_pos)); break;
			}
		}
				
		if (stepsToWalk-- == 0){
			
			if (moveStatus == 0) timeBetweenMoves = Math.abs(random.nextInt()) % maxTimeBetweenMoves+1;
			
			moveStatus = Math.abs(random.nextInt()) % 5;
			
			if (moveStatus != 0)	stepsToWalk = Math.abs(random.nextInt()) % maxStepsToWalk+1;
			else stepsToWalk = Math.abs(random.nextInt()) % maxStepsToWalk/5+1;
		}
				
		switch (moveStatus){	// Sjekker om hunden skal snu eller ikke
			case 1 :	if (!insideLimits(x_pos-leap+2,y_pos)) stepsToWalk = 0; break; // LEFT
			case 2 :	if (!insideLimits(x_pos+leap-2,y_pos)) stepsToWalk = 0; break; // RIGHT
			case 3 :	if (!insideLimits(x_pos,y_pos+2-leap)) stepsToWalk = 0; break; // UP
			case 4 :	if (!insideLimits(x_pos,y_pos-2+leap)) stepsToWalk = 0; break; // DOWN
		}
	}
	

	/***********************************************************************************************
		Metodenavn: walk
		Beskrivelse: animerer hundens gange
	************************************************************************************************/
	public void walk(){
		
		// Returner hvis ingen bevegelse eller ventettid mellom bevegelse ikke er over:
		if (moveStatus == 0 || System.currentTimeMillis() - timeSinceLastMove < timeBetweenMoves) return;	
		
		timeSinceLastMove = System.currentTimeMillis();
		
		switch (moveStatus){
			case 1:	picnr = 7; break;	// VENSTRE
			case 2:	picnr = 1; break;	// HØYRE
			case 3:	picnr = 10; break;	// OPP
			case 4:	picnr = 4; break;	// NED
		}
			

 		if (swingUp == true) picnr++; // Animerer sprite'ns gange
 		else picnr--;
		
		// Sjekker om beina skal svinge fram eller tilbake:
	
		if (picnr % 3 == 0) swingUp = true;
		else if ((picnr+1)% 3 == 0) swingUp = false;
	
		switch (moveStatus){ // Flytter sprite'n
			case 1:	x_pos -= leap; break;	// VENSTRE
			case 2:	x_pos += leap; break;	// HØYRE
			case 3:	y_pos -= leap; break;	// OPP
			case 4:	y_pos += leap; break;	// NED
		}
	}

	/***********************************************************************************************
		Metodenavn: changeCourse
		Beskrivelse: tvinger hunden til skifte retning
	************************************************************************************************/
	public void changeCourse(){stepsToWalk = 0;}
	
	/***********************************************************************************************
		Metodenavn: inBarkRange
		Beskrivelse: sjekker en sprite er innenfor hundens bjefferekkevidde
	************************************************************************************************/
	public boolean inBarkRange(sprite s){

		Rectangle r1 = new Rectangle(collision.x+x_pos,collision.y+y_pos,collision.width,collision.height);
		Rectangle r2 = new Rectangle(s.collision.x+s.x_pos,s.collision.y+s.y_pos,s.collision.width,s.collision.height);

		
		switch (moveStatus){ // Flytter sprite'n
			case 1:	r1.grow(0,18); r1.x -= 60; break;	// VENSTRE
			case 2:	r1.grow(0,18); r1.x += 60; break;  // HØYRE
			case 3:	r1.grow(18,0); r1.y -= 60; break;	// OPP
			case 4:	r1.grow(18,0); r1.y += 60; break;	// NED
		}
 		 
		return r1.intersects(r2);
	} 
	
	
	/***********************************************************************************************
		Metodenavn: draw
		Beskrivelse: tegner hunden til appletens offscreen-bilde
	************************************************************************************************/
	public void draw(){
		offScrGC.drawImage(pics[picnr],x_pos,y_pos,parentApplet);		
	}

} // Class dog