package engine.weapons;

import engine.Cooldown;
import engine.Entity;
import log.IGLog;
import sound.MSound;

import java.util.*;

public class Weapon {

    private static final Map<String, Weapon> map = new HashMap<>();

    private String name;

    private Entity owner;

    private List<MSound> sounds;
    private int soundsCpt;

    private double range;

    private int minDamage;

    private int maxDamage;

    private Cooldown cooldown;


    private Weapon(String name, List<MSound> sounds, double range,
                  int minDamage, int maxDamage, long cooldown) {
        this.name = name;
        owner = null;
        this.sounds = sounds;
        soundsCpt = 0;
        this.range = range;
        this.minDamage = minDamage;
        this.maxDamage = maxDamage;
        this.cooldown = new Cooldown(cooldown);
    }

    private Weapon(Weapon weapon) {
        name      = weapon.name;
        owner     = null;
        sounds    = new LinkedList<>(weapon.sounds);
        soundsCpt = 0;
        range     = weapon.range;
        minDamage = weapon.minDamage;
        maxDamage = weapon.maxDamage;
        cooldown  = new Cooldown(weapon.cooldown.getTime());
    }

    public static void register(String name, Map<String, String> sounds, double range,
                                int minDamage, int maxDamage, long cooldown) {
        if (map.containsKey(name)) {
            throw new IllegalArgumentException("Weapon::register -> " +
                    name + " already registered.");
        }

        if (minDamage > maxDamage) {
            throw new IllegalArgumentException("Weapon::register -> " +
                    name + ", minimal damage < maximal damage."
            );
        }

        LinkedList<MSound> createdSounds = new LinkedList<>();

        for (String key : sounds.keySet()) {
            String path = sounds.get(key);

            try {
                createdSounds.addLast(new MSound(key, path));
            } catch (Exception e) {
                IGLog.error("Unable to load <" + key + "> at \"" + path + "\"");
            }
        }

        map.put(name, new Weapon(name, createdSounds, range, minDamage,
                maxDamage, cooldown));
    }

    public static Weapon make(String name) {
        if (!map.containsKey(name)) {
            throw new IllegalArgumentException("Weapon::make -> " +
                    name + " doesn't exists."
            );
        }

        return new Weapon(map.get(name));
    }

    public static void defaults() {

        /* Punch */
        HashMap<String, String> punchSounds = new HashMap<>();
        punchSounds.put("left-punch", "sounds/left-punch.mp3");
        punchSounds.put("right-punch", "sounds/right-punch.mp3");
        Weapon.register("punch", punchSounds, 10, 1, 2, 1000);

    }

    private void playNextSound() {
        ++soundsCpt;
        if (soundsCpt >= sounds.size())
            soundsCpt = 0;

        if (soundsCpt < sounds.size())
            sounds.get(soundsCpt).play();
    }


    public boolean ready() {
        return cooldown.isReady();
    }


    public Entity getOwner() {
        return owner;
    }

    public void setOwner(Entity owner) {
        this.owner = owner;
    }

    public double getRange() {
        return range;
    }

    public int getMinDamage() {
        return minDamage;
    }

    public int getMaxDamage() {
        return maxDamage;
    }

    public boolean attack(Entity entity) {
        playNextSound();
        cooldown.start();

        if (entity instanceof Attackable) {
            Random random = new Random();
            Attackable a = (Attackable)entity;

            int damage =
                    random.nextInt(
                            (getMaxDamage() - getMinDamage()) + 1
                    ) + getMinDamage();
            return a.takeDamage(damage);
        }

        return false;
    }


}

@@ -75,40 +75,130 @@
 ort 
-log.IGLog;%0Aimport sound.MSound;%0A
+engine.EntityAssociation;%0Aimport engine.Skin;%0Aimport log.IGLog;%0Aimport sound.MSound;%0A%0Aimport java.awt.image.BufferedImage;
 %0Aimp
@@ -536,16 +536,46 @@
 ldown;%0A%0A
+    private Skin weaponSkin;%0A%0A
 %0A    pri
@@ -687,32 +687,49 @@
 e, long cooldown
+, Skin weaponSkin
 ) %7B%0A        this
@@ -965,16 +965,54 @@
 ldown);%0A
+        this.weaponSkin = weaponSkin;%0A
     %7D%0A%0A 
@@ -1060,24 +1060,25 @@
   name      
+ 
 = weapon.nam
@@ -1098,16 +1098,17 @@
 ner     
+ 
 = null;%0A
@@ -1125,16 +1125,17 @@
 unds    
+ 
 = new Li
@@ -1171,32 +1171,33 @@
       soundsCpt 
+ 
 = 0;%0A        ran
@@ -1199,24 +1199,25 @@
   range     
+ 
 = weapon.ran
@@ -1234,24 +1234,25 @@
   minDamage 
+ 
 = weapon.min
@@ -1277,16 +1277,17 @@
 xDamage 
+ 
 = weapon
@@ -1316,16 +1316,17 @@
 oldown  
+ 
 = new Co
@@ -1356,24 +1356,188 @@
 getTime());%0A
+        try %7B%0A            weaponSkin = (Skin)weapon.weaponSkin.clone();%0A        %7D catch (CloneNotSupportedException e) %7B%0A            e.printStackTrace();%0A        %7D%0A
     %7D%0A%0A    p
@@ -1693,16 +1693,24 @@
 cooldown
+, Skin s
 ) %7B%0A    
@@ -2558,16 +2558,19 @@
 cooldown
+, s
 ));%0A    
@@ -3086,32 +3086,269 @@
 ht-punch.mp3%22);%0A
+        Skin skinPunch = new Skin(20,20);%0A        try %7B%0A            BufferedImage%5B%5D c = EntityAssociation.createCharacterFromFile(%22pictures/animation/%22, 7, %22.png%22);%0A            skinPunch = new Skin(c, 4);%0A        %7D catch (Exception e)%7B%7D%0A
         Weapon.r
@@ -3391,16 +3391,27 @@
  2, 1000
+, skinPunch
 );%0A%0A    
@@ -4016,32 +4016,119 @@
 xDamage;%0A    %7D%0A%0A
+    public BufferedImage getNextAnimation() %7B%0A        return weaponSkin.move();%0A    %7D%0A%0A
     public boole
@@ -4204,16 +4204,48 @@
 start();
+%0A        weaponSkin.start(true);
 %0A%0A      

Add a weapon skin.