package app.brest.utils.app.brest.game;

import android.app.Activity;
import android.content.Context;
import android.util.Log;

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

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;

import app.brest.testmin3d.ARActivity;
import app.brest.utils.JSONLoader;
import app.brest.utils.ResourceManager;
import app.brest.utils.SensorsManager;
import app.brest.utils.Settings;

/**
 * Created by ptitcois on 19/08/16.
 */
public class Game  implements Serializable {
    private static Game gGame = null;
    protected ArrayList<Area>  mAreas = new ArrayList<Area>();
    protected ArrayList<Area>  mCurrentStageAreas = new ArrayList<Area>();
    protected ArrayList<Stage> mStages = new ArrayList<Stage>();
    protected int              mNStages;
    protected int              mCurrentStage=0;
    protected Player           mPlayer;
    protected ResourceManager  mResources;
    protected String           mName;
    protected Settings         mSettings = new Settings();
    protected boolean          mFinished= false;

    public Game(String name, Activity act)
    {
        JSONObject root = JSONLoader.load(act, name);
        mName=name;
        mPlayer = new Player(act);
        try {
            JSONArray areas = root.getJSONArray("areas");
            JSONArray stages = root.getJSONArray("stages_list");
            for(int i=0; i<areas.length(); i++)
                mAreas.add(new Area(areas.getJSONObject(i), act));
            for(int i=0; i<stages.length(); i++) {
                Stage s = new Stage(stages.getJSONObject(i));
                Resource r = findResource(s.getResourceName());
                s.setResource(r);
                mStages.add(s);
            }
            findMaxStage();
            mResources = new ResourceManager( getAllResources(act), mNStages);
            nextStage();

        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
    public Stage getCurrentStageObj()
    {
        return mCurrentStage<=mStages.size()?mStages.get(mCurrentStage-1):null;
    }

    public Stage getStage(int i)
    {
        return mStages.get(i);
    }

    public Settings getmSettings(){return mSettings;}
    public void setSettings(Settings s){ mSettings=s;}

    public int getNStages() {
        return mNStages;
    }
    public String getName() {
        return mName;
    }

    public int getCurrentStage() {
        return mCurrentStage;
    }

    public void findMaxStage()
    {
        mNStages=0;
        for(int i=0; i<mAreas.size(); i++) {
            if (mAreas.get(i).getStage() > mNStages)
                mNStages = mAreas.get(i).getStage();
        }
    }

    public boolean nextStage()
    {
        mCurrentStage++;
        if(mCurrentStage>mNStages) return true;

        loadStageAreasResources();
        mResources.nextStage(mCurrentStage);

        return false;
    }

    public void loadStageAreasResources()
    {
        mCurrentStageAreas.clear();
        for(int i=0; i<mAreas.size(); i++)
        {
            if(mAreas.get(i).getStage() == mCurrentStage)
                mCurrentStageAreas.add(mAreas.get(i));
        }
    }

    public int currentAreasCount()
    {
        return mCurrentStageAreas.size();
    }

    public Area getAreaStage(int i)
    {
        return mCurrentStageAreas.get(i);
    }

    public void removeArea(String name)
    {
        for(int i=0; i<mCurrentStageAreas.size(); i++)
            if(mCurrentStageAreas.get(i).getName().compareTo(name)==0)
                mCurrentStageAreas.remove(i);
    }

    private void removeArea(int index)
    {
        mCurrentStageAreas.remove(index);
    }

    public boolean pickResource()
    {
        mResources.clearPickedUpResources();
        ArrayList<LocatedResources> r = getResourcesNextToPlayer();
        for(int i=0; i<r.size(); i++) {
            for (int j = 0; j < mCurrentStageAreas.size(); j++) {

                if (r.get(i).getResource(0).getName().compareTo(mCurrentStageAreas.get(j).getName()) == 0 &&
                        r.get(i).getResource(0).getStage() == mCurrentStage) {
                    removeArea(j);
                }
            }
            pickResource(r.get(i).getResource(0).getName());
        }
        return mCurrentStageAreas.size()==0;
    }

    public ArrayList<Resource> getPickedUpResources()
    {
        return mResources.getPickedUpResources();
    }

    public boolean pickResource(String name)
    {

        for (int j = 0; j < mCurrentStageAreas.size(); j++)
            if (name.compareTo(mCurrentStageAreas.get(j).getName())==0) {
                removeArea(j);
            }
        mResources.pickUpResource(name);

        return mCurrentStageAreas.size()==0;
    }

    public void pickAllResoucres()
    {
        mResources.pickAllResoucres();
        mCurrentStage=mNStages;
    }

    public Resource getLatestResource()
    {
        return mResources.getLatestResource();
    }


    public String toString()
    {
        String out = "Game : "+super.toString();
                out+="mAreas[]:\n";
        for(int i=0; i<mAreas.size(); i++)
            out+="\tmAres["+i+"] = "+mAreas.get(i).getJson().toString()+"\n";
        out+="\nmResourcesAcquired[] : \n";
        for(int i=0; i<mResources.getResourceAquiered().size(); i++) {
            out+="\tmResourcesAcquired["+i+"][] : \n";
            for (int j = 0; j < mResources.getResourceAquiered().get(i).size(); j++)
                out += "\t\tmResourcesAcquired[" + i + "]["+j+"] = " + mResources.getResourceAquiered().get(i).get(j).getJson().toString() + "\n";
        }
        out+="mNStages :" +mNStages +"\n";
        out+="mCurrentStage" + mCurrentStage +"\n";
        return out;
    }

    public boolean save(Activity context)
    {
        try {
            FileOutputStream fos = context.openFileOutput("data", Context.MODE_PRIVATE);
            ObjectOutputStream os = new ObjectOutputStream(fos);
                os.writeObject(this);
            os.close();
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
            Log.e("SAVING", "Save failed:"+e.getMessage());
            return false;
        }
        Log.e("SAVING", "Save OK");
        return true;
    }

    public static Game load(Activity context)
    {
        try {
            FileInputStream fis = context.openFileInput("data");
            ObjectInputStream is = new ObjectInputStream(fis);
            Game obj = (Game) is.readObject();
            is.close();
            fis.close();
            return obj;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    public ArrayList<Resource> getAllResources(Activity act)
    {
        ArrayList<Resource> tmp = new ArrayList<Resource>();
        for(int i=0; i<mAreas.size(); i++)
        {
            ArrayList<Resource> c = mAreas.get(i).getResource();
            for(int j=0; j<c.size(); j++)
                if(!tmp.contains(c.get(j)))
                    tmp.add(c.get(j));
        }

        return tmp;
    }

    public static boolean isSaved(Activity context)
    {
        boolean b = false;
        try {
            FileInputStream fis = context.openFileInput("data");
            if(fis!=null)
                b=true;
            fis.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return b;
    }

    public void onPause(Activity context)
    {
        save(context);
        mPlayer.onPause();
        removeCached3DModels();
    }


    public void onResume(ARActivity context)
    {
        mPlayer.onResume(context);
    }

    public void setSensorsManager(SensorsManager sm)
    {
        mPlayer.setSensorsManager(sm);
    }

    public Resource findResource(String name)
    {
        for(int i=0; i<mAreas.size(); i++)
            for(int j=0; j<mAreas.get(i).countResource(); j++)
                if(mAreas.get(i).getResourceNames().get(j).compareTo(name)==0)
                 return mAreas.get(i).getResource(j);
        return null;
    }

    /**
     * Charge la ressource 3d quand on entre dans une zone
     */
    synchronized public boolean precache3DResource(Activity contecxt)
    {
        boolean b =false;
        for(int i=0; i<mAreas.size(); i++)
        {
            if(mAreas.get(i).getStage()==mCurrentStage &&  mAreas.get(i).isOnArea(mPlayer)) {
                b = true;
                ArrayList<Resource> rs = mResources.getResourceLeftByName(mAreas.get(i).getResourceNames());
                try {
                    for (int j = 0; j < rs.size(); j++) {
                        if(rs.get(j)!=null) rs.get(j).get3DModel(contecxt);
                    }

                }catch(Exception e)
                {
                    e.printStackTrace();
                }
            }
        }
        return b;
    }


    /*
     *
     * Fonction principale de positionnnemnt et orientation
     *
     */
    public ArrayList<Area> getAreaNextToPlayer()
    {
        ArrayList<Area> r = new ArrayList<Area>();
        for(int i=0; i<mCurrentStageAreas.size(); i++)
        {
            //probleme de GPS..
            if(mCurrentStageAreas.get(i).isOnArea(mPlayer))
                r.add(mCurrentStageAreas.get(i));

        }
        return r;
    }


    /*
     *
     * Fonction principale de positionnnemnt et orientation
     *
     */
    public ArrayList<LocatedResources> getResourcesNextToPlayer()
    {
        ArrayList<LocatedResources> r = new ArrayList<LocatedResources>();
        for(int i=0; i<mCurrentStageAreas.size(); i++)
        {
            //probleme de GPS..
            boolean b = mCurrentStageAreas.get(i).isOnArea(mPlayer);

            if(b)
            {

                if(i<mCurrentStageAreas.size() && mCurrentStageAreas.get(i).isOnDirection(mPlayer) &&
                        mCurrentStageAreas.get(i).isOnPlace(mPlayer))
                {
                    ArrayList<Resource> rs = mResources.getResourceLeftByName(mCurrentStageAreas.get(i).getResourceNames());
                    r.add(new LocatedResources(
                            rs,
                            mCurrentStageAreas.get(i).getPlace(0)
                    ));
                }
            }
        }
        return r;
    }


    public String getResourcesNextToPlayerDist()
    {
        double min=1000000000;
        ArrayList<Resource> r = new ArrayList<Resource>();
        for(int i=0; i<mCurrentStageAreas.size(); i++)
        {
            //probleme de GPS..
            if(mCurrentStageAreas.get(i).isOnArea(mPlayer))
            {
                if(mCurrentStageAreas.get(i).getDistanceToNextPlace(mPlayer)<min)
                    min=mCurrentStageAreas.get(i).getDistanceToNextPlace(mPlayer);

            }
        }
        if(min>10000000) return " --.- m";
        NumberFormat formatter = new DecimalFormat("#0.0");
        return formatter.format(min)+" m";
    }

    public double getResourcesNextToPlayerDistDouble()
    {
        double min=1000000000;
        ArrayList<Resource> r = new ArrayList<Resource>();
        for(int i=0; i<mCurrentStageAreas.size(); i++)
        {
            //probleme de GPS..
            if(mCurrentStageAreas.get(i).isOnArea(mPlayer))
            {
                if(mCurrentStageAreas.get(i).getDistanceToNextPlace(mPlayer)<min)
                    min=mCurrentStageAreas.get(i).getDistanceToNextPlace(mPlayer);

            }
        }
        if(min>10000000) return -1;
        return min;

    }



    public Player getPlayer()
    {
        return mPlayer;
    }

    public void removeCached3DModels()
    {
        mResources.deleteAll3DModel();
    }

    public void newSensorManager(Activity act)
    {
        mPlayer.newSensorManager(act);
    }

    public ArrayList< ArrayList<Resource> > getResourceByStage()
    {
        return mResources.getResourceAquiered();
    }

    public void restartSensors()
    {
        mPlayer.getSensorsManager().restartSensors();
    }

    public void stopSensors()
    {
        mPlayer.getSensorsManager().stopSensors();
    }
    public void printNResource(String str)
    {
    }


    public static void setGame(Game m)
    {
        gGame=m;
    }

    public static Game game()
    {
        return gGame;
    }


    public boolean canSendData() {
        Stage s =getCurrentStageObj();
        if(s==null) return false;
        return mResources.getNResourceAcquired()>=s.getNResourceStep() && !isFinished();
    }

    public boolean isFinished() { return mFinished; }

    public void finish() { mFinished=true; }

}
