﻿/*
Creature class used to handle logic of a single entity moving around on the map.
Requires that the Google Map API be loaded
*/

function Creature() {

}

//Constructor
Creature.prototype.init = function(point, name) {
    this._name = name;
    this._curPoint = point;
    this._distanceToTarget = 7;
    this._targetPoint = null;
    this._nextPoint = null;
    this._isAttacking = false;
    this._health = this.constructor.maxHealth;
    this._isDead = false;
    this._polyPath = null;
    this._curPolyVertex = 1;
    this.loadingDirections = true;
    this.loadingDirectionsCount = 0;
	this.targetBaseKey = null;
	
    this.onReachedTarget = new YAHOO.util.CustomEvent("onReachedTarget", this);
    this.onChangeIcon = new YAHOO.util.CustomEvent("onChangeIcon", this);
    this.onKilled = new YAHOO.util.CustomEvent("onKilled", this);
    this.onExploded = new YAHOO.util.CustomEvent("onExploded", this);
    this.onMap = false;
    this.effects = new Object();
}


//Static properties
Creature.imgHealth100 = "http://labs.ribaudio.com/herosquad/img/v2/health100.png";
Creature.imgHealth75 = "http://labs.ribaudio.com/herosquad/img/v2/health075.png";
Creature.imgHealth50 = "http://labs.ribaudio.com/herosquad/img/v2/health050.png";
Creature.imgHealth25 = "http://labs.ribaudio.com/herosquad/img/v2/health025.png";
Creature.uniqueCount = 0; //Counter used to generate images with unique id's to overcome a bug where gif's with the same url load at the same time

//Must use a function here to generate a new explode gif every time
Creature.getExplodeIcon = function()
{
	var explodeIcon = new GIcon(G_DEFAULT_ICON);
	explodeIcon.shadow = "";
	explodeIcon.image = "http://labs.ribaudio.com/herosquad/img/explode.gif?"+(++Creature.uniqueCount);
	explodeIcon.iconSize = new GSize(40, 40);
	explodeIcon.iconAnchor = new GPoint(20, 30);
	return explodeIcon;
}

//Static directions client
Creature.directionsClientLoadListener = null;
Creature.loadingDirections = false;
Creature.directionsClient = new GDirections(null, document.getElementById("directions"));
Creature.directionsOptions = { getPolyline: true, travelMode: G_TRAVEL_MODE_WALKING, preserveViewport: true, avoidHighways: true };

Creature.onDirectionsLoad = function() {
    //Refresh the poly that has vetor information to reach the target
    this._polyPath = Creature.directionsClient.getPolyline();
    //console.log("directions loaded, vertex count: " + this._polyPath.getVertexCount());
    this._curPolyVertex = 1;
    this.moveTowardsCurrentVertex();
    //Update marker on maps
    this.marker.setLatLng(this._curPoint);
	if(this.smallMarker)
    	this.smallMarker.setLatLng(this._curPoint);
	this.setMarkerWalking();
    Creature.loadingDirections = false;
    this.loadingDirections = false;
}

Creature.onDirectionsError = function() {
    if(console)console.log("Error with directions: " + JSON.stringify(Creature.directionsClient.getStatus()));
    if (Creature.directionsClient.getStatus().code == G_GEO_UNKNOWN_DIRECTIONS) {
		this.loadingDirections = false;
		if(console)console.log("Killing off: " + this._name);
        //spawned in a bad spot,sorry fella
        this.setIsDead(true);
    }

    Creature.loadingDirections = false;
}


//Move the creature towards the target final destination by getting a new direction
Creature.prototype.moveTowardsPoint = function(point) {
    //Only make another call if the first one completed
	if (Creature.loadingDirections == false) {
        Creature.loadingDirections = true;
        this.loadingDirections = true;
        GEvent.clearInstanceListeners(Creature.directionsClient);
        
        Creature.directionsClientLoadListener = GEvent.bind(Creature.directionsClient, "load", this, Creature.onDirectionsLoad);
        Creature.directionsClientErrorListener = GEvent.bind(Creature.directionsClient, "error", this, Creature.onDirectionsError);
        Creature.directionsClient.loadFromWaypoints([this.lat() + ", " + this.lng(), point.lat() + ", " + point.lng()], Creature.directionsOptions);
    }
}

//Moves the creature towards their currently set vertex
//TODO: optimize this more
Creature.prototype.moveTowardsCurrentVertex = function() {
    //Get the next step on the route based on the vertex.
	this._nextPoint = this._polyPath.getVertex(this._curPolyVertex);
	
	//Check to see how far distance is so we don't overshoot
    if (this._curPolyVertex < this._polyPath.getVertexCount() && this._curPoint.equals(this._nextPoint)) {
        //console.log(this._name + "'s distance is 0, skipping to next polyVertex");
		this._curPolyVertex++;
        this._nextPoint = this._polyPath.getVertex(this._curPolyVertex);
    }
	
	var y = this._nextPoint.lat() - this.lat();
    var x = this._nextPoint.lng() - this.lng();
    var distance = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
    
    if (distance <= this.moveAmount) {
		//If the new spot is reached, increment the current poly vertex
		//console.log("Distance is less than moveamount"); 
		this._curPoint = this._nextPoint;
		this._curPolyVertex++;
	}
	else {
		var yMove = parseFloat((y / distance) * this.moveAmount);
		var xMove = parseFloat((x / distance) * this.moveAmount);
		this._curPoint = this._curPoint.transform(yMove, xMove);
	}
	

    if (this._curPolyVertex >= this._polyPath.getVertexCount()) {
        //If the creature reached their target, clear the target and poly and fire onReachedTarget
        this.onReachedTarget.fire();
        this.performActionAtTarget();
        this._targetPoint = null;
        this._polyPath = null;
        this._curPolyVertex = 1;
    }
}

Creature.prototype.lat = function() {
    return parseFloat(this._curPoint.lat());
}

Creature.prototype.lng = function() {
    return parseFloat(this._curPoint.lng());
}

Creature.prototype.point = function() {
    return this._curPoint;
}

//////////////////////RUN
//Move based on the creature's target point
Creature.prototype.run = function() {
    //Remove effects
    for (eff in this.effects)
        if (new Date().getTime() >= this.effects[eff]) {
        switch (eff) {
            case "slow": this.moveAmount = this.constructor.baseMoveAmount;
                break;
        }
        delete this.effects[eff];
    }
	
	//If loading directions, keep waiting for them to be loaded, otherwise move towards vertex
	if (this._targetPoint) {
		if (this.loadingDirections) {
			this.loadingDirectionsCount++;
			if (this.loadingDirectionsCount >= 30 && !Creature.loadingDirections) {
				//console.log(this._name + " is calling for directions again");
				this.moveTowardsPoint(this._targetPoint);
				this.loadingDirectionsCount = 0;
			}
		} else {
				this.moveTowardsCurrentVertex();
				if(this.smallMarker)
					this.smallMarker.setLatLng(this._curPoint);
				
				//Only update the main map marker if they are visible
				if(this.onMap)
					this.marker.setLatLng(this._curPoint);
		}
	}
}

Creature.prototype.toString = function() {
    return this._name + " is at " + this.lat() + ", " + this.lng();
}

Creature.prototype.name = function() {
    return this._name;
}

Creature.prototype.takeDamage = function(amount) {
    this._health -= amount;
    if (this._health <= 0) {
        this.onKilled.fire();
		this.setIsDead(true);
    }
    else {
        this.updateMarker();
    }
}

Creature.prototype.setIsDead = function(isDead)
{
	if(isDead){
		//Clear out properties
		this.onReachedTarget.unsubscribeAll();
    	this.onChangeIcon.unsubscribeAll();
    	this.onKilled.unsubscribeAll(); 
    	this.onExploded.unsubscribeAll();
	    this._polyPath = null;
		this._isDead = true;
	}
	else
	{
		this._isDead = false;
	}
		
}

Creature.prototype.getCurHealthImage = function() {
    var healthImage = "";
    //Don't add health layer if this is a player
    if (!(this.constructor == Player)) {
        healthRatio = this._health / this.constructor.maxHealth;
        if (healthRatio > 0.75) {
            healthImage = Creature.imgHealth100;
        } else if (healthRatio > 0.50) {
            healthImage = Creature.imgHealth75;
        } else if (healthRatio > 0.25) {
            healthImage = Creature.imgHealth50;
        }
        else {
            healthImage = Creature.imgHealth25;
        }
    }

    return healthImage;
}

Creature.prototype.isDead = function() {
    return this._isDead;
}

Creature.prototype.setMarkerStanding = function() {
    oldMarker = this.marker;
    //Makes a call to the static properties of its class
    var newIcon = new GIcon(this.constructor.standingIcon, this.getCurHealthImage());
    this.marker = new GMarker(this._curPoint, { icon: newIcon, title: this._name });
    this.onChangeIcon.fire(oldMarker);
}

Creature.prototype.setMarkerWalking = function() {
    oldMarker = this.marker;
    //Makes a call to the static properties of its class
    var newIcon = new GIcon(this.constructor.walkingIcon, this.getCurHealthImage());
    this.marker = new GMarker(this._curPoint, { icon: newIcon, title: this._name, zIndexProcess: function(){return -50;} });
    this.onChangeIcon.fire(oldMarker);
}

Creature.prototype.updateMarker = function() {
    oldMarker = this.marker;
    newIcon = new GIcon(this.marker.getIcon(), this.getCurHealthImage());
    this.marker = new GMarker(this._curPoint, { icon: newIcon, title: this._name, zIndexProcess: function(){return -50} });
    this.onChangeIcon.fire(oldMarker);
}

Creature.prototype.slowSpeed = function(slowDivider, effectDuration) {
    for (eff in this.effects) {
        //If they are already slowed
        if (eff == "slow") {
           this.effects[eff] = new Date().getTime() + effectDuration;
           return;
        }
    }
    //Otherwise reduce move amount and slow
    this.moveAmount = (this.moveAmount / slowDivider);
    this.effects["slow"] = new Date().getTime() + effectDuration;
}