package jogamp.opengl.android.av;

import java.io.IOException;
import java.net.URL;

import javax.media.opengl.GL;
import javax.media.opengl.GLContext;
import javax.media.opengl.GLDrawable;
import javax.media.opengl.GLES2;

import jogamp.common.os.android.StaticContext;
import jogamp.opengl.av.GLMediaPlayerImpl;

import android.graphics.SurfaceTexture;
import android.graphics.SurfaceTexture.OnFrameAvailableListener;
import android.media.MediaPlayer;
import android.net.Uri;
import android.view.Surface;

import com.jogamp.opengl.av.GLMediaEventListener;
import com.jogamp.opengl.av.GLMediaPlayer;
import com.jogamp.opengl.av.GLMediaPlayer.TextureFrame;
import com.jogamp.opengl.util.PMVMatrix;
import com.jogamp.opengl.util.texture.Texture;
import com.jogamp.opengl.util.texture.TextureCoords;

/***
 * Android API Level 14: {@link MediaPlayer#setSurface(Surface)}
 * Android API Level 14: {@link Surface#Surface(android.graphics.SurfaceTexture)}
 */
public class AndroidGLMediaPlayerAPI14 extends GLMediaPlayerImpl {
    MediaPlayer mp;
    boolean updateSurface = false;
    
    public static class AndroidTextureFrame extends TextureFrame {
        public AndroidTextureFrame(Texture t, SurfaceTexture stex) {
            super(t);
            this.stex = stex;
        }
        
        public final SurfaceTexture getSurfaceTexture() { return stex; }
        
        public String toString() {
            return "AndroidTextureFrame[" + texture + ", "+ stex + "]";
        }
        protected SurfaceTexture stex;
    }
    
    public AndroidGLMediaPlayerAPI14() {
        super();
        this.setTextureTarget(GLES2.GL_TEXTURE_EXTERNAL_OES);
        this.setTextureCount(1);
        mp = new MediaPlayer();
    }

    @Override
    public void setPlaySpeed(float rate) {
        // n/a
    }

    @Override
    public void start() {
        mp.start();
    }

    @Override
    public void pause() {
        mp.pause();
    }

    @Override
    public void stop() {
        mp.stop();
    }

    @Override
    public int seek(int msec) {
        mp.seekTo(msec);
        return mp.getCurrentPosition();
    }

    @Override
    public Texture getNextTextureID() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public int getCurrentPosition() {
        return mp.getCurrentPosition();
    }

    @Override
    public boolean isValid() {
        return true;
    }
    
    AndroidTextureFrame androidTextureFrame = null;
    
    @Override
    protected void destroyImpl(GL gl) {
        mp.release();
        mp = null;        
    }
    
    @Override
    protected void setStreamImpl() throws IOException {
        try {
            final Uri uri = Uri.parse(url.toExternalForm());        
            mp.setDataSource(StaticContext.getContext(), uri);
        } catch (IllegalArgumentException e) {
            throw new RuntimeException(e);
        } catch (SecurityException e) {
            throw new RuntimeException(e);
        } catch (IllegalStateException e) {
            throw new RuntimeException(e);
        }
        mp.prepare();
        
        width = mp.getVideoWidth();
        height = mp.getVideoHeight();
        fps = 0;
        bps = 0;
        totalFrames = mp.getDuration();
        acodec = "unknown";
        vcodec = "unknown";        
    }
    
    @Override
    protected void destroyTexImage(GLContext ctx, TextureFrame imgTex) {
        final AndroidTextureFrame atf = (AndroidTextureFrame) imgTex;
        atf.getSurfaceTexture().release();
        super.destroyTexImage(ctx, imgTex);
    }
    
    @Override
    protected AndroidTextureFrame createTexImage(GLContext ctx, int idx, int[] tex) {
        final GL gl = ctx.getGL();
        
        if( 0 > tex[idx] ) {
            throw new RuntimeException("TextureName "+toHexString(tex[idx])+" invalid.");
        }
        gl.glBindTexture(GLES2.GL_TEXTURE_EXTERNAL_OES, tex[idx]);
        {
            final int err = gl.glGetError();
            if( GL.GL_NO_ERROR != err ) {
                throw new RuntimeException("Couldn't bind textureName "+toHexString(tex[idx])+" to 2D target, err "+toHexString(err));
            }
        }
        // gl.glTexParameterf(GLES2.GL_TEXTURE_EXTERNAL_OES, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
        // gl.glTexParameterf(GLES2.GL_TEXTURE_EXTERNAL_OES, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
        gl.glTexParameterf(GLES2.GL_TEXTURE_EXTERNAL_OES, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST);
        gl.glTexParameterf(GLES2.GL_TEXTURE_EXTERNAL_OES, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST);
        // Clamp to edge is only option.
        gl.glTexParameteri(GLES2.GL_TEXTURE_EXTERNAL_OES, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE);
        gl.glTexParameteri(GLES2.GL_TEXTURE_EXTERNAL_OES, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE);
                
        SurfaceTexture stex = new SurfaceTexture(tex[idx]);
        stex.setOnFrameAvailableListener(onFrameAvailableListener);
        
        return new AndroidTextureFrame( com.jogamp.opengl.util.texture.TextureIO.newTexture(tex[idx],
                                     GLES2.GL_TEXTURE_EXTERNAL_OES,
                                     width, height,
                                     width, height,
                                     true), stex);
    }

    protected OnFrameAvailableListener onFrameAvailableListener = new OnFrameAvailableListener() {
        @Override
        public void onFrameAvailable(SurfaceTexture surfaceTexture) {
            frameNumber++;
            updateSurface = true;
        }        
    };
        
    @Override
    public float getPlaySpeed() {
        // TODO Auto-generated method stub
        return 0;
    }

    private float[] mSTMatrix = new float[16];
    
    @Override
    public Texture getLastTextureID() {
        if(updateSurface) {
            androidTextureFrame.getSurfaceTexture().updateTexImage();
            androidTextureFrame.getSurfaceTexture().getTransformMatrix(mSTMatrix);
            TextureCoords tc = androidTextureFrame.getTexture().getImageTexCoords();
            PMVMatrix pmv;
        }
        return androidTextureFrame.getTexture();
    }

}