package app.brest.testmin3d;
import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;

import app.brest.app.brest.ui.CameraPreview;
import app.brest.utils.app.brest.game.Area;
import app.brest.utils.app.brest.game.Game;
import app.brest.utils.app.brest.game.LocatedResources;
import app.brest.utils.app.brest.game.Place;
import app.brest.utils.app.brest.game.Resource;
import app.brest.utils.app.brest.game.Stage;
import app.brest.utils.geometry.GPSPoint;
import min3d.core.Object3d;
import min3d.core.Object3dContainer;
import min3d.core.RendererActivity;
import min3d.vos.CameraVo;
import min3d.vos.Light;
import min3d.vos.Number3d;


public class ARActivity extends RendererActivity
{

    private CameraPreview mImageSurfaceView;
    private Camera camera;
    private FrameLayout cameraPreviewLayout;

    private Object3dContainer faceObject3D;
    private Button mOkButton;
    private final Object mLock = new Object();
    protected boolean isPausing=false;
    protected static GPSPoint mLocation;
    protected static boolean mLocationUpdated=false;
    protected TextView mTvDistance;
    protected TextView mTvAngle;
    protected TextView mTvGPS;
    protected RelativeLayout mRlRoot;
    protected ImageView mIvWhite;
    protected ImageView mIvRed;
    protected ImageView mIvGreen;
    protected ImageView mIvNone;
    protected int mViewWidth;
    protected int mViewHeight;
    protected boolean mDetect=false;
    protected boolean mInArea=false;
    private Game mGame;
    private  Boolean  mUpdate = true;
    private Handler mCustomHandler = new Handler();

    public void init()
    {
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);



        cameraPreviewLayout = (FrameLayout)findViewById(R.id.camera_preview);
        Log.e("____", "Camera:");
        camera = checkDeviceCamera();
        mImageSurfaceView = new CameraPreview(ARActivity.this, camera);


        mOkButton = (Button) findViewById(R.id.button_catch);
        mOkButton.setVisibility(View.INVISIBLE);
        if(cameraPreviewLayout.getChildCount()<2)
        {
            cameraPreviewLayout.addView(_glSurfaceView,0);
            cameraPreviewLayout.addView(mImageSurfaceView,0);
        }

    }

    private Camera checkDeviceCamera() {
        Camera mCamera = null;
        try {
            mCamera = Camera.open();
            Log.e("____", "Camera OK "+mCamera);

        } catch (Exception e) {
            Log.e("____", "Camera Fail "+mCamera);
            e.printStackTrace();
        }
        return mCamera;
    }

    protected void onCreateSetContentView()
    {
        //init();

    }

    @Override
    protected void glSurfaceViewConfig()
    {
        // !important
        _glSurfaceView.setEGLConfigChooser(8,8,8,8, 16, 0);
        _glSurfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
    }

    @Override
    public void initScene()
    {
        // !important
        scene.clear();
        scene.backgroundColor().setAll(0x00000000);
        //scene.lights().add(new Light());
        //scene.lights().add(new Light());

        Light myLight = new Light();
        myLight.position.setZ(150);
        myLight.position.setY(150);
        scene.lights().add(myLight);


        //IParser myParser = Parser.createParser(Parser.Type.OBJ, getResources(), "app.brest.testmin3d:raw/face_obj", true);
        //myParser.parse();



    }

    protected Number3d pos(float deltaAngle, int _radius)
    {
        float radius = _radius;
        return new Number3d((float)(radius*Math.sin(deltaAngle)),
                            0,
                            (float)(15+radius*Math.cos(deltaAngle))
                        );
    }

    private Runnable updateTimerThread = new Runnable() {

        public void run() {
            mCustomHandler.postDelayed(this, 10);
        }

    };

    protected long mLedPeriode=0;
    protected long mLedLastTick=0;
    protected boolean mLedState=false;
    protected void updateLed(boolean detected,  double dist)
    {
        //si detecte
        if(detected)
        {
            mIvWhite.getHandler().post(new Runnable() { public void run() {mIvWhite.setVisibility(View.VISIBLE);}});
            mIvGreen.getHandler().post(new Runnable() { public void run() {mIvGreen.setVisibility(View.VISIBLE);}});
            mIvRed.getHandler().post(new Runnable() { public void run() {mIvRed.setVisibility(View.INVISIBLE);}});
            mInArea=mDetect=true;
        }
        //si dans une zone
        else if(dist>=0)
        {
            if(dist<5) mLedPeriode=5;
            else if(dist>=5 && dist<50) mLedPeriode=(int)((dist-4)*10);
            else mLedPeriode=500;
            if(System.currentTimeMillis()>mLedLastTick+mLedPeriode)
            {
                mLedLastTick=System.currentTimeMillis();
                if(mLedState)
                {
                    mLedState=false;
                    mIvWhite.getHandler().post(new Runnable() { public void run() {mIvWhite.setVisibility(View.INVISIBLE);}});
                }else
                {
                    mLedState=true;
                    mIvWhite.getHandler().post(new Runnable() { public void run() {mIvWhite.setVisibility(View.VISIBLE);}});
                }
            }

            mIvGreen.getHandler().post(new Runnable() { public void run() {mIvGreen.setVisibility(View.INVISIBLE);}});
            mIvRed.getHandler().post(new Runnable() { public void run() {mIvRed.setVisibility(View.VISIBLE);}});
            mInArea=true;
            mDetect=false;
        }
        //si rien
        else
        {
            mIvWhite.getHandler().post(new Runnable() { public void run() {mIvWhite.setVisibility(View.INVISIBLE);}});
            mIvGreen.getHandler().post(new Runnable() { public void run() {mIvGreen.setVisibility(View.INVISIBLE);}});
            mIvRed.getHandler().post(new Runnable() { public void run() {mIvRed.setVisibility(View.INVISIBLE);}});
            mInArea=mDetect=false;
        }
    }
    float x = 0;
    protected boolean updateSceneResource()
    {

        ArrayList<LocatedResources> res = mGame.getResourcesNextToPlayer();
        String toDisplay ="";
        float vX =0;
        boolean detected = false;
       // String dete = "Detected:\n";
        scene.clear();

        if(mGame.getmSettings().isAreaDebug())
        {
            ArrayList<Area> ar = mGame.getAreaNextToPlayer();
            String ttxt = "Zones trouvées:\n";
            for(int i=0; i<ar.size(); i++)
                ttxt+="\t"+ar.get(i).getName()+"\n";
            toDisplay+=ttxt+"\n";

        }

        if(mGame.getmSettings().isAreaDebug()) toDisplay+="Resources détectées: \n";

        if(mGame.getmSettings().isARMode()) {
            for (int i = 0; i < res.size(); i++) {
                Resource rr = res.get(i).getResource(0);
                Place p = res.get(i).getPlace();
                if (rr != null) {
                    detected = true;
                    Object3d oo = rr.get3DModel(this);
                    CameraVo v = new CameraVo();
                    double distCoef = (p.getDistance(mGame.getPlayer()) / 50) * 0.8;
                    distCoef += 0.2;
                    if (distCoef > 1) distCoef = 1.0;

                    double theta = -(-mGame.getPlayer().getOrientationY() + 135 - (0.5 * Math.atan(p.getDistance(mGame.getPlayer()) / 1.6) * 180 / Math.PI) % 360);
                    while (theta < -180) theta += 360;
                    while (theta > 180) theta -= 360;

                    oo.position().y = -25 + (float) (50 * Math.sin(-theta * Math.PI / 180.0));

                    double alpha = ((float) (mGame.getPlayer().getAngleWith(p) - mGame.getPlayer().getOrientationX())) - mGame.getPlayer().getOrientationZ();
                    oo.position().z = -20;//(float)(90*distCoef*Math.cos(alpha*Math.PI/180.0));
                    oo.position().x = -(float) (90 * distCoef * Math.sin(alpha * Math.PI / 180.0));

                    if (mGame.getmSettings().isAreaDebug()) {

                        toDisplay += "Azimuth: " + dts(alpha) + "°\nPosition (" + dts(oo.position().x) + ", " + dts(oo.position().y)
                                + ", " + dts(oo.position().z) + ")\n\n";
                    }

                    vX = (float) (mGame.getPlayer().getAngleWith(p));
                    scene.camera(v);
                    scene.addChild(oo);
                }
            }
        }
        updateLed(detected, mGame.getResourcesNextToPlayerDistDouble());



        //affichage en debug
        final String td = toDisplay;
        final TextView xv = (TextView)findViewById(R.id.text_area);
        xv.getHandler().post(new Runnable() { public void run() { xv.setText(td);  } });


        //affichage de la distance dans l'HUD
        final String dete2 = mGame.getResourcesNextToPlayerDist();
        mTvDistance.getHandler().post(new Runnable() {
            public void run() {
                mTvDistance.setText(dete2);
            }
        });


        return scene.numChildren()>0;
    }

    protected void onList()
    {
        Intent intent = new Intent(this, ARActivity.class);
        intent.putExtra("game", mGame);
        startActivity(intent);
    }

    protected void moveView(View v, int x, int y, int w, int h)
    {
        RelativeLayout.LayoutParams l = new RelativeLayout.LayoutParams(w, h);
        l.leftMargin = x;
        l.topMargin = y;
        v.setLayoutParams(l);
    }


     @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        //mGame = (Game) getIntent().getSerializableExtra("game");
        mGame = Game.game();
        mGame.newSensorManager(this);
        mTvDistance=(TextView)findViewById(R.id.tv_distance);
        mTvAngle=(TextView)findViewById(R.id.tv_angle);
        mTvGPS=(TextView)findViewById(R.id.tv_gps);
        mRlRoot=(RelativeLayout) findViewById(R.id.rl_root);
        mIvWhite=(ImageView)findViewById(R.id.iv_white);
        mIvRed=(ImageView)findViewById(R.id.iv_red);
        mIvGreen=(ImageView)findViewById(R.id.iv_green);
        mIvNone=(ImageView)findViewById(R.id.iv_none);



        ViewTreeObserver vto = mRlRoot.getViewTreeObserver();
        vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                mRlRoot.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                int w =mViewWidth  = mRlRoot.getMeasuredWidth();
                int h =mViewHeight = mRlRoot.getMeasuredHeight();

                mTvGPS.setTextSize(pxToDp((int)(h*0.121f/3.5)));
                mTvGPS.setText("N ?°\nE ?°");
                mTvAngle.setTextSize(pxToDp((int)(h*0.121f/3.5)));
                mTvDistance.setTextSize(pxToDp((int)(h*0.046f)));

                moveView(mTvAngle, (int)(0.03*w), (int)(0.864f*h), (int)(0.291f*w), (int)(0.121*h ));
                moveView(mTvGPS, w-(int)(0.32f*w), (int)(0.875f*h),(int)(0.3*w), (int)(0.121*h));
                moveView(mTvDistance, w-mTvDistance.getWidth()-(int)(0.36f*w), (int)(0.033f*h), mTvGPS.getWidth(), (int)(0.121*h));

                moveView(mIvNone, (int)(w/4.0), 0, (int)(w/2.0), (int)(0.06f*h));
                moveView(mIvWhite, (int)(w*0.269), (int)(0.034*h), (int)(w*0.03333), (int)(0.02286f*h));
                moveView(mIvRed, (int)(w*0.702), (int)(0.034*h), (int)(w*0.03333), (int)(0.02286f*h));
                moveView(mIvGreen, (int)(w*0.702), (int)(0.034*h), (int)(w*0.03333), (int)(0.02286f*h));
            }
        });



        int w = mRlRoot.getWidth();
        int h = mRlRoot.getHeight();


    }




    @Override
    /**
     * Verifie si on doit afficher des resources et gere le bouton de capture
     */
    public  void updateScene()
    {
        synchronized (mUpdate)
        {
            if(!mUpdate) return;
            boolean isResource = false;
            synchronized (mLock) {
                if (!isPausing) {
                    boolean b = mGame.precache3DResource(this);
                    isResource = updateSceneResource();
                }else
                {
                    scene.clear();
                    mGame.removeCached3DModels();
                }
            }

            if(isResource) {
                mOkButton.getHandler().post(new Runnable() {
                    public void run() {
                        mOkButton.setVisibility(View.VISIBLE);
                    }
                });
            }else
            {
                mOkButton.getHandler().post(new Runnable() {
                    public void run() {
                        mOkButton.setVisibility(View.INVISIBLE);
                    }
                });

            }
            mTvAngle.getHandler().post(new Runnable() {
                public void run() {
                    NumberFormat formatter = new DecimalFormat("#0.0");
                    mTvAngle.setText("X : "+formatter.format(mGame.getPlayer().getOrientation())+"°\nY : "+
                            formatter.format(mGame.getPlayer().getOrientationY())
                                    +"°\nZ : "+formatter.format(mGame.getPlayer().getOrientationZ())+"°");
                }
            });

            setGpsText();
        }

    }

    protected String dts(double d, int n)
    {
        String str = "#0";
        if(n>0)
        {
            str+=".";
            for(int i=0; i<n; i++) str+="0";
        }
        NumberFormat formatter = new DecimalFormat(str);
        return formatter.format(d);
    }

    protected String dts(double d)
    {
        return dts(d,2);
    }


    @Override
    protected  void onResume() {
        super.onResume();
        init();
        mGame.onResume(this);
        scene.clear();
        synchronized (mLock)
        {
            isPausing=false;
        }
    }
    @Override
    protected  void onPause()
    {
        synchronized (mLock)
        {
            isPausing=true;
        }
        super.onPause();
        mGame.onPause(this);
        scene.clear();
        cameraPreviewLayout.removeViewAt(0);
        cameraPreviewLayout.removeViewAt(0);

    }

    public void finish()
    {
        mGame.stopSensors();
        super.finish();
    }

    public void setGpsText()
    {
        if(mLocationUpdated) {
            final GPSPoint gps = mLocation;
            mTvGPS.getHandler().post(new Runnable() {

                public void run() {

                    NumberFormat formatter = new DecimalFormat("#0.0000000");
                    NumberFormat formatter2 = new DecimalFormat("#0.0");
                    mTvGPS.setText("N "+formatter.format(gps.getX()) + "°\nE " + formatter.format(gps.getY()) + "°\n+/- "+formatter2.format(gps.getAccuracy())+" m");
                }
            });
            mLocationUpdated=false;
        }
    }


    public void onSaveInstanceState(Bundle savedInstanceState) {
        // Save the user's current game state
        savedInstanceState.putSerializable("game", mGame);

        // Always call the superclass so it can save the view hierarchy state
        super.onSaveInstanceState(savedInstanceState);
    }

    public void onClickPickUp(View v)
    {
        synchronized (mUpdate) {mUpdate=false;}
        ArrayList<Resource> res = null;
        boolean stageFinished = mGame.pickResource();
        boolean finished = false;
        res=mGame.getPickedUpResources();


        if(stageFinished)
        {
           finished = mGame.nextStage();
        }

        if(finished)
        {
            Log.e("Finished", "Finished");
        }

        if(stageFinished)
        {
            Stage s = mGame.getCurrentStageObj();
            Resource stageRes = s.getResource();

            if(finished)
            {
                Intent intent2 = new Intent(this, EndActivity.class);
                startActivity(intent2);
            }

            Intent intent = new Intent(this, ViewerActivity.class);
            intent.putExtra("resource", stageRes );
            startActivity(intent);

            Intent intent2 = new Intent(this, TransferActivity.class);
            startActivity(intent2);
        }
        for(int i=0; i<res.size(); i++)
        {
            Intent intent = new Intent(this, ViewerActivity.class);
            intent.putExtra("resource", res.get(i) );
            startActivity(intent);
        }
        finish();
    }


    public static void setLocation(GPSPoint p)
    {
        mLocation = p;
        mLocationUpdated=true;
    }


    public static int dpToPx(int dp)
    {
        return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
    }

    public static int pxToDp(int px)
    {
        return (int) (px / Resources.getSystem().getDisplayMetrics().density);
    }

    public void onStub(View v)
    {
        mGame.getPlayer().nextStub();
    }

}
