package edu.calpoly.csc480.Wumpus.Agent;

import com.bcurry.www.awt.*;

import edu.calpoly.csc480.Wumpus.Agent.Rule.*;

public class KnowledgeBase
{
	public static int
	 blind = 0, alert = 1, risky = 2,
	 numKnowledgeBases = 3;

	/*
	1: This must occur first, so as to avoid the erroneous association of a
	percept string with the last valid square.
	*/
	public KnowledgeBase() {
		type = alert;

		husks = new Husks();
		husks.setKnowledgeBase(this);
	}

	public final boolean hasAmmo()		{return ammo;}

	public final int getType()				{return type;}

	public final Husks getHusks()			{return husks;}

	public final Path getPath()			{return path;}
	public final Husk getHusk()			{return husk;}

	public final Rule.Perceivable getRule(int type)	{return rules[type];}

	public final ActionValueSystem getCurrentAVS()			{return avs;}
	public final ActionValueSystem.Hunt getHuntingAVS()	{return huntAvs;}
	public final ActionValueSystem.Flee getFleeingAVS()	{return fleeAvs;}

	public void setType(int type) {
		this.type = type;
	}

	public void setAmmo(boolean ammo) {
		this.ammo = ammo;
	}

	public void setCurrentAVS(ActionValueSystem avs) {
		this.avs = avs;
	}

	public void setHusk(Husk husk) {
		if (this.husk != null) {
			this.husk.set(Husk.agent, false);
		}

		this.husk = husk;
		this.husk.setVisited(true);
		this.husk.set(Husk.agent, true);
	}

	public void tell(Theorems.Environs t) {
		huntAvs = new ActionValueSystem.Hunt();
		fleeAvs = new ActionValueSystem.Flee();

		huntAvs.setKnowledgeBase(this);
		fleeAvs.setKnowledgeBase(this);

		rules = new Rule.Perceivable[Rule.Perceivable.numRules];
		rules[Percept.bump]	  = new BumpRule(); // 1
		rules[Percept.stench]  = new StenchRule();
		rules[Percept.breeze]  = new BreezeRule();
		rules[Percept.glitter] = new GlitterRule();
		rules[Percept.scream]  = new ScreamRule();

		for (int rule = 0; rule < rules.length; rule++) {
			rules[rule].setKnowledgeBase(this);
		}

		new OKRule().setKnowledgeBase(this);

		ammo = true;

		path = new Path();
		setCurrentAVS(getHuntingAVS());

		husks.resolveWalls(t.tilesSize);
		husks.resolveExit(t.exitPoint);
	}
	
	public void tell(Theorems.Presence t) {
		husks.resolveDawn(t.dawnPoint);
	}

	public void tell(Percept p) {
		for (int rule = 0; rule < rules.length; rule++) {
			rules[rule].tell(p);
		}
	}

	public Action makeAction() {
		return (type == blind ? makeBlindAction() : avs.makeAction());
	}

	public void tell(Action a) {
		a.tell(this);
	}

	protected int type;

	protected boolean ammo;

	protected Husk husk;
	protected Husks husks;
	protected Path path;
	protected ActionValueSystem avs;
	protected ActionValueSystem.Hunt huntAvs;
	protected ActionValueSystem.Flee fleeAvs;

	protected Rule.Perceivable rules[];

	protected Action makeBlindAction() {
		double luck;
		int drift;

		luck = Math.random();

		if (luck <= 0.25)			{return new Action.Climb();}
		else if (luck <= 0.50)	{return new Action.Grab();}
		else {
			drift = (int)(Math.random() * Direction.numDirections);

			if (luck >= 0.75) {
				Action.Shoot shoot;

				shoot = new Action.Shoot();
				shoot.setDirection(drift);
				return shoot;
			}
			else {
				Action.Move move;

				move = new Action.Move();
				move.setCourse(
				 husks.getHusk(
				  BasicPoint.add(getHusk(), Direction.points[drift])),
				 getHusk()
				);
				return move;
			}
		}
	}
}