//
// Lol Engine
//
// Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net>
//   This program is free software; you can redistribute it and/or
//   modify it under the terms of the Do What The Fuck You Want To
//   Public License, Version 2, as published by Sam Hocevar. See
//   http://www.wtfpl.net/ for more details.
//

package net.lolengine;

import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.AssetManager; /* getAssets() */
import android.content.res.Resources; /* getResources() */
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.WindowManager;
import android.view.Window;

import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.opengles.GL10;

/* FIXME: this needs to have a different name for each project */
public class LolActivity extends Activity
{
    @Override protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                             WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
                             WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        requestWindowFeature(Window.FEATURE_NO_TITLE);

        nativeInit();

        mView = new LolView(getApplication());
        setContentView(mView);
    }

    @Override protected void onPause()
    {
        super.onPause();
        mView.onPause();
    }

    @Override protected void onResume()
    {
        super.onResume();
        mView.onResume();
    }

    private LolView mView;

    static
    {
        System.loadLibrary("stlport_shared");
        System.loadLibrary("@PROGRAM@");
    }

    public Bitmap openImage(String name)
    {
        try
        {
            return BitmapFactory.decodeStream(getAssets().open(name));
        }
        catch (Exception e) { }
        return null;
    }

    public int getWidth(Bitmap bmp) { return bmp.getWidth(); }
    public int getHeight(Bitmap bmp) { return bmp.getHeight(); }

    public void getPixels(Bitmap bmp, int[] pixels)
    {
        int w = bmp.getWidth();
        int h = bmp.getHeight();
        bmp.getPixels(pixels, 0, w, 0, 0, w, h);
    }

    public void closeImage(Bitmap bmp)
    {
        bmp.recycle();
    }

    private native void nativeInit();
}

class LolView extends GLSurfaceView
{
    public LolView(Context context)
    {
        super(context);
        setEGLContextFactory(new ContextFactory());
        //setEGLConfigChooser(new ConfigChooser(4, 4, 4, 0, 8, 0));
        setEGLConfigChooser(new ConfigChooser(4, 4, 4, 4, 8, 0));
        setRenderer(new LolRenderer());
    }

    private static class ContextFactory implements GLSurfaceView.EGLContextFactory
    {
        private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
        public EGLContext createContext(EGL10 egl, EGLDisplay dpy, EGLConfig cfg)
        {
            Log.w("LOL", "creating OpenGL ES 2.0 context");
            int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
            EGLContext ctx = egl.eglCreateContext(dpy, cfg, EGL10.EGL_NO_CONTEXT, attrib_list);
            return ctx;
        }

        public void destroyContext(EGL10 egl, EGLDisplay dpy, EGLContext ctx)
        {
            egl.eglDestroyContext(dpy, ctx);
        }
    }

    private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser
    {
        public ConfigChooser(int r, int g, int b, int a, int depth, int stencil)
        {
            mRed = r;
            mGreen = g;
            mBlue = b;
            mAlpha = a;
            mDepth = depth;
            mStencil = stencil;
        }

        private static int EGL_OPENGL_ES2_BIT = 4;
        private static int[] s_configAttribs2 =
        {
//            EGL10.EGL_BUFFER_SIZE, 16,
            EGL10.EGL_DEPTH_SIZE, 8,
            EGL10.EGL_RED_SIZE, 4,
            EGL10.EGL_GREEN_SIZE, 4,
            EGL10.EGL_BLUE_SIZE, 4,
//            EGL10.EGL_ALPHA_SIZE, 4,
            EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
            EGL10.EGL_NONE
        };

        public EGLConfig chooseConfig(EGL10 egl, EGLDisplay dpy)
        {
            int[] num_config = new int[1];
            egl.eglChooseConfig(dpy, s_configAttribs2, null, 0, num_config);

            int n = num_config[0];
            if (n <= 0)
                throw new IllegalArgumentException("No GLES configs");

            EGLConfig[] configs = new EGLConfig[n];
            egl.eglChooseConfig(dpy, s_configAttribs2, configs, n, num_config);
            return choose(egl, dpy, configs);
        }

        public EGLConfig choose(EGL10 egl, EGLDisplay dpy, EGLConfig[] configs)
        {
            for(EGLConfig cfg : configs)
            {
                /* Do not complain if we get more bits than we asked. */
                if (get(egl, dpy, cfg, EGL10.EGL_STENCIL_SIZE, 0) >= mStencil
                 && get(egl, dpy, cfg, EGL10.EGL_DEPTH_SIZE, 0) >= mDepth
                 && get(egl, dpy, cfg, EGL10.EGL_RED_SIZE, 0) >= mRed
                 && get(egl, dpy, cfg, EGL10.EGL_GREEN_SIZE, 0) >= mGreen
                 && get(egl, dpy, cfg, EGL10.EGL_BLUE_SIZE, 0) >= mBlue
                 && get(egl, dpy, cfg, EGL10.EGL_ALPHA_SIZE, 0) >= mAlpha)
                    return cfg;
            }
            return null;
        }

        private int get(EGL10 egl, EGLDisplay dpy, EGLConfig cfg,
                        int attr, int defval)
        {
            int[] value = new int[1];

            if (egl.eglGetConfigAttrib(dpy, cfg, attr, value))
                return value[0];
            return defval;
        }

        protected int mRed, mGreen, mBlue, mAlpha, mDepth, mStencil;
    }

    public boolean onTouchEvent(final MotionEvent ev)
    {
        final int action = ev.getAction();
        switch (action)
        {
            case MotionEvent.ACTION_DOWN:
                nativeMove((int)ev.getX(), (int)ev.getY());
                nativeDown();
                break;
            case MotionEvent.ACTION_UP:
                nativeMove((int)ev.getX(), (int)ev.getY());
                nativeUp();
                break;
            case MotionEvent.ACTION_MOVE:
                nativeMove((int)ev.getX(), (int)ev.getY());
                break;
        }

        return true;
    }

    private static native void nativePause();
    private static native void nativeDown();
    private static native void nativeUp();
    private static native void nativeMove(int x, int y);
}

class LolRenderer implements GLSurfaceView.Renderer
{
    public void onSurfaceCreated(GL10 gl, EGLConfig config)
    {
        nativeInit();
    }

    public void onSurfaceChanged(GL10 gl, int w, int h)
    {
        Log.w("LOL", String.format("resizing to %dx%d", w, h));
        nativeResize(w, h);
    }

    public void onDrawFrame(GL10 gl)
    {
        nativeRender();
    }

    private static native void nativeInit();
    private static native void nativeResize(int w, int h);
    private static native void nativeRender();
    private static native void nativeDone();
}