package common.potion;

import java.util.Map;
import java.util.Map.Entry;

import common.attributes.Attribute;
import common.attributes.AttributeInstance;
import common.attributes.AttributeMap;
import common.attributes.AttributeModifier;
import common.attributes.Attributes;
import common.collect.Maps;
import common.entity.DamageSource;
import common.entity.projectile.EntityPotion;
import common.entity.types.EntityLiving;
import common.init.Config;

public enum Potion {
    SPEED("speed", "Schnelligkeit", "Trank der Schnelligkeit", false, 8171462, new PotionModifier(Attributes.MOVEMENT_SPEED, "PotSpd", 0.2, true)),
    SLOWNESS("slowness", "Langsamkeit", "Trank der Langsamkeit", true, 5926017, new PotionModifier(Attributes.MOVEMENT_SPEED, "PotSlow", -0.15, true)),
    HASTE("haste", "Eile", "Trank der Eile", false, 14270531) {
		public double getEffectiveness() {
			return 1.5;
		}
    },
    FATIGUE("mining_fatigue", "Abbaulähmung", "Trank der Trägheit", true, 4866583),
    STRENGTH("strength", "Stärke", "Trank der Stärke", false, 9643043, new PotionModifier(Attributes.ATTACK_DAMAGE, "PotDmg", 2.5, true)) {
		public double getAmount(int amp, AttributeModifier modifier) {
			return 1.3D * (double)(amp + 1);
		}
    },
    HEAL("instant_health", "Direktheilung", "Trank der Heilung", false, 16262179) {
		public boolean isInstant() {
			return true;
		}
		
		public void onImpact(EntityPotion potion, EntityLiving thrower, EntityLiving entity, int amp, double effect) {
			if(entity.arePotionsInverted()) {
				if(Config.damagePotion) {
					int dmg = (int)(effect * (double)(6 << amp) + 0.5D);
					if(potion == null)
						entity.attackEntityFrom(DamageSource.magic, dmg);
					else
						entity.attackEntityFrom(DamageSource.causeIndirectMagicDamage(potion, thrower), dmg);
				}
			}
			else {
				entity.heal(Math.max((int)(effect * (double)(4 << amp) + 0.5D), 0));
			}
		}
    },
    DAMAGE("instant_damage", "Direktschaden", "Trank des Schadens", true, 4393481) {
		public boolean isInstant() {
			return true;
		}
		
		public void onImpact(EntityPotion potion, EntityLiving thrower, EntityLiving entity, int amp, double effect) {
			if(!entity.arePotionsInverted()) {
				if(Config.damagePotion) {
					int dmg = (int)(effect * (double)(6 << amp) + 0.5D);
					if(potion == null)
						entity.attackEntityFrom(DamageSource.magic, dmg);
					else
						entity.attackEntityFrom(DamageSource.causeIndirectMagicDamage(potion, thrower), dmg);
				}
			}
			else {
				entity.heal(Math.max((int)(effect * (double)(4 << amp) + 0.5D), 0));
			}
		}
    },
    JUMP("jump_boost", "Sprungkraft", "Trank der Sprungkraft", false, 2293580),
    NAUSEA("nausea", "Übelkeit", "Trank der Übelkeit", true, 5578058) {
		public double getEffectiveness() {
			return 0.25;
		}
    },
    REGENERATION("regeneration", "Regeneration", "Trank der Regeneration", false, 13458603) {
		public void onUpdate(EntityLiving entity, int duration, int amp) {
			int k = 50 >> amp;
			if((k <= 0 || duration % k == 0) && entity.getHealth() < entity.getMaxHealth())
				entity.heal(1);
		}

		public double getEffectiveness() {
			return 0.25;
		}
    },
    RESISTANCE("resistance", "Resistenz", "Trank des Widerstandes", false, 10044730),
    FIRE_RESISTANCE("fire_resistance", "Feuerschutz", "Trank der Feuerresistenz", false, 14981690),
    MANA("mana_boost", "Manaschub", "Trank des Manaschubes", false, 3035801) {
		public void onUpdate(EntityLiving entity, int duration, int amp) {
			int k = 40 >> amp;
			if((k <= 0 || duration % k == 0) && entity.getManaPoints() < entity.getMaxMana())
				entity.healMana(1);
		}
    },
    FLYING("flying", "Schweben", "Trank des Schwebens", false, 8356754),
    BLINDNESS("blindness", "Blindheit", "Trank der Blindheit", true, 2039587) {
		public double getEffectiveness() {
			return 0.25;
		}
    },
    NIGHT_VISION("night_vision", "Nachtsicht", "Trank der Nachtsicht", false, 2039713),
    STABILITY("stability", "Stabilität", "Trank der Standfestigkeit", false, 5797459, new PotionModifier(Attributes.KNOCKBACK_RESISTANCE, "PotStbl", 1.0, false)),
    WEAKNESS("weakness", "Schwäche", "Trank der Schwäche", true, 4738376, new PotionModifier(Attributes.ATTACK_DAMAGE, "PotWeak", 2.0, false)) {
		public double getAmount(int amp, AttributeModifier modifier) {
			return (double)(-0.5F * (float)(amp + 1));
		}
    },
    POISON("poison", "Vergiftung", "Trank der Vergiftung", true, 5149489) {
		public void onUpdate(EntityLiving entity, int duration, int amp) {
			int j = 25 >> amp;
			if((j <= 0 || duration % j == 0) && (entity.worldObj.client || Config.damagePoison) && entity.getHealth() > 1)
				entity.attackEntityFrom(DamageSource.magic, 1);
		}

		public double getEffectiveness() {
			return 0.25;
		}
    },
    HEALTH("health_boost", "Extraenergie", "Trank der Extraenergie", false, 16284963, new PotionModifier(Attributes.MAX_HEALTH, "PotHp", 4.0, false)) {
		public void removeModifiers(EntityLiving entity, AttributeMap map, int amp) {
			super.removeModifiers(entity, map, amp);
			if(entity.getHealth() > entity.getMaxHealth())
				entity.setHealth(entity.getMaxHealth());
		}
    },
    ABSORPTION("absorption", "Absorption", "Trank der Absorption", false, 2445989) {
		public void removeModifiers(EntityLiving entity, AttributeMap map, int amp) {
			entity.setAbsorptionAmount(entity.getAbsorptionAmount() - (4 * (amp + 1)));
			super.removeModifiers(entity, map, amp);
		}

		public void addModifiers(EntityLiving entity, AttributeMap map, int amp) {
			entity.setAbsorptionAmount(entity.getAbsorptionAmount() + (4 * (amp + 1)));
			super.addModifiers(entity, map, amp);
		}
    },
    RADIATION("radiation", "Strahlung", "Radioaktiver Trank", true, 0x00ff00) {
		public void onUpdate(EntityLiving entity, int duration, int amp) {
			if(entity.ticksExisted % 20 == 0 && (entity.worldObj.client || Config.damageRadiation)) // && entityLivingBaseIn.getHealth() > 1.0F)
				entity.attackEntityFrom(DamageSource.radiation, 1 + amp);
		}
    };
	
	private static class PotionModifier {
		private final Attribute attribute;
		private final String id;
		private final double value;
		private final boolean multiply;
		
		public PotionModifier(Attribute attr, String id, double value, boolean multiply) {
			this.attribute = attr;
			this.id = id;
			this.value = value;
			this.multiply = multiply;
		}
	}

	private static final Map<String, Potion> LOOKUP = Maps.newHashMap();
    
	private final Map<Attribute, AttributeModifier> modifiers = Maps.<Attribute, AttributeModifier>newHashMap();
	private final String name;
	private final String effectDisplay;
	private final String potionDisplay;
	private final boolean bad;
	private final int color;

	static {
		for(Potion potion : values()) {
			LOOKUP.put(potion.name, potion);
		}
	}

	public static Potion getByName(String name) {
		return LOOKUP.get(name);
	}

	private Potion(String name, String effectDisplay, String potionDisplay, boolean bad, int color, PotionModifier ... modifiers) {
		this.name = name;
		this.bad = bad;
		this.color = color;
		this.effectDisplay = effectDisplay;
		this.potionDisplay = potionDisplay;
		for(PotionModifier modifier : modifiers) {
			this.modifiers.put(modifier.attribute, new AttributeModifier(AttributeModifier.getModifierId(modifier.id), "potion." + name, modifier.value, modifier.multiply));
		}
	}

	public String getName() {
		return this.name;
	}

	public String toString() {
		return this.name;
	}

	public String getDisplay() {
		return this.effectDisplay;
	}

	public String getPotionDisplay() {
		return this.potionDisplay;
	}

	public boolean isBadEffect() {
		return this.bad;
	}

	public int getColor() {
		return this.color;
	}

	public Map<Attribute, AttributeModifier> getModifiers() {
		return this.modifiers;
	}

	public void onUpdate(EntityLiving entity, int duration, int amp) {
	}

	public void onImpact(EntityPotion potion, EntityLiving thrower, EntityLiving entity, int amp, double effect) {
	}

	public boolean isInstant() {
		return false;
	}

	public double getAmount(int amp, AttributeModifier modifier) {
		return modifier.getAmount() * (double)(amp + 1);
	}

	public double getEffectiveness() {
		return this.bad ? 0.5 : 1.0;
	}

	public void removeModifiers(EntityLiving entity, AttributeMap map, int amp) {
		for(Entry<Attribute, AttributeModifier> entry : this.modifiers.entrySet()) {
			AttributeInstance attr = map.getAttributeInstance(entry.getKey());
			if(attr != null)
				attr.removeModifier(entry.getValue());
		}
	}

	public void addModifiers(EntityLiving entity, AttributeMap map, int amp) {
		for(Entry<Attribute, AttributeModifier> entry : this.modifiers.entrySet()) {
			AttributeInstance attr = map.getAttributeInstance(entry.getKey());
			if(attr != null) {
				AttributeModifier mod = entry.getValue();
				attr.removeModifier(mod);
				attr.applyModifier(new AttributeModifier(mod.getID(), "potion." + this.name + " " + amp, this.getAmount(amp, mod), mod.isMultiplied()));
			}
		}
	}
}
