package com.xugame.gameconsole.emulator;

import android.content.SharedPreferences;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;

import com.retroarch.browser.retroactivity.RetroActivityCommon;
import com.xugame.gameconsole.preferences.UserPreferences;

import java.io.IOException;

public abstract class RetroActivityCamera extends RetroActivityCommon {

    private Camera mCamera = null;
    private long lastTimestamp = 0;
    private SurfaceTexture texture;
    private boolean updateSurface = true;
    private boolean camera_service_running = false;
    public abstract void showLocalExitDialog();

    /**
     * Executed when the {@link Camera}
     * is staring to capture.
     */
    public void onCameraStart()
    {
        if (camera_service_running)
            return;

        if (mCamera != null)
            mCamera.startPreview();
        camera_service_running = true;
    }

    /**
     * Executed when the {@link Camera} is done capturing.
     * <p>
     * Note that this does not release the currently held
     * {@link Camera} instance and must be freed by calling
     * {@link #onCameraFree}
     */
    public void onCameraStop()
    {
        if (!camera_service_running)
            return;

        if (mCamera != null)
            mCamera.stopPreview();
        camera_service_running = false;
    }

    /**
     * Releases the currently held {@link Camera} instance.
     */
    public void onCameraFree()
    {
        onCameraStop();

        if (mCamera != null)
            mCamera.release();
    }

    /**
     * Initializes the camera for use.
     */
    public void onCameraInit()
    {
        if (mCamera != null)
            return;

        mCamera = Camera.open();
    }

    /**
     * Polls the camera for updates to the {@link SurfaceTexture}.
     *
     * @return true if polling was successful, false otherwise.
     */
    public boolean onCameraPoll()
    {
        if (!camera_service_running)
            return false;

        if (texture == null)
        {
            Log.i("RetroActivity", "No texture");
            return true;
        }
        else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
        {
            if (updateSurface)
            {
                texture.updateTexImage();
            }

            long newTimestamp = texture.getTimestamp();

            if (newTimestamp != lastTimestamp)
            {
                lastTimestamp = newTimestamp;
                return true;
            }

            return false;
        }

        return true;
    }

    /**
     * Initializes the {@link SurfaceTexture} used by the
     * {@link Camera} with a given OpenGL texure ID.
     *
     * @param gl_texid texture ID to initialize the
     *        {@link SurfaceTexture} with.
     */
    public void onCameraTextureInit(int gl_texid)
    {
        texture = new SurfaceTexture(gl_texid);
        texture.setOnFrameAvailableListener(onCameraFrameAvailableListener);
    }

    /**
     * Sets the {@link Camera} texture with the texture represented
     * by the given OpenGL texture ID.
     *
     * @param gl_texid     The texture ID representing the texture to set the camera to.
     * @throws IOException If setting the texture fails.
     */
    public void onCameraSetTexture(int gl_texid) throws IOException
    {
        if (texture == null)
            onCameraTextureInit(gl_texid);

        if (mCamera != null)
            mCamera.setPreviewTexture(texture);
    }

    private final SurfaceTexture.OnFrameAvailableListener onCameraFrameAvailableListener = new SurfaceTexture.OnFrameAvailableListener()
    {
        @Override
        public void onFrameAvailable(SurfaceTexture surfaceTexture)
        {
            updateSurface = true;
        }
    };

    @Override
    public void showExitDialog() {
        showLocalExitDialog();
    }

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        // Save the current setting for updates
        SharedPreferences prefs = UserPreferences.getPreferences(this);
        SharedPreferences.Editor edit = prefs.edit();
        edit.putBoolean("CAMERA_UPDATES_ON", false);
        edit.apply();

        camera_service_running = false;

        super.onCreate(savedInstanceState);
    }

    @Override
    public void onPause()
    {
        // Save the current setting for updates
        SharedPreferences prefs = UserPreferences.getPreferences(this);
        SharedPreferences.Editor edit = prefs.edit();
        edit.putBoolean("CAMERA_UPDATES_ON", camera_service_running);
        edit.apply();

        onCameraStop();
        super.onPause();
    }

    @Override
    public void onResume()
    {
        SharedPreferences prefs = UserPreferences.getPreferences(this);
        SharedPreferences.Editor edit = prefs.edit();

        /*
         * Get any previous setting for camera updates
         * Gets "false" if an error occurs
         */
        if (prefs.contains("CAMERA_UPDATES_ON"))
        {
            camera_service_running = prefs.getBoolean("CAMERA_UPDATES_ON", false);
            if (camera_service_running)
            {
                onCameraStart();
            }
        }
        else // Otherwise, turn off camera updates
        {
            edit.putBoolean("CAMERA_UPDATES_ON", false);
            edit.apply();
            camera_service_running = false;
        }

        super.onResume();
    }

    @Override
    public void onDestroy()
    {
        onCameraFree();
        super.onDestroy();
    }

    @Override
    public void onStop()
    {
        onCameraStop();
        super.onStop();
    }

}
