package hypernova;

import java.util.Properties;

import org.apache.log4j.Logger;

public class Weapon {
    public static final double DEFAULT_COOLDOWN = 3.0;
    public static final double DEFAULT_MASS = 1.0;
    public static final String DEFAULT_AMMO = "bolt";
    public static final int DEFAULT_CHANNEL = 0;
    public static final int DEFAULT_NOTE = 40;
    public static final int DEFAULT_VOLUME = 75;

    public final String name, info;

    private double cooldown, timeout;
    private double mass;
    private Ammo ammo;
    private int channel, note, volume;

    private static Logger log = Logger.getLogger("Weapon");

    protected Weapon(String name, String info) {
        this.name = name;
        this.info = info;
    }

    public static Weapon get(String name) {
        String filename = "parts/" + name + ".weapon";
        log.debug("Loading weapon '" + name + "' (" + filename + ")");
        Properties props = new Properties();
        try {
            props.load(Weapon.class.getResourceAsStream(filename));
        } catch (java.io.IOException e) {
            /* TODO handle this more gracefully. */
            log.error("Failed to load weapon '" + name + "': "
                      + e.getMessage());
            return null;
        }

        Weapon weapon = new Weapon(props.getProperty("name"),
                                   props.getProperty("info"));
        weapon.cooldown = attempt(props, "cooldown", DEFAULT_COOLDOWN);
        weapon.mass = attempt(props, "mass", DEFAULT_MASS);
        weapon.channel = (int) Weapon.attempt(props, "channel",
                                              DEFAULT_CHANNEL);
        weapon.note = (int) Weapon.attempt(props, "note", DEFAULT_NOTE);
        weapon.volume = (int) Weapon.attempt(props, "volume", DEFAULT_VOLUME);
        String ammoname = props.getProperty("ammo");
        if (ammoname == null)
            ammoname = DEFAULT_AMMO;
        weapon.ammo = Ammo.get(ammoname);
        return weapon;
    }

    public static double attempt(Properties ps, String prop, double def) {
        String str = ps.getProperty(prop);
        if (str == null)
            return def;
        try {
            return Double.parseDouble(str);
        } catch (NumberFormatException e) {
            log.warn("Invalid property value for '" + prop + "'");
            return def;
        }
    }

    public void fire(Mass src) {
        if (timeout <= 0) {
            Sound.play(channel, note, volume);
            Hypernova.universe.add(ammo.copy(src));
            timeout = cooldown;
        }
    }

    public double getMass() {
        return mass;
    }

    public void step(double t) {
        timeout -= t;
    }
}

@@ -13,16 +13,64 @@
 rnova;%0A%0A
+import java.util.Map;%0Aimport java.util.HashMap;%0A
 import j
@@ -90,16 +90,16 @@
 erties;%0A
-
 %0Aimport 
@@ -615,16 +615,94 @@
 olume;%0A%0A
+    private static Map%3CString, Weapon%3E cache = new HashMap%3CString, Weapon%3E();%0A
     priv
@@ -902,24 +902,115 @@
 ing name) %7B%0A
+        Weapon weapon = cache.get(name);%0A        if (weapon != null) return weapon.copy();%0A
         Stri
@@ -1484,39 +1484,32 @@
      %7D%0A%0A        
-Weapon 
 weapon = new Wea
@@ -1539,23 +1539,16 @@
 name%22),%0A
-       
         
@@ -2165,24 +2165,57 @@
 (ammoname);%0A
+        cache.put(name, weapon);%0A
         retu
@@ -2223,16 +2223,23 @@
 n weapon
+.copy()
 ;%0A    %7D%0A
@@ -2912,24 +2912,24 @@
 double t) %7B%0A
-
         time
@@ -2943,11 +2943,302 @@
 t;%0A    %7D
+%0A%0A    public Weapon copy() %7B%0A        Weapon weapon = new Weapon(name, info);%0A        weapon.ammo = ammo;%0A        weapon.mass = mass;%0A        weapon.cooldown = cooldown;%0A        weapon.channel = channel;%0A        weapon.note = note;%0A        weapon.volume = volume;%0A        return weapon;%0A    %7D
 %0A%7D%0A

Implement weapon caching.