package jp.agentec.abook.abv.ui.viewer.view.action;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import jp.agentec.abook.abv.bl.acms.client.json.content.PageObjectJSON;
import jp.agentec.abook.abv.bl.common.log.Logger;
import jp.agentec.abook.abv.bl.websocket.MeetingManager;
import jp.agentec.abook.abv.cl.util.BitmapUtil;
import jp.agentec.abook.abv.cl.util.ContentLogUtil;
import jp.agentec.abook.abv.cl.util.PreferenceUtil;
import jp.agentec.abook.abv.launcher.android.R;
import jp.agentec.abook.abv.ui.common.appinfo.AppDefType.DefPrefKey;
import jp.agentec.abook.abv.ui.common.util.ABVToastUtil;
import jp.agentec.abook.abv.ui.common.util.DisplayUtil;
import jp.agentec.abook.abv.ui.viewer.activity.ContentViewActivity;
import jp.agentec.abook.abv.ui.viewer.view.ActionSurfaceView;
import jp.agentec.abook.abv.ui.viewer.view.ZoomRelativeLayout;
import jp.agentec.adf.util.RuntimeUtil;
import jp.agentec.adf.util.StringUtil;

import org.json.adf.JSONObject;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.drawable.BitmapDrawable;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.os.Build;
import android.os.Handler;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.ImageView.ScaleType;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.Toast;

/***********************************************************************
 * 動画（埋め込み/差替え）  クラス
 ***********************************************************************/
public class VideoMountAction {
	private static final String TAG = "VideoMountAction";
	
	public interface VideoMountActionListener{
		void changeStatus(int index, String videofile, int status);
	}
	
	public interface SeekBarTouchListener{
		//SeekBarのタッチ開始時
        void onStartTrackingTouch();
		//SeekBarのタッチ終了時
        void onStopTrackingTouch();
	}
	
	// リスナー
	private VideoMountActionListener actionListener;
	private SeekBarTouchListener seekBarListener;
	
	// Activity, View
	private ContentViewActivity mActivity;
	private RelativeLayout mContentPageView;
	private LinearLayout mLayoutMain;
	private RelativeLayout mIconLayout;
	private LinearLayout mSurfaceViewLayout;
	private RelativeLayout controlLayout;
	private ActionSurfaceView surfaceView;
	private SurfaceHolder mHolder;
	private MediaPlayer mediaPlayer;
	private ImageButton mImgBtnPlay;
	private ImageButton mImgBtnMaxView;
	private SeekBar mSeekBar;
	
	// 定数
	private static int SEEKBAR_HEIGHT = 30;    //SeekBarの高さ
	public static final int VIDEO_MAX = 1006;
	public static final int VIDEO_DEFAULT = 1007;

	// Executor等
	private ScheduledExecutorService mExecutor;
	private Handler mHandler = new Handler();
	private MeetingManager meetingManager;

	// コンテンツ情報
	private Long contentId;
	private Integer pageNumber;
	private Long objectId;
	private String mVideofile;                //動画ファイル
	private int mIndex;
	private List<String> fileNames;   // 差し替え動画ファイル
	private long tid;                 // TargetID
	private PageObjectJSON pageObject;

	// 座標・サイズ
	private int mX;
	private int mY;
	private int mW;
	private int mH;
	private int mSeekBarHeight;

	// フラグ等
	private int mCurrentPosition;             //SeekBar現在値
	private boolean isMax;              //最大化フラグ
	private boolean isConfigured;
	private boolean isPrepared;
	private boolean repeatable;
	private boolean isChangeVideo = false; // 差替え動画か通常の埋め込み動画か
	private int errorCount;
	private int retryCount = 0;
	
	// オブジェクトログ関連
	private int objectLogId = -1;
	public int readingLogId = -1;
	private int actionTime = 0;

	public VideoMountAction(ContentViewActivity contentViewActivity, Long contentId, PageObjectJSON pageObject, RelativeLayout contentPageView, int readingLogId) {
		this.pageObject = pageObject;
		this.contentId = contentId;
		this.pageNumber = pageObject.getPageNumber();
		this.objectId = pageObject.getActionInfo().getObjectId();
		this.readingLogId = readingLogId;
		mActivity = contentViewActivity;
      	mContentPageView = contentPageView;
		meetingManager = MeetingManager.getInstance();
		repeatable = PreferenceUtil.get(mActivity, DefPrefKey.REPEATABLE_PLAY, contentViewActivity.getResources().getBoolean(R.bool.repeat_default));
	}
	
	/**
	 *  動画表示領域の設定
	 * 
	 * @param x
	 * @param y
	 * @param w
	 * @param h
	 * @param fscale
	 * @param videofile
	 */
    public void configureVideoView(int x, int y, int w, int h, float fscale, String videofile) {
      	mVideofile = videofile;
    	mX = x;
    	mY = y;
    	mW = w;
    	mH = h;
    	
    	float tmpDensity = mActivity.getResources().getDisplayMetrics().density;
    	mSeekBarHeight = (int)(SEEKBAR_HEIGHT * tmpDensity + 0.5f);
      	isMax = false;
      	
    	mLayoutMain = new LinearLayout(mActivity);
    	mLayoutMain.setBackgroundColor(0);
    	mLayoutMain.setOrientation(LinearLayout.VERTICAL);
    	
      	// 動画表示領域
    	mSurfaceViewLayout = new LinearLayout(mActivity) {
    		private long prevTime;

			@Override
    		public boolean dispatchTouchEvent(MotionEvent ev) {
    			Logger.d(TAG, "dispatchTouchEvent mMaxViewFlg=" + isMax + " ev=" + ev);
				if (System.currentTimeMillis() - prevTime < 300) {
					return true;
				}
				prevTime = System.currentTimeMillis();
				
    			if (controlLayout.getVisibility() == View.VISIBLE) {
        			controlLayout.setVisibility(View.INVISIBLE);
    			}
    			else {
        			controlLayout.setVisibility(View.VISIBLE);
        			mLayoutMain.bringToFront();
        			controlLayout.bringToFront();
    			}

    			return true;
    		}
			
			@Override
			public void onDraw(Canvas canvas) {
				super.onDraw(canvas);
				if (!isConfigured) {
					return;
				}
				((ActionSurfaceView)getChildAt(0)).doDraw(canvas);
			}
    	};
    	mSurfaceViewLayout.setOrientation(LinearLayout.VERTICAL);
    	mSurfaceViewLayout.setBackgroundColor(0);
    	
    	surfaceView = new ActionSurfaceView(mActivity); 
    	surfaceView.setOriginalSize(w, h, y, x);
    	surfaceView.setBackgroundColor(0);
        LinearLayout.LayoutParams surfaceViewParam = new LinearLayout.LayoutParams(w, h);
        mSurfaceViewLayout.addView(surfaceView, surfaceViewParam);
    	
    	mHolder = surfaceView.getHolder();
//        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); // これが2.3.3で重要

        LinearLayout.LayoutParams surfaceViewLayoutParam = new LinearLayout.LayoutParams(w, h);   //W,H 横幅、高さ
      	mLayoutMain.addView(mSurfaceViewLayout, surfaceViewLayoutParam);
      	
		// コントロールレイアウト
		LayoutInflater layoutInflater = (LayoutInflater)mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		controlLayout = (RelativeLayout)layoutInflater.inflate(R.layout.videoview_emb, null);
		controlLayout.setBackgroundColor(Color.parseColor("#8025120C")); // なぜかここでセットしないと、差替え動画の時色が変わってしまう。

    	mImgBtnPlay = (ImageButton)controlLayout.findViewById(R.id.btnPlay); // 再生・一時停止ボタン 
    	mSeekBar = (SeekBar)controlLayout.findViewById(R.id.mVideoSeekBar); //SeekBar
    	if (w < 120 * tmpDensity) {
    		mSeekBar.setVisibility(View.INVISIBLE); // 横幅が短い場合は表示しない。
    	}
    	mImgBtnMaxView =  (ImageButton) controlLayout.findViewById(R.id.btnZoom); //最大表示ボタン
    	
      	LinearLayout.LayoutParams controlLayoutParam = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, mSeekBarHeight);                    //W,H 横幅、高さ
    	mLayoutMain.addView(controlLayout, controlLayoutParam);
    	controlLayout.setVisibility(View.INVISIBLE);
    	
    	surfaceView.setVisibility(View.INVISIBLE); 
    	
    	RelativeLayout.LayoutParams layoutMainParam = new RelativeLayout.LayoutParams(w, h + mSeekBarHeight);
    	layoutMainParam.setMargins(x, y, 0, 0);
    	mContentPageView.addView(mLayoutMain, layoutMainParam);


    	//***** SeekBarセット
    	mCurrentPosition = 0;
		mSeekBar.setProgress(mCurrentPosition);   //現在値（初期値）
    	mSeekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
    		//SeekBarの値が変わったとき 
    		@Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
    			if (fromUser) {   //ユーザ操作の場合
    				seekTo(progress);
    		        if (meetingManager.isSendable()) {
    		        	JSONObject json = new JSONObject();
    					json.put(MeetingManager.TYPE, isPlaying(mediaPlayer)? MeetingManager.START: MeetingManager.PAUSE);
    					json.put(MeetingManager.PLAY_TIME, progress / 1000);
    		        	meetingManager.sendWs(MeetingManager.CMD_MOVIEACTION, contentId, pageNumber, objectId, json);
    		        }
    			}
    		}
    		//SeekBarのタッチ開始時
			@Override
            public void onStartTrackingTouch(SeekBar seekBar) {
				seekBarListener.onStartTrackingTouch();
			}
			//SeekBarのタッチ終了時
			@Override
            public void onStopTrackingTouch(SeekBar seekBar) {
				seekBarListener.onStopTrackingTouch();
			}
    	});
    	
    	//***** 再生、停止ボタン
    	mImgBtnPlay.setOnClickListener(new View.OnClickListener() {
	        @Override
	        public void onClick(View v) {
	        	if (isPlaying(mediaPlayer)) {
	        		pauseVideo();
	        	} else {
	        		pauseAfterStartVideo();
	        	}
	        }
		});
    	
    	//***** 最大表示ボタン
      	mImgBtnMaxView.setOnClickListener(new View.OnClickListener() {
	        @Override
	        public void onClick(View v) {
	    		isMax = !isMax;
		        if (meetingManager.isSendable()) {
		        	JSONObject json = new JSONObject();
					json.put(MeetingManager.IS_FULL_SCREEN, isMax);
		        	meetingManager.sendWs(MeetingManager.CMD_MOVIEACTION, contentId, pageNumber, objectId, json);
		        }

	        	if (isMax) {
	        		// 最大表示
	        		actionListener.changeStatus(mIndex, mVideofile, VIDEO_MAX);
	        		showMax();
	        	} else {
	        		// 元のサイズに戻す
	        		actionListener.changeStatus(mIndex, mVideofile, VIDEO_DEFAULT);
	        		showDefault();
	        	}
	        }
		});
    	
      	isConfigured = true;
    }
    
    //***** 動画アイコンの追加
    public void addVideoIcon(float iconScale, String iconPosition) {
		// クリック可能エリア（TODO:later　あとでサムネイルを入れる）
		mIconLayout = new RelativeLayout(mActivity); 
		//noinspection deprecation(API16から非推奨になった。無視)
      	mIconLayout.setBackgroundDrawable(mActivity.getResources().getDrawable(R.drawable.border));   //枠線表示
      	mIconLayout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
            	videoOnClick(mContentPageView);
            }
        });

		// 再生アイコン
		ImageButton playIcon = new ImageButton(mActivity);
		playIcon.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
            	videoOnClick(mContentPageView);
            }
		});
		playIcon.setBackgroundColor(0); 
		if (isChangeVideo) {
			playIcon.setImageDrawable(mActivity.getResources().getDrawable(android.R.drawable.ic_media_play));   //再生ボタン表示
		}
		else {
			int videoIconSize = 196;
			int scaleIcon = (int) (videoIconSize * iconScale) ;
			if(scaleIcon > 0){
				Bitmap bg = BitmapUtil.getResizedBitmapResource(mActivity.getResources(), R.drawable.play, scaleIcon, scaleIcon, Bitmap.Config.RGB_565, false);
				playIcon.setImageDrawable(new BitmapDrawable(mActivity.getResources(), bg));
			}
		}
		playIcon.setScaleType(ScaleType.MATRIX); 
		
		RelativeLayout.LayoutParams param = mActivity.createIconPosition(Integer.parseInt(iconPosition));
        mIconLayout.addView(playIcon, param);
        
    	RelativeLayout.LayoutParams param1 = new RelativeLayout.LayoutParams(mW, mH);
    	param1.setMargins(mX, mY, 0, 0);
      	mContentPageView.addView(mIconLayout , param1);
    }
    
    private void videoOnClick(RelativeLayout contentPageView) {
    	if (((ZoomRelativeLayout)contentPageView).isZooming() == false) {
			//動画の表示・再生
			if (meetingManager.isSendable()) {
    			meetingManager.sendWs(MeetingManager.CMD_ACTION, contentId, pageNumber, objectId, null);
    		}
    		
    		// オブジェクトログ
    		objectLogId = ContentLogUtil.getInstance().insertContentObjectLog(contentId, readingLogId, pageObject);
    		
    		mImgBtnPlay.setImageDrawable(mActivity.getResources().getDrawable(android.R.drawable.ic_media_pause));   //停止ボタン表示
        	try {
        		mExecutor.shutdownNow();
        	} catch (Exception e) {
        	}
			controlLayout.setVisibility(View.INVISIBLE);
        	start(mVideofile, 0);
    	}
	}

    /**
     * 
     * 動画ファイルを再生する。
     * 
     * 同じオブジェクトへの連打への対策としてsynchronizedにする。通常の連打ならOKだが、
     * 激しい連打をすると、onPreparedの前にこの別のスレッドからメソッドが走って
     * IOException ((1, -2147483648) error)が発生しうる
     * The surface has been releasedエラーを防ぐため、毎回MediaPlayerのインスタンスを生成する。
     * 
     * @param videofile
     * @param seek
     */
	public synchronized void start(String videofile, int seek) {
		Logger.d(TAG, "==============Video START============= " + videofile + "(" + seek + ")");
		actionTime = 0;

		if (StringUtil.isNullOrEmpty(videofile)) {
			return;
		}

		startStep1();
		startStep2(videofile, seek);
	}

	public synchronized void start(String videofile, int seek, int objectLogId) {
		Logger.d(TAG, "==============Video START============= " + videofile + "(" + seek + ")");
		if (StringUtil.isNullOrEmpty(videofile)) {
			return;
		}
		startStep1();
		// STOPする前にオブジェクトログIDを入れ替えると更新対象が入れ替わってしまうのでここで書き換える
		this.objectLogId = objectLogId;
		actionTime = 0;
		startStep2(videofile, seek);
	}
    
    private void startStep1(){
		if (isChangeVideo) {
        	mActivity.stopCurrentPageMountVideo(null, false);
        	mActivity.stopCurrentPageChangeVideo(mIndex, false);
        	if (mediaPlayer != null && isPlaying(mediaPlayer)) {
        		stopVideo(false);
        	}
    	}
    	else {
    		mActivity.stopCurrentPageMountVideo(mIndex, false);
    		mActivity.stopCurrentPageChangeVideo(null, false);
    	}

    	if (mExecutor != null) {
    		mExecutor.shutdownNow();
		}
    }
    
    private void startStep2(String videofile, int seek){
    	isPrepared = false;
    	mVideofile = videofile;
    	
    	surfaceView.setVisibility(View.VISIBLE); // setDisplay,prepareの前にVISIBLEにしないと表示されなくなる。ここは決定的に重要。
		mLayoutMain.bringToFront();
		releaseNoThrow();
		
		mediaPlayer = new MediaPlayer();
		addPlayerListener();
        errorCount = 0;
    	
		try {
			
			mediaPlayer.reset();
			mHolder = surfaceView.getHolder();
    		mediaPlayer.setDisplay(mHolder);
    		FileInputStream fis = null;
    		try {
    			fis = new FileInputStream(mVideofile);
                try {
                    RuntimeUtil.exec("chmod 754 " + mVideofile);
                } catch (IOException e) {
                    Logger.e(TAG, "chmod error. " + mVideofile, e);
                }
                mediaPlayer.setDataSource(fis.getFD());

            } finally {
    			if (fis != null) {
    				fis.close();
    			}
    		}

           	mediaPlayer.setLooping(repeatable);
    		mSeekBar.setProgress(seek);
    		mediaPlayer.prepare();
		} catch (Exception e) {
			Logger.e(TAG, "ReStart error ", e);
			ABVToastUtil.showMakeText(mActivity, "Video Start Error", Toast.LENGTH_LONG);
			releaseNoThrow();
		}
    }

	protected void releaseNoThrow() {
		if (mediaPlayer != null) {
			try {
				mediaPlayer.release();
			} catch (Exception e) { // ignore
				Logger.e(TAG, "mediaPlayer.release error. " + e.toString());
			}
		}
        if (mExecutor != null) {
        	mExecutor.shutdownNow();
        }
	}

    /**
     * mediaPlayerが再生中かどうかを返す。
     * isPlaying()でIllegalStateExceptionが発生することがあるが無視。これ以外にStateを取るメソッドなし。
     * 
     * @param mediaPlayer
     * @return
     */
	private boolean isPlaying(MediaPlayer mediaPlayer) {
		try {
			return mediaPlayer.isPlaying();
		} catch (IllegalStateException e) { // ignore 
			return false;
		}
	}

	private void addPlayerListener() {
    	mediaPlayer.setOnErrorListener(new OnErrorListener() {
			@Override
			public boolean onError(MediaPlayer arg0, int arg1, int arg2) {
		    	Logger.e(TAG, "mediaPlayer setOnError arg1=" + arg1 + " arg2=" + arg2);
				try {
            		mExecutor.shutdownNow();
            	} catch (Exception e) {
            		
            	}
				surfaceView.setVisibility(View.INVISIBLE);
				mIconLayout.setVisibility(View.VISIBLE);
		    	mLayoutMain.setVisibility(View.INVISIBLE);
//		    	isPrepared = false;
//				ABVToastUtil.makeText(mActivity, "Video Play Error", Toast.LENGTH_SHORT); // ここでは表示しない
				
				errorCount++;
				if (errorCount > 10) { // error -38が続く場合、いったんリリースする。
					releaseNoThrow();
					ABVToastUtil.showMakeText(mActivity, mActivity.getString(R.string.MOVIE_FATAL_ERROR), Toast.LENGTH_LONG);
					errorCount = 0;
					isPrepared = false;
				}
				return false;
			}
    	});
    	
    	//***** 動画の再生準備ができたとき
    	mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
    		@Override
            public void onPrepared(MediaPlayer mp) {
    			Logger.v(TAG, "mediaPlayer onPrepared w=%s h=%s", mp.getVideoWidth(), mp.getVideoHeight());
    			isPrepared = true;
    			mSeekBar.setMax(mediaPlayer.getDuration());   //SeekBar最大値セット
    			videoStart();
    		}
    		
    		private void videoStart() {
    	    	mImgBtnPlay.setImageDrawable(mActivity.getResources().getDrawable(android.R.drawable.ic_media_pause));   //停止ボタン表示
    	    	mActivity.stopSound();   //再生中のAudioPlayerを一時停止
    	    	mIconLayout.setVisibility(View.INVISIBLE);
    	    	mLayoutMain.setVisibility(View.VISIBLE);
    	    	surfaceView.setVisibility(View.VISIBLE);
    	    	controlLayout.bringToFront();
    	    	mLayoutMain.bringToFront();

    	    	mIconLayout.setOnTouchListener(new View.OnTouchListener() {
    				@Override
    				public boolean onTouch(View v, MotionEvent event) {
    					return true;
    				}
    			});
    	    	
    	    	mediaPlayer.start();
    	    	
    			//指定時間毎に処理を呼び出す
    	    	runExecutor();
    	    }
    	});
    	
    	//***** ビデオの再生が完了したらOnCompletionイベントが発生
    	mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
        	@Override
        	public void onCompletion(MediaPlayer mp) {
				try {
					mp.release();
				} catch (Exception e) {
					Logger.e(TAG, e);
				}
				Logger.d(TAG, "mediaPlayer onCompletion repeatable=" + repeatable);
        		if (!repeatable) {
        			stopVideo();
        			mActivity.playPageBGMSound();
        			if (isMax) {
        				showDefault();
        			}
        		}
        	}
    	});
	}
    
	/**
	 * 停止後の再生
	 */
    public void pauseAfterStartVideo() {
    	Logger.d(TAG, "==============Video PAUSE&START=============isPrepared=" + isPrepared);
    	
    	if (mediaPlayer == null) {
    		return;
    	}
    	
        if (meetingManager.isSendable()) {
            JSONObject json = new JSONObject();
    		json.put(MeetingManager.TYPE, MeetingManager.START);
    		json.put(MeetingManager.PLAY_TIME, mCurrentPosition / 1000);
            meetingManager.sendWs(MeetingManager.CMD_MOVIEACTION, contentId, pageNumber, objectId, json);
        }

   		mImgBtnPlay.setImageDrawable(mActivity.getResources().getDrawable(android.R.drawable.ic_media_pause));
   		mActivity.stopSound();   
    	mIconLayout.setVisibility(View.INVISIBLE);
    	mLayoutMain.setVisibility(View.VISIBLE);
    	surfaceView.setVisibility(View.VISIBLE);
   		
    	if (isPrepared) {
    		mediaPlayer.start();
    	}
    	else {
    		try {
				mediaPlayer.prepare();
			} catch (IllegalStateException e) {
				Logger.e(TAG, "prepare failed", e); // ignore
			} catch (IOException e) {
				Logger.e(TAG, "prepare failed", e); // ignore
			}
    	}
	
		//指定時間毎に処理を呼び出す
    	runExecutor();
    }
    
    /**
     * 一時停止
     */
    public void pauseVideo() {
        if (meetingManager.isSendable()) {
        	JSONObject json = new JSONObject();
			json.put(MeetingManager.TYPE, MeetingManager.PAUSE);
			json.put(MeetingManager.PLAY_TIME, mCurrentPosition / 1000);
        	meetingManager.sendWs(MeetingManager.CMD_MOVIEACTION, contentId, pageNumber, objectId, json);
        }

        if (mExecutor != null) {
        	boolean logUpdateFlg = mExecutor.isShutdown();
        	mExecutor.shutdownNow();
        	if(!logUpdateFlg){
        		ContentLogUtil.getInstance().updateActionTime(contentId, objectLogId, actionTime);
        	}
        }
        if (mediaPlayer != null) {
        	mediaPlayer.pause();
        	mActivity.playPageBGMSound();
        }
        
		mImgBtnPlay.setImageDrawable(mActivity.getResources().getDrawable(android.R.drawable.ic_media_play));    //再生ボタン表示
    }

    /**
     * 動画終了
     * 
     */
	public void stopVideo() {
		stopVideo(true);
	}

	public void stopVideo(boolean videoInvisible) {
		retryCount = 0;
		isPrepared = false;
        if (mExecutor != null) {
        	boolean logUpdateFlg = mExecutor.isShutdown();
        	mExecutor.shutdownNow();
        	if(!logUpdateFlg){
        		ContentLogUtil.getInstance().updateActionTime(contentId, objectLogId, actionTime);
        	}
        }
    	try {
    		if (mediaPlayer != null && isPlaying(mediaPlayer)) {
    			mediaPlayer.stop();
    			mediaPlayer.release();
    		}
    	} catch (Exception e) {
    		Logger.e(TAG, "stop failed.", e);
    	}
	    
    	if (videoInvisible) {
    		surfaceView.setVisibility(View.INVISIBLE);
    		mIconLayout.setVisibility(View.VISIBLE);
    		mLayoutMain.setVisibility(View.INVISIBLE);
    		mImgBtnPlay.setImageDrawable(mActivity.getResources().getDrawable(android.R.drawable.ic_media_play));   //再生ボタン表示
    		
    		mIconLayout.setOnTouchListener(new View.OnTouchListener() {
    			@Override
    			public boolean onTouch(View v, MotionEvent event) {
    				return false;
    			}
    		});
    	}
    	try {
			RuntimeUtil.exec("chmod 750 " + mVideofile);
		} catch (IOException e) {
			Logger.e(TAG, "chmod error. " + mVideofile, e);
		}
    }
    
	private void runExecutor() {
		mExecutor = Executors.newSingleThreadScheduledExecutor();
    	mExecutor.scheduleAtFixedRate(new Runnable() {
    		@Override
    		public void run() {
    			mHandler.post(new Runnable() {
					@Override
					public void run() {
						try {
							if((mediaPlayer.getCurrentPosition()  - mCurrentPosition) > 0){
								actionTime += (mediaPlayer.getCurrentPosition()  - mCurrentPosition);
							}
							mCurrentPosition = mediaPlayer.getCurrentPosition();
							mSeekBar.setProgress(mCurrentPosition);
							if (mediaPlayer.getVideoHeight() == 0 && retryCount == 0) { // height>0でも真っ黒になる場合がある
								retryCount++;
								start(mVideofile, 0);
							}
						} catch (Exception e) {
							Logger.e(TAG, "mExecutor error." + e.toString());
						}
					}
				});
    		}
    	}, 200, 200, TimeUnit.MILLISECONDS);
	}
    
	/**
	 * ジャンプ
	 * 
	 * @param progress
	 */
	public void seekTo(int progress) {
		mCurrentPosition = progress;
		mediaPlayer.seekTo(mCurrentPosition);
	}

    /**
     *  最大表示
     *  
     *  バーを除いたディスプレイのサイズにアスペクト比をぴったりと合わせている模様
     *  
     */
    public void showMax() {
		isMax = true;
		Point point = DisplayUtil.getDisplaySize(mActivity);
    	final int dispWidth = point.x;
    	final int dispHeight = point.y;
    	float tmpDensity = mActivity.getResources().getDisplayMetrics().density;
    	int seekBarHeight = (int)(SEEKBAR_HEIGHT * tmpDensity + 0.5f);        	
    	int iHeight = dispHeight - seekBarHeight;   //dispHeight - seekBarHeight - 45
    	if (Build.VERSION.SDK_INT == 12 || Build.VERSION.SDK_INT == 11) { // Version 3.1 or 3.0
    		iHeight = iHeight - 48;
    	}

    	int sw;
    	int sh;
    	if (mW > mH) {
    		sw = dispWidth;
    		sh = (int)((float)mH * (float)dispWidth / (float)mW);
    		if (sh > iHeight) {
    			sh = iHeight;
    			sw = (int)((float)mW * (float)iHeight / (float)mH);
    		}
    	} else {
    		sh = iHeight;
    		sw = (int)((float)mW * (float)iHeight / (float)mH);
    		if (sw > dispWidth) {
    			sw = dispWidth;
    			sh = (int)((float)mH * (float)dispWidth / (float)mW);
    		}
    	}
    	int iLeft = (dispWidth - sw) / 2;
    	int iTop = (iHeight - sh) / 2;
    	surfaceView.setMaxView(true, sw, sh, iLeft, iTop);

    	LinearLayout.LayoutParams paramLin1_ = new LinearLayout.LayoutParams(dispWidth, iHeight);
    	mSurfaceViewLayout.setLayoutParams(paramLin1_);
    	mSurfaceViewLayout.refreshDrawableState();

    	RelativeLayout.LayoutParams paramRe1_ = new RelativeLayout.LayoutParams(dispWidth, dispHeight);
    	mLayoutMain.setLayoutParams(paramRe1_);
    	mLayoutMain.setBackgroundColor(Color.parseColor("#FF000000"));
    	mLayoutMain.bringToFront();   //前面表示

    	mSeekBar.setVisibility(View.VISIBLE);
    	mImgBtnMaxView.setImageDrawable(mActivity.getResources().getDrawable(R.drawable.ic_menu_zoom_out));

    	surfaceView.invalidate();
    }
    
    /**
     *  元のサイズに戻す
     */
    public void showDefault() {
		isMax = false;
    	surfaceView.setMaxView(false, 0, 0, 0, 0);

    	LinearLayout.LayoutParams paramLin1_ = new LinearLayout.LayoutParams(mW, mH);
    	mSurfaceViewLayout.setLayoutParams(paramLin1_);
    	mSurfaceViewLayout.refreshDrawableState();

    	float tmpDensity = mActivity.getResources().getDisplayMetrics().density;
    	int seekBarHeight = (int)(SEEKBAR_HEIGHT * tmpDensity + 0.5f);
    	RelativeLayout.LayoutParams paramRe1_ = new RelativeLayout.LayoutParams(mW, mH + seekBarHeight);
    	paramRe1_.setMargins(mX, mY, 0, 0);
    	mLayoutMain.setLayoutParams(paramRe1_); 
    	mLayoutMain.setBackgroundColor(0);

    	if (isChangeVideo) {
    		mActivity.stopCurrentPageMountVideo(null, false);
    		mActivity.stopCurrentPageChangeVideo(mIndex, false);
    	}
    	else {
    		mActivity.stopCurrentPageMountVideo(mIndex, false);
    		mActivity.stopCurrentPageChangeVideo(null, false);
    	}

    	if (mW < 120 * tmpDensity) {
    		mSeekBar.setVisibility(View.INVISIBLE); // 横幅が短い場合は表示しない。
    	}
    	
    	mImgBtnMaxView.setImageDrawable(mActivity.getResources().getDrawable(android.R.drawable.ic_menu_zoom));
    }

    public void setDefaultPosition() {
    	LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(mW, mH);
		surfaceView.setLayoutParams(params);
    }
    
    
    ////////////////////////  getter & setter //////////////////////

	public void setActionListener(VideoMountActionListener actionListener) {
		this.actionListener = actionListener;
	}

	public void setSeekBarListener(SeekBarTouchListener seekBarListener) {
		this.seekBarListener = seekBarListener;
	}

    public void setIndex(int index) {
    	mIndex = index;
    }
    public int getIndex() {
    	return mIndex;
    }    
    
    public void setFileNames(List<String> fileNames) {
    	this.fileNames = fileNames;
	}
	
	public String getFileName(int index) {
		return fileNames.get(index);
	}
	public void setID(long id) {
		this.tid = id;
	}
	public long getID() {
		return tid;
	}
	
    public void setSurfaceVisibility(int status) {
		surfaceView.setVisibility(status);
	}
    
	public int getSurfaceVisibility() {
		return surfaceView.getVisibility();
	}
	
	public void setObjectId(long objectId) {
		this.objectId = objectId;
	}

	public Long getObjectId() {
		return objectId;
	}

	public boolean isPrepared() {
		return isPrepared;
	}
	
	public String getVideoFile() {
		return mVideofile;
	}

	public boolean isChangeVideo() {
		return isChangeVideo;
	}

	public void setChangeVideo(boolean isChangeVideo) {
		this.isChangeVideo = isChangeVideo;
	}

	public Integer getPageNumber() {
		return pageNumber;
	}
}
