package macampcorp.macamp.game.challenges;

import android.app.Activity;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

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

import macampcorp.macamp.activities.HostActivity;
import macampcorp.macamp.exceptions.BadChallengeConfigException;
import macampcorp.macamp.game.Event;
import macampcorp.macamp.game.Game;
import macampcorp.macamp.game.Indice;
import macampcorp.macamp.utils.L;

public abstract class Challenge implements Serializable{

    public static final String CHALLENGE_NULL="null";

    public static int OK =1;
    public static int FAIL=0;
    public static int NO_RESPONSE=-1;
    protected String mType=CHALLENGE_NULL;
    protected String mName="null";
    protected String mGoodMessage="";
    protected String mBadMessage="";

    protected Class  mStartWith = null;
    protected ArrayList<Indice> mIndices = new ArrayList<Indice>();
    protected int mLastIndiceDiscoveredIndex = 0;
    protected int mCharIndex=-1;

    protected ArrayList<Event> mStartEvent = new ArrayList<Event>();
    protected ArrayList<Event> mEndEvent = new ArrayList<Event>();

    protected String mResource;
    protected boolean mIsMandatory=true;
    protected float mPenality=0;

    public Challenge(Game g, JSONObject root, Class start, Activity act)
    {
        mStartWith=start;
        try {
            mType = root.getString("type");
        } catch (JSONException e) {
            e.printStackTrace();
            throw new BadChallengeConfigException("Bad parameter 'type' :  "+e.getMessage());
        }

        try {
            mName = root.getString("name");
        } catch (JSONException e) {
            e.printStackTrace();
            throw new BadChallengeConfigException("Bad parameter 'name' : "+e.getMessage());
        }

        try {
            mResource = root.getString("resource");
            g.registerResource(mResource, act);
        } catch (JSONException e) {
            mResource="error";
            throw new BadChallengeConfigException("Bad parameter 'resource' : "+e.getMessage());
        }


        /**
         * event_start
         */
        try {
            JSONArray arr = root.getJSONArray("event_start");
            for(int i=0; i<arr.length(); i++)
                mStartEvent.add(new Event(arr.getJSONObject(i)));

        } catch (JSONException e) {
        }

        try {
            mStartEvent.add(new Event(root.getJSONObject("event_start")));
        } catch (JSONException e) {
        }

        /**
         * event_start
         */
        try {
            JSONArray arr = root.getJSONArray("event_end");
            for(int i=0; i<arr.length(); i++)
                mEndEvent.add(new Event(arr.getJSONObject(i)));
        } catch (JSONException e) {
        }

        try {
            mEndEvent.add(new Event(root.getJSONObject("event_end")));
        } catch (JSONException e) {
        }

        try {
            JSONArray arr = root.getJSONArray("indices");
            for(int i=0; i<arr.length(); i++)
                mIndices.add(Indice.fromJSONObject(arr.getJSONObject(i)));
        } catch (JSONException e) {
        }

        try {
            mCharIndex = root.getInt("charIndex");
        } catch (JSONException e) {
        }

        try {
            mIsMandatory = root.getBoolean("mandatory");
        } catch(JSONException e){}

        try {
            mPenality = (float)root.getDouble("penality");
        } catch(JSONException e){mPenality=0;}


        try {mGoodMessage = root.getString("good_message"); } catch (JSONException e) {mGoodMessage=null;}
        try {mBadMessage = root.getString("bad_message"); } catch (JSONException e) {mBadMessage=null;}

    }


    public void exec(Game g, HostActivity act)
    {
        act.setFragment(this);
    }

    public String getType() {
        return mType;
    }

    public String getName() {
        return mName;
    }


    public int getCharIndex() {return mCharIndex; }

    public boolean isMandatory() {
        return mIsMandatory;
    }

    public float getPenality() {
        return mPenality;
    }

    public static Class getChallengeClass(String classe)
    {
        try {
            L.debug("Load class : 'macampcorp.macamp.game.challenges."+classe+"'");
            Class cls = Class.forName("macampcorp.macamp.game.challenges."+classe);
            L.debug("Load class : 'macampcorp.macamp.game.challenges."+classe+"' loaded");
            return cls;
        }
        catch(ClassNotFoundException cnfe)
        {
            cnfe.printStackTrace();
            return null;
        }
    }

    public static Constructor<?> getChallengeConstructor(String classe)
    {
        try {
            Class[] type = { Game.class, JSONObject.class, Activity.class };
            return getChallengeClass(classe).getConstructor(type);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static Challenge callChallengeConstructor(String classe, Game g,JSONObject o, Activity a)
    {
        Constructor constr = getChallengeConstructor(classe);
        L.debug("callChallenge : '"+classe+"' ");
        try {
            return ((Challenge) constr.newInstance(g, o, a));
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.getCause().printStackTrace();
            if(e.getCause() instanceof  RuntimeException)
                throw (RuntimeException)e.getCause();
            throw  new RuntimeException("Erreur dans l'invocation du challenge : "+e.getCause().getMessage()+" ("+e.getCause().getClass().toString()+")");
        }
        return null;
    }

    public boolean hasNextIndice()
    {
        int i=0;
        for(i=0; i<mIndices.size(); i++)
            if(!mIndices.get(i).isDiscovered())
                return true;
        return false;
    }

    public Indice peakNextIndice()
    {
        int i=0;
        for(i=0; i<mIndices.size(); i++)
            if(!mIndices.get(i).isDiscovered())
                return mIndices.get(i);
        return null;
    }

    public Indice nextIndice()
    {
        int i=0;
        for(i=0; i<mIndices.size(); i++)
            if(!mIndices.get(i).isDiscovered())
                return mIndices.get(mLastIndiceDiscoveredIndex=i);
        mLastIndiceDiscoveredIndex=-1;
        return null;
    }

    public int getIndiceIndex(){
        return mLastIndiceDiscoveredIndex;
    }

    public ArrayList<Indice> getIndices() { return mIndices; }

    public String getResourceName() {
        return mResource;
    }

    public ArrayList<Event> getStartEvent() {
        return mStartEvent;
    }

    public ArrayList<Event> getEndEvent() {
        return mEndEvent;
    }

    public Class getStartWith(){
        return mStartWith;
    }

    public String getGoodMessage() {
        return mGoodMessage;
    }

    public String getBadMessage() {
        return mBadMessage;
    }
}
