package powerups;

import models.Activation;
import models.Club;
import models.PowerupModel;
import play.twirl.api.Html;

import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public abstract class Powerup implements Serializable {

    /**
     * Private access as no Powerup should ever be able to change the name of a Club.
     */
    private final Club club;

    /**
     * Final, as no view should ever have access to modify its own model runtime.
     */
    public final PowerupModel model;

    /**
     * Boilerplate constructor used to set up a Powerup. This exposes some vital information for all Powerups.
     * @param club The club referenced by the {@link models.Activation} used to instantiate the Powerup. It is saved
     *             for reference.
     * @param model The model referenced by the {@link models.Activation} used to instantiate the Powerup. It is saved
     *              so that views may access the data held by the model.
     * @see play.db.ebean.Model
     */
    public Powerup(Club club, PowerupModel model) {
        this.club = club;
        this.model = model;
    }

    /**
     * Every powerup must implement a method to render its associated view. For now, only one view may be referenced,
     * though this is likely to change as the API matures.
     * @return The HTML to insert into the club's view.
     * @see views.html.club.show
     * @see play.twirl.api.Html
     */
    public abstract Html render();

    /**
     * Lazily loads the {@link powerups.Powerup} associated with the {@link models.Activation}
     * @param activation The activation used to instantiate the Powerup.
     * @return The instantiated Powerup.
     */
    public static Powerup getPowerup(Activation activation) {
        PowerupModel powerupModel = PowerupModel.find.byId(activation.key.powerupId);
        Club club = Club.find.byId(activation.key.clubId);

        try {
            @SuppressWarnings("unchecked")
            Class<? extends Powerup> c = (Class<? extends Powerup>) Class.forName("powerups." + powerupModel.className);
            Constructor<? extends Powerup> constructor = c.getDeclaredConstructor(Club.class, PowerupModel.class);
            return constructor.newInstance(club, powerupModel);
        } catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

    protected Club getClub() {
        return club;
    }
}

@@ -235,16 +235,719 @@
 ption;%0A%0A
+/**%0A * The class that every Powerup must extend. The nature of a powerup is fickle. Once its class name has been set in its%0A * %7B@link models.PowerupModel%7D, this should never change post production. The class uses lazy loading to read its%0A * model's class name, and thus must be properly set and qualified as documented in the PowerupModel class. Make sure%0A * to properly read example powerups' documentation, as well as this one before attempting to use write a powerup.%0A * As of 1.0-SNAPSHOT, there is no error handling for the powerup activation, so a user will not get any indication%0A * whether this powerup exists if it is not loaded properly.%0A * @since 1.0-SNAPSHOT%0A * @see models.PowerupModel%0A */%0A
 public a
@@ -2555,31 +2555,8 @@
 l = 
-PowerupModel.find.byId(
 acti
@@ -2566,22 +2566,15 @@
 ion.
-key.
 powerup
-Id)
 ;%0A  
@@ -2595,23 +2595,8 @@
 b = 
-Club.find.byId(
 acti
@@ -2606,19 +2606,12 @@
 ion.
-key.
 club
-Id)
 ;%0A%0A 

Improve speed of lazy loader, and further document.