package jp.sourceforge.nicoro;

import static jp.sourceforge.nicoro.Log.LOG_TAG;

import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

import org.apache.http.client.ClientProtocolException;
import org.apache.http.impl.client.DefaultHttpClient;

import jp.sourceforge.nicoro.AbstractNicoroPlayer.MessageData;
import jp.sourceforge.nicoro.NicoroAPIManager.ParseGetFLVJikkyo;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.TextView;
import android.widget.ToggleButton;

public class NicoroJikkyoPlayer extends Activity
implements MessageView.Callback {
	private static final boolean DEBUG_LOGD = Release.IS_DEBUG && true;
    private static final boolean DEBUG_LOGV = Release.IS_DEBUG && false;

	private static final int MSG_ID_MESSAGE_DRAW_MESSAGE = 0;
	private static final int MSG_ID_MESSAGE_ADDED_MESSAGE = 1;
	private static final int MSG_ID_MESSAGE_OCCURRED_ERROR = 2;

	public static final String INTENT_NAME_COOKIE = "COOKIE";
	public static final String INTENT_NAME_JIKKYO_NUMBER = "JIKKYO_NUMBER";
	public static final String INTENT_NAME_MESSAGE_URL = "MESSAGE_URL";
	public static final String INTENT_NAME_MESSAGE_PORT = "MESSAGE_PORT";
	public static final String INTENT_NAME_THREAD_ID = "THREAD_ID";
	public static final String INTENT_NAME_USER_ID = "USER_ID";
	public static final String INTENT_NAME_HTTP_PORT = "HTTP_PORT";

	private SurfaceView mCameraPreview;
	private Camera mCamera;
	private MessageView mMessageView;
	private TextView mChannelName;

	private ViewGroup mPlayerController;
	private ToggleButton mButtonCameraOnOff;

	private SurfaceHolder.Callback mCameraPreviewCallback;

	private LiveMessageLoader mLiveMessageLoader;

//    private Matrix mMatrixMessage = new Matrix();
//    private Random mRandom = new Random();
	private MessageData mMessageData = new MessageData();
	private long mStartTime;
//    private Paint mPaintText = new Paint();

    private MessageChatController mMessageChatController = new MessageChatController();

    private SharedPreferences mSharedPreferences;

    private PlayerInfoControllerManager mPlayerInfoControllerManager;

	private Handler mHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			if (mHandler == null) {
				if (DEBUG_LOGD) {
					Log.d(LOG_TAG, Log.buf().append("Activity was destroyed. ignore message=")
							.append(msg.toString()).toString());
				}
				return;
			}
			switch (msg.what) {
			case MSG_ID_MESSAGE_DRAW_MESSAGE:
				if (!isFinishing()) {
					mMessageView.invalidate();

					Message message = mHandler.obtainMessage(
							MSG_ID_MESSAGE_DRAW_MESSAGE);
					mHandler.sendMessageDelayed(message, 33L);
				}
				break;
			case MSG_ID_MESSAGE_ADDED_MESSAGE:
				if (!hasMessages(MSG_ID_MESSAGE_DRAW_MESSAGE)) {
					mHandler.sendEmptyMessageDelayed(MSG_ID_MESSAGE_DRAW_MESSAGE, 33L);
				}
				break;
			case MSG_ID_MESSAGE_OCCURRED_ERROR:
				Util.showErrorDialog(NicoroJikkyoPlayer.this,
						(String) msg.obj, true);
				break;
			default:
				super.handleMessage(msg);
				break;
			}
		}
	};

	private class GetFLVTask extends AsyncTask<String, Void, ParseGetFLVJikkyo> {
		public void executeWrapper(String jikkyoNumber, String cookieUserSession,
				String userAgent) {
			execute(jikkyoNumber, cookieUserSession, userAgent);
		}

		@Override
		protected ParseGetFLVJikkyo doInBackground(String... params) {
			assert params.length == 3;

			final String jikkyoNumber = params[0];
			final String cookieUserSession = params[1];
			final String userAgent = params[2];

			ParseGetFLVJikkyo parseGetFLVJikkyo = null;
			try {
				DefaultHttpClient httpClient = Util.createHttpClient();
				httpClient.getCookieStore().clear();
				parseGetFLVJikkyo = new ParseGetFLVJikkyo();
				parseGetFLVJikkyo.initialize(httpClient,
						jikkyoNumber,
						cookieUserSession, userAgent);
			} catch (ClientProtocolException e) {
				Log.d(LOG_TAG, e.toString(), e);
			} catch (IOException e) {
				Log.d(LOG_TAG, e.toString(), e);
			}

			return parseGetFLVJikkyo;
		}

		@Override
		protected void onPostExecute(ParseGetFLVJikkyo result) {
			if (result == null) {
				return;
			}
			ParseGetFLVJikkyo parseGetFLVJikkyo = result;

			String cookieUserSession = mSharedPreferences.getString(
					NicoroConfig.COOKIE_USER_SESSION, null);
			final String messageUrl = parseGetFLVJikkyo.get("ms");
			final String messagePort = parseGetFLVJikkyo.get("ms_port");
			final String threadId = parseGetFLVJikkyo.get("thread_id");
			final String userId = parseGetFLVJikkyo.get("user_id");

			mLiveMessageLoader = new LiveMessageLoader(messageUrl,
	    			messagePort,
//	    			httpPort,
	    			threadId, cookieUserSession, userId,
	    			getApplicationContext());
			mLiveMessageLoader.setEventListener(new LiveMessageLoader.EventListener() {
			    @Override
		        public void onConnected(LiveMessageLoader loader) {
                    // nothing
		        }
				@Override
				public void onAddedMessage(LiveMessageLoader loader) {
                    if (mHandler != null) {
    					if (!mHandler.hasMessages(MSG_ID_MESSAGE_ADDED_MESSAGE)) {
    						mHandler.sendEmptyMessage(MSG_ID_MESSAGE_ADDED_MESSAGE);
    					}
                    }
				}
				@Override
				public void onFinished(LiveMessageLoader loader) {
					// nothing
				}
				@Override
				public void onOccurredError(LiveMessageLoader loader,
						String errorMessage) {
					if (mHandler != null) {
						Message message = mHandler.obtainMessage(MSG_ID_MESSAGE_OCCURRED_ERROR, errorMessage);
						mHandler.sendMessage(message);
					}
				}
			});
			mLiveMessageLoader.startLoad();

			final String channelName = parseGetFLVJikkyo.get("channel_name");
			if (channelName != null) {
				mChannelName.setText(channelName);
			}
		}
	}
	private GetFLVTask mGetFLVTask;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

        if (DEBUG_LOGD) {
        	Log.d(LOG_TAG, "NicoroJikkyoPlayer onCreate");
        }

		setContentView(R.layout.nicoro_jikkyoplayer);
		mCameraPreview = (SurfaceView) findViewById(R.id.camera);
		SurfaceHolder holder = mCameraPreview.getHolder();
		holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
		mCameraPreviewCallback = new SurfaceHolder.Callback() {
			@Override
			public void surfaceChanged(SurfaceHolder holder, int format,
					int width, int height) {
		        if (DEBUG_LOGD) {
		        	Log.d(LOG_TAG, Log.buf().append("surfaceChanged format=")
		        			.append(format).append(" width=").append(width)
		        			.append(" height=").append(height).toString());
		        }

				if (mCamera != null) {
					mCamera.stopPreview();
					Camera.Parameters params = mCamera.getParameters();
//					params.setPreviewFormat(format);
					params.setPreviewFormat(PixelFormat.JPEG);
					params.setPreviewSize(width, height);
//					params.setPreviewSize(640, 480);
					mCamera.setParameters(params);
					mCamera.startPreview();
				}
			}
			@Override
			public void surfaceCreated(SurfaceHolder holder) {
				if (mCamera != null) {
//					mCamera.startPreview();
					try {
						mCamera.setPreviewDisplay(holder);
					} catch (IOException e) {
						Log.e(LOG_TAG, e.toString(), e);
					}
				}
			}
			@Override
			public void surfaceDestroyed(SurfaceHolder holder) {
				if (mCamera != null) {
					mCamera.stopPreview();
				}
			}
		};
		holder.addCallback(mCameraPreviewCallback);

		mCamera = Camera.open();
//		try {
//			mCamera.setPreviewDisplay(holder);
//		} catch (IOException e) {
//			Log.e(LOG_TAG, e.getMessage(), e);
//		}

		mChannelName = (TextView) findViewById(R.id.channel_name);

		mMessageView = (MessageView) findViewById(R.id.message_view);
		mMessageView.setCallback(this);

		mMessageData.mChatsWait =
			new LinkedList<MessageChat>();
		mMessageData.mChatsRunningNaka =
			new LinkedList<MessageChat>();
		mMessageData.mChatsRunningShita =
			new LinkedList<MessageChat>();
		mMessageData.mChatsRunningUe =
			new LinkedList<MessageChat>();

        mPlayerController = (ViewGroup) findViewById(R.id.player_controller);
        mButtonCameraOnOff = (ToggleButton) findViewById(R.id.button_camera_onoff);
        mButtonCameraOnOff.setChecked(false);
        mButtonCameraOnOff.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
			@Override
			public void onCheckedChanged(CompoundButton buttonView,
					boolean isChecked) {
				if (isChecked) {
				    if (mCameraPreview != null) {
				        mCameraPreview.setVisibility(View.VISIBLE);
				    }
					mCamera.startPreview();
				} else {
                    if (mCameraPreview != null) {
                        mCameraPreview.setVisibility(View.INVISIBLE);
                    }
					mCamera.stopPreview();
				}
			}
        });
        assert mCameraPreview.getVisibility() != View.VISIBLE;

        mPlayerInfoControllerManager = new PlayerInfoControllerManager(
                getApplicationContext(), null, mPlayerController, null);

		mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(
				getApplicationContext());
        Intent intent = getIntent();
        mGetFLVTask = new GetFLVTask();
		final String jikkyoNumber = intent.getStringExtra(
				NicoroJikkyoPlayer.INTENT_NAME_JIKKYO_NUMBER);
		final String cookieUserSession = mSharedPreferences.getString(
				NicoroConfig.COOKIE_USER_SESSION, null);
		final String userAgent = mSharedPreferences.getString(
				NicoroConfig.USER_AGENT, null);
        mGetFLVTask.executeWrapper(jikkyoNumber, cookieUserSession,
        		userAgent);

        boolean messageAntialias = mSharedPreferences.getBoolean(
				getString(R.string.pref_key_message_antialias), false);
        mMessageChatController.setAntiAlias(messageAntialias);
//        mPaintText.setAntiAlias(messageAntialias);

		final boolean showHintToast = mSharedPreferences.getBoolean(
				getString(R.string.pref_key_show_hint_toast), true);
		if (showHintToast) {
			Util.showInfoToast(getApplicationContext(),
					R.string.toast_explain_player_ctrl);
		}

		mStartTime = SystemClock.elapsedRealtime();
	}

	@Override
	protected void onDestroy() {
		mGetFLVTask.cancel(true);
    	if (mLiveMessageLoader != null) {
    		mLiveMessageLoader.finish();
    		mLiveMessageLoader = null;
    	}

		super.onDestroy();
		mCameraPreview.getHolder().removeCallback(mCameraPreviewCallback);
		mCameraPreviewCallback = null;
        mCameraPreview = null;
		mCamera.release();
		mCamera = null;
		mHandler = null;
	}

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

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

	@Override
    public boolean onTouchEvent(MotionEvent event) {
	    if (mPlayerInfoControllerManager.onTouchEvent(event)) {
			return true;
		}
		return super.onTouchEvent(event);
    }

	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
	    if (mPlayerInfoControllerManager.onKeyDown(keyCode, event)) {
	        return true;
	    }
		return super.onKeyDown(keyCode, event);
	}

	@Override
	public boolean onKeyUp(int keyCode, KeyEvent event) {
		return super.onKeyUp(keyCode, event);
	}

    @Override
    protected void finalize() throws Throwable {
    	try {
            if (DEBUG_LOGV) {
                Log.v(LOG_TAG, "NicoroJikkyoPlayer#finalize start");
            }
    		super.finalize();
    	} finally {
        	if (mLiveMessageLoader != null) {
        		mLiveMessageLoader.finish();
        	}
            if (DEBUG_LOGV) {
                Log.v(LOG_TAG, "NicoroJikkyoPlayer#finalize end");
            }
    	}
    }

	private static LiveMessageLoader createLiveMessageLoader(Intent intent, Context context,
			String userSession) {
		LiveMessageLoader liveMessageLoader = null;
		String cookie = intent.getStringExtra(
				NicoroJikkyoPlayer.INTENT_NAME_COOKIE);
		String jikkyoNumber = intent.getStringExtra(
				NicoroJikkyoPlayer.INTENT_NAME_JIKKYO_NUMBER);
		String messageUrl = intent.getStringExtra(
				NicoroJikkyoPlayer.INTENT_NAME_MESSAGE_URL);
		String messagePort = intent.getStringExtra(
				NicoroJikkyoPlayer.INTENT_NAME_MESSAGE_PORT);
		String threadId = intent.getStringExtra(
				NicoroJikkyoPlayer.INTENT_NAME_THREAD_ID);
		String userId = intent.getStringExtra(
				NicoroJikkyoPlayer.INTENT_NAME_USER_ID);
		String httpPort = intent.getStringExtra(
				NicoroJikkyoPlayer.INTENT_NAME_HTTP_PORT);

    	liveMessageLoader = new LiveMessageLoader(messageUrl,
    			messagePort,
//    			httpPort,
    			threadId, userSession, userId,
    			context);

		return liveMessageLoader;
	}

	@Override
	public void drawMessageView(MessageView messageView, Canvas canvas) {
		canvas.drawColor(0x00000000);
		// vposは現在時間基準
		final int vpos = (int) (SystemClock.elapsedRealtime() - mStartTime) / 10;

		mMessageChatController.drawMessageForLive(
				canvas, mMessageData, null, vpos,
				messageView.getWidth(), messageView.getHeight(),
				false, mLiveMessageLoader);
	}
}
