package edu.calpoly.csc480.Wumpus.Agent;

import java.util.*;

import edu.calpoly.csc480.Wumpus.Area.*;
import edu.calpoly.csc480.Wumpus.Tile.*;

public abstract class ActionRule
{
	public static class Grab extends ActionRule {
		public Grab() {
			grab = new Action.Grab();
		}

		public boolean test() {
			return kb.getHusk().getFact(Fact.gold).isTrue();
		}

		public Action make()		{return grab;}

		protected Action.Grab grab;
	}

	public static class Climb extends ActionRule {
		public Climb() {
			climb = new Action.Climb();
		}

		public boolean test() {
			return kb.getHusk().getFact(Fact.exit).isTrue();
		}

		public Action make()		{return climb;}

		protected Action.Climb climb;
	}

	public static class Shoot extends ActionRule {
		public Shoot() {
			shoot = new Action.Shoot();
		}

		public boolean test()	{
			if (kb.hasAmmo()) {
				for (int drift = 0; drift < Direction.numDirections; drift++) {
					if (
					 kb.getHusks().getHusk(drift, kb.getHusk()).
					 getFact(Fact.wumpus).isTrue()) {
						shoot.setDirection(drift);
						return true;
					}
				}
			}

			return false;
		}

		public Action make()		{return shoot;}

		protected Action.Shoot shoot;
	}

	public static abstract class Move extends ActionRule {
		public Move() {
			move = new Action.Move();
			lastMove = new Action.Move();
		}

		public boolean test() {
			Action.Flee flee;
			Husk near;

			for (int drift = 0; drift < Direction.numDirections; drift++) {
				near = kb.getHusks().getHusk(drift, kb.getHusk());

				if (test(near)) {
					flee = (Action.Flee)kb.getHuntingAVS().getFleeMove().make();

					move.setCourse(near, kb.getHusk());
					lastMove.setCourse(flee.getSource(), flee.getTarget());

					return (
					 kb.getPath().contains(move) == false &&
					 move.equals(lastMove) == false
					);
/*
					if (move.equals(lastMove)) {
						return false;
					}
					else {
						lastMove.setCourse(move.getTarget(), move.getSource());
						return true;
					}
*/				}
			}

			return false;
		}

		public Action make()		{return move;}

		protected Action.Move move, lastMove;

		protected abstract boolean test(Husk near);
	}

	public static class HuntMove extends ActionRule.Move {
		protected boolean test(Husk near) {
			return (
				near.getFact(Fact.ok).isTrue() &&
				!near.isVisited()
			);
		}
	}

	public static class EchoMove extends ActionRule.Move {
		public EchoMove() {
			move = new Action.Move();
		}

		protected boolean test(Husk near) {
			return (
				near.getFact(Fact.ok).isTrue() &&
				near.isVisited()
			);
		}

		protected Action.Move move;
	}

	public static class RiskMove extends ActionRule.Move {
		public boolean test() {
			return (kb.getType() == kb.risky ? super.test() : false);
		}

		protected boolean test(Husk near) {
			return near.getFact(Fact.ok).isFuzzy();
		}
	}

	public static class FleeMove extends ActionRule {
		public FleeMove() {
			flee = new Action.Flee();
		}

		public boolean test() {
			Action.Move last, copy;

			if (kb.getPath().peek() != null) {
				last = kb.getPath().pop();
				flee.setCourse(last.getSource(), last.getTarget());
				return true;
			}

			return false;
		}

		public Action make() {return flee;}

		protected Action.Flee flee;
	}

	public ActionRule() {
	}

	public void setKnowledgeBase(KnowledgeBase kb) {
		this.kb = kb;
	}

	public abstract boolean test();
	public abstract Action make();

	protected KnowledgeBase kb;
}