package dk.itu.mario.level;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import dk.itu.mario.level.matcher.ProfileMatcher.SKILL;

public class PlayerProfile {
	// From Bartle/Yee models of player psychology: achiever, killer, explorer,
	// manipulator
	public enum TYPE {
		BUMPER, COLLECTOR, RUNNER, SHOOTER, JUMPER
	}

	/*
	 * Certain probabilities are boosted by this constant based on the player's
	 * type.
	 */
	public static final double TYPE_MULTIPLIER = 1.25;

	public enum ChallengeRewardType {
		GAP, ENEMY, HARDER_ENEMY, JUMP, COIN, BLOCK, POWERUP
	};

	// Dreyfus model of skill acquisition:
	public enum SKILL_LEVEL {
		NOVICE, BEGINNER, COMPETENT, PROFICIENT, EXPERT
	}

	private Set<LevelComponent.TYPE> enabledComponents = new HashSet<LevelComponent.TYPE>();

	private SKILL_LEVEL skillLevel;
	private Map<SKILL, Integer> skillVector;
	private TYPE type;

	public PlayerProfile(SKILL_LEVEL skillLevel, TYPE type,
			Map<SKILL, Integer> skillVector) {
		this.skillLevel = skillLevel;
		this.type = type;
		this.skillVector = skillVector;
		for (LevelComponent.TYPE lcType : LevelComponent.TYPE.values()) {
			setEnabled(lcType);
		}
	}

	public boolean isEnabled(LevelComponent.TYPE type) {
		return enabledComponents.contains(type);
	}

	public SKILL_LEVEL getSkillLevel() {
		return skillLevel;
	}

	public int getJumpSkill() {
		switch (type) {
		case JUMPER:
			switch (skillLevel) {
			case NOVICE:
				return 20;
			case BEGINNER:
				return 40;
			case COMPETENT:
				return 60;
			case PROFICIENT:
				return 80;
			case EXPERT:
				return 100;
			default:
				return 0;
			}
		default:
			return 0;
		}
	}

	public double getProbability(ChallengeRewardType crt) {
		// if (!isEnabled(type)) {
		// return 0.0;
		// }
		
		switch (crt) {
		case GAP:
			return Math.min(.5, (.5) * (skillVector.get(SKILL.JUMP) / 100.0)
					* ((type == TYPE.JUMPER) ? TYPE_MULTIPLIER : 1));
		case ENEMY:
			double skillSet = ((100 - skillVector.get(SKILL.RUN)) / 100.0)
					* ((type == TYPE.RUNNER) ? -1 * TYPE_MULTIPLIER : 1);
			skillSet += (skillVector.get(SKILL.STOMP) / 100.0);
			skillSet /= 2;
			return Math.min(.5, (.5) * skillSet);
		case HARDER_ENEMY:
			return Math.min(.5, (.5) * (skillVector.get(SKILL.SHOOT) / 100.0)
					* ((type == TYPE.SHOOTER) ? TYPE_MULTIPLIER : 1));
		case JUMP:
			return Math.min(.5, (.5) * (skillVector.get(SKILL.JUMP) / 100.0)
					* ((type == TYPE.JUMPER) ? TYPE_MULTIPLIER : 1));
		case BLOCK:
			return Math.min(.5, (.5) * (skillVector.get(SKILL.BUMP) / 100.0)
					* ((type == TYPE.BUMPER) ? TYPE_MULTIPLIER : 1));
		case COIN:
			return Math.min(.5, (.5) * (skillVector.get(SKILL.COLLECT) / 100.0)
					* ((type == TYPE.COLLECTOR) ? TYPE_MULTIPLIER : 1));
		case POWERUP:
			double skillMod = 0;
			switch (skillLevel) {
			case BEGINNER:
				skillMod = .8;
				break;
			case COMPETENT:
				skillMod = .6;
				break;
			case PROFICIENT:
				skillMod = .4;
				break;
			case EXPERT:
				skillMod = .2;
				break;
			default:
				skillMod = 1;
			}

			skillMod = (skillMod + (skillVector.get(SKILL.SHOOT) / 100.0)) / 2.0;

			return (.3) * skillMod;
		default:
			return 0.1;
		}
	}

	public TYPE getType() {
		return type;
	}

	public void setDisabled(LevelComponent.TYPE type) {
		if (enabledComponents.contains(type)) {
			System.out.println("Component type disabled: " + type);
			enabledComponents.remove(type);
		}
	}

	public void setEnabled(LevelComponent.TYPE type) {
		if (!enabledComponents.contains(type)) {
			System.out.println("Component type enabled: " + type);
			enabledComponents.add(type);
		}
	}

	@Override
	public String toString() {
		return skillLevel + " " + type;
	}
}
