/*
 * Copyright 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Must be changed with #define HELPER_CLASS_NAME "com/android/helper/NDKHelper" in AndroidMain.cpp
package com.android.helper;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.nio.ByteBuffer;

import javax.microedition.khronos.opengles.GL10;

import android.R.bool;
import android.opengl.GLES30;

import android.annotation.TargetApi;
import android.app.Activity;
import android.app.NativeActivity;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.opengl.GLUtils;
import android.os.Build;
import android.util.Log;
import android.view.View;
import android.view.View.MeasureSpec;

@TargetApi(Build.VERSION_CODES.GINGERBREAD)
public class NDKHelper {

    public NDKHelper(NativeActivity act) {
        activity = act;
    }

    public void loadLibrary(String soname) {
        if (soname.isEmpty() == false) {
            System.loadLibrary(soname);
            loadedSO = true;
        }
    }

    public static Boolean checkSOLoaded() {
        if (loadedSO == false) {
            Log.e("NDKHelper",
                    "--------------------------------------------\n"
                            + ".so has not been loaded. To use JUI helper, please initialize with \n"
                            + "NDKHelper::Init( ANativeActivity* activity, const char* helper_class_name, const char* native_soname);\n"
                            + "--------------------------------------------\n");
            return false;
        } else
            return true;
    }

    private static boolean loadedSO = false;
    NativeActivity activity;



    //
    // Load Bitmap
    // Java helper is useful decoding PNG, TIFF etc rather than linking libPng
    // etc separately
    //
    private int nextPOT(int i) {
        int pot = 1;
        while (pot < i)
            pot <<= 1;
        return pot;
    }

    private Bitmap scaleBitmap(Bitmap bitmapToScale, float newWidth,
                               float newHeight) {
        if (bitmapToScale == null)
            return null;
        // get the original width and height
        int width = bitmapToScale.getWidth();
        int height = bitmapToScale.getHeight();
        // create a matrix for the manipulation
        Matrix matrix = new Matrix();

        // resize the bit map
        matrix.postScale(newWidth / width, newHeight / height);

        // recreate the new Bitmap and set it back
        return Bitmap.createBitmap(bitmapToScale, 0, 0,
                bitmapToScale.getWidth(), bitmapToScale.getHeight(), matrix,
                true);
    }

    public class TextureInformation {
        boolean ret;
        boolean alphaChannel;
        int originalWidth;
        int originalHeight;
        Object image;
    }

    public Object loadTexture(String path) {
        Bitmap bitmap = null;
        TextureInformation info = new TextureInformation();
        try {
            String str = path;
            if (!path.startsWith("/")) {
                str = "/" + path;
            }

            File file = new File(activity.getExternalFilesDir(null), str);
            if (file.canRead()) {
                bitmap = BitmapFactory.decodeStream(new FileInputStream(file));
            } else {
                bitmap = BitmapFactory.decodeStream(activity.getResources()
                        .getAssets().open(path));
            }
            // Matrix matrix = new Matrix();
            // // resize the bit map
            // matrix.postScale(-1F, 1F);
            //
            // // recreate the new Bitmap and set it back
            // bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
            // bitmap.getHeight(), matrix, true);

        } catch (Exception e) {
            Log.w("NDKHelper", "Coundn't load a file:" + path);
            info.ret = false;
            return info;
        }

        if (bitmap != null) {
            GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
        }
        info.ret = true;
        info.alphaChannel = bitmap.hasAlpha();
        info.originalWidth = getBitmapWidth(bitmap);
        info.originalHeight = getBitmapHeight(bitmap);

        return info;
    }

    public Object loadCubemapTexture(String path, int face, int miplevel, boolean sRGB) {
        Bitmap bitmap = null;
        TextureInformation info = new TextureInformation();
        try {
            String str = path;
            if (!path.startsWith("/")) {
                str = "/" + path;
            }

            File file = new File(activity.getExternalFilesDir(null), str);
            if (file.canRead()) {
                bitmap = BitmapFactory.decodeStream(new FileInputStream(file));
            } else {
                bitmap = BitmapFactory.decodeStream(activity.getResources()
                        .getAssets().open(path));
            }
        } catch (Exception e) {
            Log.w("NDKHelper", "Coundn't load a file:" + path);
            info.ret = false;
            return info;
        }

        if (bitmap != null) {
            if (sRGB)
            {
//        		GLUtils.texImage2D(face, miplevel, bitmap, 0);
//        		GLUtils.texImage2D(face, miplevel,
//        				GLUtils.getInternalFormat(bitmap), bitmap, 0);
//        		int i = GLUtils.getInternalFormat(bitmap);
//        		if( i == GL10.GL_RGBA)
//        		{
//            		GLUtils.texImage2D(face, miplevel,
//            				GLES30.GL_SRGB, bitmap, 0);
//        		}
                //Leave them for now
                GLUtils.texImage2D(face, miplevel, bitmap, 0);
            }
            else
                GLUtils.texImage2D(face, miplevel, bitmap, 0);
        }
        info.ret = true;
        info.alphaChannel = bitmap.hasAlpha();
        info.originalWidth = getBitmapWidth(bitmap);
        info.originalHeight = getBitmapHeight(bitmap);

        return info;

    }

    public Object loadImage(String path) {
        Bitmap bitmap = null;
        TextureInformation info = new TextureInformation();
        try {
            String str = path;
            if (!path.startsWith("/")) {
                str = "/" + path;
            }

            File file = new File(activity.getExternalFilesDir(null), str);
            if (file.canRead()) {
                bitmap = BitmapFactory.decodeStream(new FileInputStream(file));
            } else {
                bitmap = BitmapFactory.decodeStream(activity.getResources()
                        .getAssets().open(path));
            }
        } catch (Exception e) {
            Log.w("NDKHelper", "Coundn't load a file:" + path);
            info.ret = false;
            return info;
        }

        if (bitmap != null) {
            GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
        }
        info.ret = true;
        info.alphaChannel = bitmap.hasAlpha();
        info.originalWidth = getBitmapWidth(bitmap);
        info.originalHeight = getBitmapHeight(bitmap);

        int iBytes = bitmap.getWidth() * bitmap.getHeight() * 4;
        ByteBuffer buffer = ByteBuffer.allocateDirect(iBytes);

        bitmap.copyPixelsToBuffer(buffer);
        info.image = buffer;
        return info;
    }

    public Bitmap openBitmap(String path, boolean iScalePOT) {
        Bitmap bitmap = null;
        try {
            bitmap = BitmapFactory.decodeStream(activity.getResources()
                    .getAssets().open(path));
            if (iScalePOT) {
                int originalWidth = getBitmapWidth(bitmap);
                int originalHeight = getBitmapHeight(bitmap);
                int width = nextPOT(originalWidth);
                int height = nextPOT(originalHeight);
                if (originalWidth != width || originalHeight != height) {
                    // Scale it
                    bitmap = scaleBitmap(bitmap, width, height);
                }
            }

        } catch (Exception e) {
            Log.w("NDKHelper", "Coundn't load a file:" + path);
        }

        return bitmap;
    }

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

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

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

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

    public String getNativeLibraryDirectory(Context appContext) {
        ApplicationInfo ai = activity.getApplicationInfo();

        Log.w("NDKHelper", "ai.nativeLibraryDir:" + ai.nativeLibraryDir);

        if ((ai.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0
                || (ai.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
            return ai.nativeLibraryDir;
        }
        return "/system/lib/";
    }

    public String getApplicationName() {
        final PackageManager pm = activity.getPackageManager();
        ApplicationInfo ai;
        try {
            ai = pm.getApplicationInfo(activity.getPackageName(), 0);
        } catch (final NameNotFoundException e) {
            ai = null;
        }
        String applicationName = (String) (ai != null ? pm
                .getApplicationLabel(ai) : "(unknown)");
        return applicationName;
    }

    public String getStringResource(String resourceName)
    {
        int id = activity.getResources().getIdentifier(resourceName, "string", activity.getPackageName());
        String value = id == 0 ? "" : (String)activity.getResources().getText(id);
        return value;
    }

    //
    // Audio related helpers
    //
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
    public int getNativeAudioBufferSize() {
        int SDK_INT = android.os.Build.VERSION.SDK_INT;
        if (SDK_INT >= 17) {
            AudioManager am = (AudioManager) activity
                    .getSystemService(Context.AUDIO_SERVICE);
            String framesPerBuffer = am
                    .getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER);
            return Integer.parseInt(framesPerBuffer);
        } else {
            return 0;
        }
    }

    public int getNativeAudioSampleRate() {
        return AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_SYSTEM);
    }

    /*
     * Helper to execute function in UIThread
     */
    public void runOnUIThread(final long p) {
        if (checkSOLoaded()) {
            activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    RunOnUiThreadHandler(p);
                }
            });
        }
        return;
    }

    /*
     * Native code helper for RunOnUiThread
     */
    native public void RunOnUiThreadHandler(long pointer);
}