package com.codeim.youliao;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.Button;
import android.widget.CursorAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

import com.codeim.youliao.app.LazyImageLoader.ImageLoaderCallback;
import com.codeim.youliao.app.Preferences;
import com.codeim.youliao.data.Dm;
import com.codeim.youliao.db.MessageTable;
import com.codeim.youliao.db.TwitterDatabase;
import com.codeim.youliao.fanfou.DirectMessage;
import com.codeim.youliao.fanfou.Paging;
import com.codeim.youliao.http.HttpException;
import com.codeim.youliao.task.GenericTask;
import com.codeim.youliao.task.TaskAdapter;
import com.codeim.youliao.task.TaskListener;
import com.codeim.youliao.task.TaskParams;
import com.codeim.youliao.task.TaskResult;
import com.codeim.youliao.ui.base.BaseActivity;
import com.codeim.youliao.ui.base.Refreshable;
import com.codeim.youliao.ui.module.Feedback;
import com.codeim.youliao.ui.module.FeedbackFactory;
import com.codeim.youliao.ui.module.FeedbackFactory.FeedbackType;
import com.codeim.youliao.ui.module.NavBar;
import com.codeim.youliao.ui.module.SimpleFeedback;
import com.codeim.youliao.util.DateTimeHelper;
import com.codeim.youliao.util.TextHelper;
import com.codeim.youliao.R;

public class DmActivity extends BaseActivity implements Refreshable {

	private static final String TAG = "DmActivity";

	// Views.
	private ListView mTweetList;
	private Adapter mAdapter;
	private Adapter mInboxAdapter;
	private Adapter mSendboxAdapter;

	Button inbox;
	Button sendbox;
	// Button newMsg;

	private int mDMType;
	// private static final int DM_TYPE_ALL = 0;
	private static final int DM_TYPE_INBOX = 1;
	private static final int DM_TYPE_SENDBOX = 2;

	private TextView mProgressText;

	private NavBar mNavbar;
	private Feedback mFeedback;

	// Tasks.
	private GenericTask mRetrieveTask;
	private GenericTask mDeleteTask;

	private TaskListener mDeleteTaskListener = new TaskAdapter() {
		@Override
		public void onPreExecute(GenericTask task) {
			updateProgress(getString(R.string.page_status_deleting));
		}

		@Override
		public void onPostExecute(GenericTask task, TaskResult result) {
			if (result == TaskResult.AUTH_ERROR) {
				logout();
			} else if (result == TaskResult.OK) {
				mAdapter.refresh();
			} else {
				// Do nothing.
			}

			updateProgress("");
		}

		@Override
		public String getName() {
			return "DmDeleteTask";
		}
	};
	
	private TaskListener mRetrieveTaskListener = new TaskAdapter() {
		@Override
		public void onPreExecute(GenericTask task) {
			updateProgress(getString(R.string.page_status_refreshing));
		}

		@Override
		public void onProgressUpdate(GenericTask task, Object params) {
			draw();
		}

		@Override
		public void onPostExecute(GenericTask task, TaskResult result) {
			if (result == TaskResult.AUTH_ERROR) {
				logout();
			} else if (result == TaskResult.OK) {
				SharedPreferences.Editor editor = mPreferences.edit();
				editor.putLong(Preferences.LAST_DM_REFRESH_KEY, DateTimeHelper.getNowTime());
				editor.commit();
				draw();
				goTop();
			} else {
				// Do nothing.
			}

			updateProgress("");
		}

		@Override
		public String getName() {
			return "DmRetrieve";
		}
	};

	// Refresh data at startup if last refresh was this long ago or greater.
	private static final long REFRESH_THRESHOLD = 5 * 60 * 1000;
	private static final String EXTRA_USER = "user";
	private static final String LAUNCH_ACTION = "com.codeim.youliao.DMS";

	public static Intent createIntent() {
		return createIntent("");
	}

	public static Intent createIntent(String user) {
		Intent intent = new Intent(LAUNCH_ACTION);
		intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

		if (!TextUtils.isEmpty(user)) {
			intent.putExtra(EXTRA_USER, user);
		}

		return intent;
	}

	@Override
	protected boolean _onCreate(Bundle savedInstanceState) {
		if (super._onCreate(savedInstanceState)) {
			setContentView(R.layout.dm);
			mNavbar = new NavBar(NavBar.HEADER_STYLE_TITLE, this);
			mNavbar.setHeaderTitle("信息");

			mFeedback = FeedbackFactory.create(this, FeedbackType.PROGRESS);

			bindFooterButtonEvent();

			mTweetList = (ListView) findViewById(R.id.tweet_list);
			mProgressText = (TextView) findViewById(R.id.progress_text);

			TwitterDatabase db = getDb();
			// Mark all as read.
			db.markAllDmsRead();

			setupAdapter();  // Make sure call bindFooterButtonEvent first

			boolean shouldRetrieve = false;

			long lastRefreshTime = mPreferences.getLong(Preferences.LAST_DM_REFRESH_KEY, 0);
			long nowTime = DateTimeHelper.getNowTime();

			long diff = nowTime - lastRefreshTime;
			Log.d(TAG, "Last refresh was " + diff + " ms ago.");

			if (diff > REFRESH_THRESHOLD) {
				shouldRetrieve = true;
			} else if (isTrue(savedInstanceState, SIS_RUNNING_KEY)) {
				// Check to see if it was running a send or retrieve task.
				// It makes no sense to resend the send request (don't want
				// dupes)
				// so we instead retrieve (refresh) to see if the message has
				// posted.
				Log.d(TAG, "Was last running a retrieve or send task. Let's refresh.");
				shouldRetrieve = true;
			}

			if (shouldRetrieve) {
				doRetrieve();
			}

			// Want to be able to focus on the items with the trackball.
			// That way, we can navigate up and down by changing item focus.
			mTweetList.setItemsCanFocus(true);

			return true;
		} else {
			return false;
		}
	}

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

	private static final String SIS_RUNNING_KEY = "running";

	@Override
	protected void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);

		if (mRetrieveTask != null && mRetrieveTask.getStatus() == GenericTask.Status.RUNNING) {
			outState.putBoolean(SIS_RUNNING_KEY, true);
		}
	}

	@Override
	protected void onDestroy() {
		Log.d(TAG, "onDestroy.");

		if (mRetrieveTask != null && mRetrieveTask.getStatus() == GenericTask.Status.RUNNING) {
			mRetrieveTask.cancel(true);
		}
		if (mDeleteTask != null && mDeleteTask.getStatus() == GenericTask.Status.RUNNING) {
			mDeleteTask.cancel(true);
		}

		super.onDestroy();
	}

	// UI helpers.
	private void bindFooterButtonEvent() {
		inbox = (Button) findViewById(R.id.inbox);
		sendbox = (Button) findViewById(R.id.sendbox);
		// newMsg = (Button) findViewById(R.id.new_message);

		inbox.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				if (mDMType != DM_TYPE_INBOX) {
					mDMType = DM_TYPE_INBOX;
					inbox.setEnabled(false);
					sendbox.setEnabled(true);
					mTweetList.setAdapter(mInboxAdapter);
					mInboxAdapter.refresh();
				}
			}
		});

		sendbox.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				if (mDMType != DM_TYPE_SENDBOX) {
					mDMType = DM_TYPE_SENDBOX;
					inbox.setEnabled(true);
					sendbox.setEnabled(false);
					mTweetList.setAdapter(mSendboxAdapter);
					mSendboxAdapter.refresh();
				}
			}
		});

		/*
		newMsg.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				Intent intent = new Intent();
				intent.setClass(DmActivity.this, WriteDmActivity.class);
				intent.putExtra("reply_to_id", 0); // TODO: 传入实际的reply_to_id
				startActivity(intent);
			}
		});
		*/
	}

	private void setupAdapter() {
		Cursor cursor = getDb().fetchAllDms(-1);
		startManagingCursor(cursor);
		mAdapter = new Adapter(this, cursor);

		Cursor inboxCursor = getDb().fetchInboxDms();
		startManagingCursor(inboxCursor);
		mInboxAdapter = new Adapter(this, inboxCursor);

		Cursor sendboxCursor = getDb().fetchSendboxDms();
		startManagingCursor(sendboxCursor);
		mSendboxAdapter = new Adapter(this, sendboxCursor);

		mTweetList.setAdapter(mInboxAdapter);
		registerForContextMenu(mTweetList);

		inbox.setEnabled(false);
	}

	private class DmRetrieveTask extends GenericTask {
	
		@Override
		protected TaskResult _doInBackground(TaskParams... params) {
			List<DirectMessage> dmList;

			ArrayList<Dm> dms = new ArrayList<Dm>();

			TwitterDatabase db = getDb();
			// ImageManager imageManager = getImageManager();

			String maxId = db.fetchMaxDmId(false);

			HashSet<String> imageUrls = new HashSet<String>();

			try {
				if (maxId != null) {
					Paging paging = new Paging(maxId);
					dmList = getApi().getDirectMessages(paging);
				} else {
					dmList = getApi().getDirectMessages();
				}
			} catch (HttpException e) {
				Log.e(TAG, e.getMessage(), e);
				return TaskResult.IO_ERROR;
			}
			publishProgress(SimpleFeedback.calProgressBySize(40, 20, dmList));

			for (DirectMessage directMessage : dmList) {
				if (isCancelled()) {
					return TaskResult.CANCELLED;
				}

				Dm dm;

				dm = Dm.create(directMessage, false);
				dms.add(dm);
				imageUrls.add(dm.profileImageUrl);

				if (isCancelled()) {
					return TaskResult.CANCELLED;
				}
			}

			maxId = db.fetchMaxDmId(true);

			try {
				if (maxId != null) {
					Paging paging = new Paging(maxId);
					dmList = getApi().getSentDirectMessages(paging);
				} else {
					dmList = getApi().getSentDirectMessages();
				}
			} catch (HttpException e) {
				Log.e(TAG, e.getMessage(), e);
				return TaskResult.IO_ERROR;
			}

			for (DirectMessage directMessage : dmList) {
				if (isCancelled()) {
					return TaskResult.CANCELLED;
				}

				Dm dm;

				dm = Dm.create(directMessage, true);
				dms.add(dm);
				imageUrls.add(dm.profileImageUrl);

				if (isCancelled()) {
					return TaskResult.CANCELLED;
				}
			}

			db.addDms(dms, false);

			// if (isCancelled()) {
			// return TaskResult.CANCELLED;
			// }
			//
			// publishProgress(null);
			//
			// for (String imageUrl : imageUrls) {
			// if (!Utils.isEmpty(imageUrl)) {
			// // Fetch image to cache.
			// try {
			// imageManager.put(imageUrl);
			// } catch (IOException e) {
			// Log.e(TAG, e.getMessage(), e);
			// }
			// }
			//
			// if (isCancelled()) {
			// return TaskResult.CANCELLED;
			// }
			// }

			return TaskResult.OK;
		}
	}

	private static class Adapter extends CursorAdapter {

		public Adapter(Context context, Cursor cursor) {
			super(context, cursor);

			mInflater = LayoutInflater.from(context);

			// TODO: 可使用:
			// DM dm = MessageTable.parseCursor(cursor);
			mUserTextColumn = cursor.getColumnIndexOrThrow(MessageTable.FIELD_USER_SCREEN_NAME);
			mTextColumn = cursor.getColumnIndexOrThrow(MessageTable.FIELD_TEXT);
			mProfileImageUrlColumn = cursor.getColumnIndexOrThrow(MessageTable.FIELD_PROFILE_IMAGE_URL);
			mCreatedAtColumn = cursor.getColumnIndexOrThrow(MessageTable.FIELD_CREATED_AT);
			mIsSentColumn = cursor.getColumnIndexOrThrow(MessageTable.FIELD_IS_SENT);
		}

		private LayoutInflater mInflater;

		private int mUserTextColumn;
		private int mTextColumn;
		private int mProfileImageUrlColumn;
		private int mIsSentColumn;
		private int mCreatedAtColumn;

		@Override
		public View newView(Context context, Cursor cursor, ViewGroup parent) {
			View view = mInflater.inflate(R.layout.direct_message, parent, false);

			ViewHolder holder = new ViewHolder();
			holder.userText = (TextView) view.findViewById(R.id.tweet_user_text);
			holder.tweetText = (TextView) view.findViewById(R.id.tweet_text);
			holder.profileImage = (ImageView) view.findViewById(R.id.profile_image);
			holder.metaText = (TextView) view.findViewById(R.id.tweet_meta_text);
			view.setTag(holder);

			return view;
		}

		class ViewHolder {
			public TextView userText;
			public TextView tweetText;
			public ImageView profileImage;
			public TextView metaText;
		}

		@Override
		public void bindView(View view, Context context, Cursor cursor) {
			ViewHolder holder = (ViewHolder) view.getTag();

			int isSent = cursor.getInt(mIsSentColumn);
			String user = cursor.getString(mUserTextColumn);

			if (0 == isSent) {
				holder.userText.setText(context.getString(R.string.direct_message_label_from_prefix) + user);
			} else {
				holder.userText.setText(context.getString(R.string.direct_message_label_to_prefix) + user);
			}

			TextHelper.setTweetText(holder.tweetText, cursor.getString(mTextColumn));

			String profileImageUrl = cursor.getString(mProfileImageUrlColumn);

			if (!TextUtils.isEmpty(profileImageUrl)) {
				holder.profileImage
						.setImageBitmap(TwitterApplication.mImageLoader.get(
								profileImageUrl, new ImageLoaderCallback() {

									@Override
									public void refresh(String url,
											Bitmap bitmap) {
										Adapter.this.refresh();
									}

								}));
			}

			try {
				holder.metaText.setText(DateTimeHelper.getRelativeDate(TwitterDatabase.DB_DATE_FORMATTER
						.parse(cursor.getString(mCreatedAtColumn))));
			} catch (ParseException e) {
				Log.w(TAG, "Invalid created at data.");
			}
		}

		public void refresh() {
			getCursor().requery();
		}
	}

	// Menu.

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		return super.onCreateOptionsMenu(menu);
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		// FIXME: 将刷新功能绑定到顶部的刷新按钮上，主菜单中的刷新选项已删除
		// case OPTIONS_MENU_ID_REFRESH:
		// doRetrieve();
		// return true;
		case OPTIONS_MENU_ID_TWEETS:
			launchActivity(TwitterActivity.createIntent(this));
			return true;
		case OPTIONS_MENU_ID_REPLIES:
			launchActivity(MentionActivity.createIntent(this));
			return true;
		}

		return super.onOptionsItemSelected(item);
	}

	private static final int CONTEXT_REPLY_ID = 0;
	private static final int CONTEXT_DELETE_ID = 1;

	@Override
	public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
		super.onCreateContextMenu(menu, v, menuInfo);
		menu.add(0, CONTEXT_REPLY_ID, 0, R.string.cmenu_reply);
		menu.add(0, CONTEXT_DELETE_ID, 0, R.string.cmenu_delete);
	}

	@Override
	public boolean onContextItemSelected(MenuItem item) {
		AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
		Cursor cursor = (Cursor) mAdapter.getItem(info.position);

		if (cursor == null) {
			Log.w(TAG, "Selected item not available.");
			return super.onContextItemSelected(item);
		}

		switch (item.getItemId()) {
		case CONTEXT_REPLY_ID:
			String user_id = cursor.getString(cursor.getColumnIndexOrThrow(MessageTable.FIELD_USER_ID));
			Intent intent = WriteDmActivity.createIntent(user_id);
			startActivity(intent);
			return true;
		case CONTEXT_DELETE_ID:
			int idIndex = cursor.getColumnIndexOrThrow(MessageTable._ID);
			String id = cursor.getString(idIndex);
			doDestroy(id);
			return true;
		default:
			return super.onContextItemSelected(item);
		}
	}

	private void doDestroy(String id) {
		Log.d(TAG, "Attempting delete.");

		if (mDeleteTask != null && mDeleteTask.getStatus() == GenericTask.Status.RUNNING) {
			return;
		} else {
			mDeleteTask = new DmDeleteTask();
			mDeleteTask.setListener(mDeleteTaskListener);

			TaskParams params = new TaskParams();
			params.put("id", id);
			mDeleteTask.execute(params);
		}
	}

	private class DmDeleteTask extends GenericTask {

		@Override
		protected TaskResult _doInBackground(TaskParams... params) {
			TaskParams param = params[0];
			try {
				String id = param.getString("id");
				DirectMessage directMessage = getApi().destroyDirectMessage(id);
				Dm.create(directMessage, false);
				getDb().deleteDm(id);
			} catch (HttpException e) {
				Log.e(TAG, e.getMessage(), e);
				return TaskResult.IO_ERROR;
			}

			if (isCancelled()) {
				return TaskResult.CANCELLED;
			}

			return TaskResult.OK;
		}
	}

	public void doRetrieve() {
		Log.d(TAG, "Attempting retrieve.");

		if (mRetrieveTask != null && mRetrieveTask.getStatus() == GenericTask.Status.RUNNING) {
			return;
		} else {
			mRetrieveTask = new DmRetrieveTask();
			mRetrieveTask.setFeedback(mFeedback);
			mRetrieveTask.setListener(mRetrieveTaskListener);
			mRetrieveTask.execute();
		}
	}

	public void goTop() {
		mTweetList.setSelection(0);
	}

	public void draw() {
		mAdapter.refresh();
		mInboxAdapter.refresh();
		mSendboxAdapter.refresh();
	}

	private void updateProgress(String msg) {
		mProgressText.setText(msg);
	}
}
