/*******************************************************************************
	File:		MediaPlayer.java

	Contains:	player wrap implement file.

	Written by:	Fenger King

	Change History (most recent first):
	2013-09-28		Fenger			Create file

*******************************************************************************/
package com.qiniu.qplayer.mediaEngine;

import android.content.Context;
import android.media.AudioManager;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.ViewGroup.LayoutParams;
import android.widget.RelativeLayout;
import android.graphics.Bitmap;

import java.io.File;
import java.io.FileOutputStream;
import java.lang.ref.WeakReference;

import android.util.DisplayMetrics;
import android.util.Log;
import java.io.UnsupportedEncodingException;

public class MediaPlayer implements BasePlayer {
	private static final String TAG = "QCLOGMediaPlayer";

	private Context 	m_context = null;
	private long 		m_NativeContext = 0;
	private Surface 	m_NativeSurface = null;
	private SurfaceView m_SurfaceView = null;

	private int m_nStreamNum = 0;
	private int m_nStreamPlay = -1;
	private int	m_nStreamBitrate = 0;

	private int m_nVideoWidth = 0;
	private int m_nVideoHeight = 0;
	private int m_nSampleRate = 0;
	private int m_nChannels = 0;
	private int m_nBTOffset = 0;

	private Object				m_pObjPlayer = null;
	private String				m_strApkPath = null;
	private String				m_strURL = null;
	private AudioRender			m_AudioRender = null;
	private onEventListener 	m_EventListener = null;
	private msgHandler 			m_hHandler = null;

	static {
		System.loadLibrary("QPlayer");
	}

	public int Init(Context context, String apkPath, int nFlag) {
		m_hHandler = new msgHandler();
		m_context = context;
		AudioManager am = (AudioManager)context.getSystemService(context.AUDIO_SERVICE);
		if (am != null && am.isBluetoothA2dpOn())
			m_nBTOffset = 250;
		m_strApkPath = apkPath;
		m_pObjPlayer = new WeakReference<MediaPlayer>(this);
		m_NativeContext = nativeInit(m_pObjPlayer, apkPath, nFlag);
		if (m_NativeContext == 0)
			return -1;
		if (m_NativeSurface != null)
			nativeSetView(m_NativeContext, m_NativeSurface);

		return 0;
	}

	public void setEventListener(onEventListener listener) {
		m_EventListener = listener;
	}

	public void SetView(SurfaceView sv) {
		m_SurfaceView = sv;
		if (sv != null) {
			SurfaceHolder sh = sv.getHolder();
			m_NativeSurface = sh.getSurface();
		} else {
			m_NativeSurface = null;
		}
		if (m_NativeContext != 0)
			nativeSetView(m_NativeContext, m_NativeSurface);
	}

	public int Open(String strPath, int nFlag) {
		m_strURL = strPath;
		return nativeOpen(m_NativeContext, strPath, nFlag);
	}

	public void Play() {
		nativePlay(m_NativeContext);
	}

	public void Pause() {
		nativePause(m_NativeContext);
	}

	public void Stop() {
		nativeStop(m_NativeContext);
	}

	public long GetDuration() {
		return nativeGetDuration(m_NativeContext);
	}

	public long GetPos() {
		return nativeGetPos(m_NativeContext);
	}

	public int SetPos(long lPos) {
		return nativeSetPos(m_NativeContext, lPos);
	}

	public int GetParam(int nParamId, int nParam, Object objParam) {
		return nativeGetParam(m_NativeContext, nParamId, nParam, objParam);
	}

	public int SetParam(int nParamId, int nParam, Object objParam) {
		return nativeSetParam(m_NativeContext, nParamId, nParam, objParam);
	}

	public void Uninit() {
		nativeUninit(m_NativeContext);
		if (m_AudioRender != null)
			m_AudioRender.closeTrack();
		m_AudioRender = null;
		m_NativeContext = 0;
	}

	public int GetVideoWidth() {
		return m_nVideoWidth;
	}

	public int GetVideoHeight() {
		return m_nVideoHeight;
	}

	public void SetVolume(int nVolume) {
		SetParam (PARAM_PID_AUDIO_VOLUME, nVolume, null);
	}

	public int GetStreamNum() {
		if (m_nStreamNum == 0)
			GetParam (QCPLAY_PID_StreamNum, 0, this);
		return m_nStreamNum;

	}
	public int SetStreamPlay (int nStream) {
		if (nStream == m_nStreamPlay)
			return nStream;
		m_nStreamPlay = nStream;
		SetParam (QCPLAY_PID_StreamPlay, m_nStreamPlay, null);
		return m_nStreamPlay;
	}

	public int GetStreamPlay () {
		GetParam (QCPLAY_PID_StreamPlay, 0, this);
		return m_nStreamPlay;
	}

	public int GetStreamBitrate (int nStream) {
		GetParam (QCPLAY_PID_StreamInfo, nStream, this);
		return m_nStreamBitrate;
	}

	
	public void OnOpenComplete () {
		SetParam (QCPLAY_PID_Clock_OffTime,  m_nBTOffset, null);
	}

	public void onVideoSizeChanged () {
		RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams)m_SurfaceView.getLayoutParams();
		DisplayMetrics dm = m_context.getResources().getDisplayMetrics();
		if (m_nVideoWidth != 0 && m_nVideoHeight != 0)// && lp.width == LayoutParams.FILL_PARENT && lp.height == LayoutParams.FILL_PARENT)
		{
			int nMaxOutW = lp.width;
			if (nMaxOutW <= 0)
				nMaxOutW = dm.widthPixels;
			int nMaxOutH = lp.height;
			if (nMaxOutH <= 0)
				nMaxOutH = dm.heightPixels;

			if (nMaxOutW * m_nVideoHeight > m_nVideoWidth * nMaxOutH) {
				lp.height = nMaxOutH;
				lp.width  = m_nVideoWidth * nMaxOutH / m_nVideoHeight;
			} else {
				lp.width  = nMaxOutW;
				lp.height = m_nVideoHeight * nMaxOutW / m_nVideoWidth;
			}	
			//lp.width = lp.width * 2;
			//lp.height = lp.height * 2;		
			m_SurfaceView.setLayoutParams(lp);	
			Log.v("PlayerView", String.format("setSurfaceSize width = %d, height = %d", lp.width , lp.height));			
		}
	} 
		
	private static void postEventFromNative(Object baselayer_ref, int what, int ext1, int ext2, Object obj)
	{
		if (what != BasePlayer.QC_MSG_SNKA_RENDER && what != BasePlayer.QC_MSG_SNKV_RENDER)
			Log.v("MediaPlayer", String.format("QC_MSG ID = 0X%08X   value %d   %d", what, ext1, ext2));

		MediaPlayer player = (MediaPlayer)((WeakReference)baselayer_ref).get();
		if (player == null) 
			return;
		
		if (what == QC_MSG_SNKV_NEW_FORMAT)
		{
			if (player.m_nVideoWidth == ext1 && player.m_nVideoHeight == ext2){
				player.SetParam (PARAM_PID_EVENT_DONE, 0, null);
				return;
			}

			player.m_nVideoWidth = ext1;
			player.m_nVideoHeight = ext2;
		}		
		else if (what == QC_MSG_SNKA_NEW_FORMAT)
		{
			player.m_nSampleRate = ext1;
			player.m_nChannels = ext2;

			if (player.m_nSampleRate == 0 && player.m_nChannels == 0){
				if (player.m_AudioRender != null)
					player.m_AudioRender.closeTrack();
				return;
			}

			if (player.m_AudioRender == null)
				player.m_AudioRender = new AudioRender(player.m_context, player);
			player.m_AudioRender.openTrack (player.m_nSampleRate, player.m_nChannels);
			return;
		}
		else if (what == QC_MSG_RTMP_METADATA) {
			if (player.m_EventListener != null)
				player.m_EventListener.onEvent(what, ext1, ext2, obj);
			return;
		}

		Message msg = player.m_hHandler.obtainMessage(what, ext1, ext2, obj);
		msg.sendToTarget();
	}
		
	private static void audioDataFromNative(Object baselayer_ref, byte[] data, int size, long lTime)
	{
		// Log.v("audioDataFromNative", String.format("Size %d  Time  %d", size, lTime));
		MediaPlayer player = (MediaPlayer)((WeakReference)baselayer_ref).get();
		if (player == null) 
			return;
		if (player.m_AudioRender != null)
			player.m_AudioRender.writeData(data,  size);
	}
	
	private static void videoDataFromNative(Object baselayer_ref, byte[] data, int size, long lTime, int nFlag)
	{
		Log.v("videoDataFromNative", String.format("Size %d  Time  %d, Flag   %x", size, lTime, nFlag));
		MediaPlayer player = (MediaPlayer)((WeakReference)baselayer_ref).get();
		if (player == null) 
			return;
		if (nFlag == QC_FLAG_Video_CaptureImage) {
			// Save the jpeg buff to file.
			player.m_EventListener.OnImage(data, size);
		}
		else if (nFlag == QC_FLAG_Video_SEIDATA) {
			// handle the SEI DATA.
			Log.v("videoDataFromNative SEI", String.format("Size %d  Time  %d, data   %d", size, lTime, data[0]));
		}
	}

	class msgHandler extends Handler {
		public msgHandler() {
		}
		@Override
		public void handleMessage(Message msg) {
			if (m_NativeContext == 0)
				return;
			if (msg.what == QC_MSG_VIDEO_HWDEC_FAILED) {
				nativeUninit(m_NativeContext);
				m_NativeContext = nativeInit(m_pObjPlayer, m_strApkPath, 0);
				if (m_NativeSurface != null)
					nativeSetView(m_NativeContext, m_NativeSurface);
				nativeOpen (m_NativeContext, m_strURL, 0);
				//return;
			}
			if (msg.what == QC_MSG_PLAY_OPEN_DONE) {
				OnOpenComplete ();
			}
			if (m_EventListener != null) {
				m_EventListener.onEvent(msg.what, msg.arg1, msg.arg2, msg.obj);
			}
			if (msg.what == QC_MSG_SNKV_NEW_FORMAT) {
				//onVideoSizeChanged ();
				SetParam(PARAM_PID_EVENT_DONE, 0, null);
			}
		}
	}

	// the native functions
    private native long	nativeInit(Object player, String apkPath, int nFlag);
    private native int 	nativeUninit(long nNativeContext);
    private native int 	nativeSetView(long nNativeContext, Object view);
    private native int 	nativeOpen(long nNativeContext,String strPath, int nFlag);
    private native int 	nativePlay(long nNativeContext);
    private native int 	nativePause(long nNativeContext);
    private native int 	nativeStop(long nNativeContext);
    private native long	nativeGetPos(long nNativeContext);
    private native int 	nativeSetPos(long nNativeContext,long lPos);
    private native long nativeGetDuration(long nNativeContext);
	private native int 	nativeGetParam(long nNativeContext,int nParamId, int nParam, Object objParam);
    private native int 	nativeSetParam(long nNativeContext,int nParamId, int nParam, Object objParam);
}