/*
 * The MIT License
 *
 * Copyright 2014 Masahiko, SAWAI <masahiko.sawai@gmail.com>.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.example.hello.android.ui_pattern_listview_crud_array;

import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.ListView;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;

public class UserListActivity extends ListActivity
	implements OnItemClickListener, View.OnClickListener, UserConstants
{

	private static final String LOG_TAG = "XXX";
	private static final String USER_LIST_FILE_NAME = "user_list.ser";
	// Child activity request code
	private static final int REQUEST_CODE_VIEW_USER = 101;
	private static final int REQUEST_CODE_EDIT_USER = 102;
	private static final int REQUEST_CODE_ADD_USER = 103;
	// instances
	private final List<UserInfo> userList = new ArrayList<UserInfo>();
	private UserListAdapter userListAdapter;
	private boolean editMode = false;

	public boolean isEditMode()
	{
		return editMode;
	}

	public void setEditMode(boolean newMode)
	{
		if (this.editMode != newMode)
		{
			this.editMode = newMode;
			if (this.editMode)
			{
				enterEditMode();
			}
			else
			{
				enterViewMode();
			}
		}
	}

	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		Log.v(LOG_TAG, "onCreate() : Hello");

		super.onCreate(savedInstanceState);
		setContentView(R.layout.user_list_activity);

		loadUserList();

		// Init ListAdapter
		userListAdapter = new UserListAdapter(this, userList);
		setListAdapter(userListAdapter);

		Button cancelButton = (Button) findViewById(R.id.cancel_button);
		Button deleteButton = (Button) findViewById(R.id.delete_button);
		cancelButton.setOnClickListener(this);
		deleteButton.setOnClickListener(this);

		// default mode
		enterViewMode();

		Log.v(LOG_TAG, "onCreate() : Bye");
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data)
	{
		Log.v(LOG_TAG, "onActivityResult() : Hello");
		if ((requestCode == REQUEST_CODE_EDIT_USER || requestCode == REQUEST_CODE_VIEW_USER)
			&& resultCode == RESULT_OK)
		{
			Log.d(LOG_TAG, "onActivityResult() : user edit is done.");
			Log.d(LOG_TAG, "onActivityResult() : data => " + data);
			int id = data.getIntExtra(EXTRA_ID, -1);
			if (id >= 0 && id < userList.size())
			{
				String firstName = data.getStringExtra(EXTRA_FIRST_NAME);
				String lastName = data.getStringExtra(EXTRA_LAST_NAME);
				String email = data.getStringExtra(EXTRA_EMAIL);
				int age = data.getIntExtra(EXTRA_AGE, -1);

				UserInfo userInfo = userList.get(id);
				userInfo.setFirstName(firstName);
				userInfo.setLastName(lastName);
				userInfo.setEmail(email);
				userInfo.setAge(age);
				saveUserList();
				userListAdapter.notifyDataSetChanged();
			}
		}
		else if (requestCode == REQUEST_CODE_ADD_USER && resultCode == RESULT_OK)
		{
			Log.d(LOG_TAG, "onActivityResult() : new user edit is done.");
			String firstName = data.getStringExtra(EXTRA_FIRST_NAME);
			String lastName = data.getStringExtra(EXTRA_LAST_NAME);
			String email = data.getStringExtra(EXTRA_EMAIL);
			int age = data.getIntExtra(EXTRA_AGE, -1);

			UserInfo userInfo = new UserInfo(firstName, lastName, email, age);
			userList.add(userInfo);
			saveUserList();
			userListAdapter.notifyDataSetChanged();
		}
		Log.v(LOG_TAG, "onActivityResult() : Bye");
	}

	@Override
	protected void onResume()
	{
		Log.v(LOG_TAG, "onResume() : Hello");
		super.onResume();
		loadUserList();
		userListAdapter.notifyDataSetChanged();
		Log.v(LOG_TAG, "onResume() : Bye");
	}

	@Override
	protected void onPause()
	{
		Log.v(LOG_TAG, "onPause() : Hello");
		saveUserList();
		super.onPause();
		Log.v(LOG_TAG, "onPause() : Bye");
	}

	@Override
	public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)
	{
		Log.v(LOG_TAG, "onCreateContextMenu() : Hello");
		super.onCreateContextMenu(menu, v, menuInfo);

		MenuInflater menuInflater = getMenuInflater();
		menuInflater.inflate(R.menu.user_list_context_menu, menu);
		Log.v(LOG_TAG, "onCreateContextMenu() : Bye");
	}

	@Override
	public boolean onContextItemSelected(MenuItem item)
	{
		boolean result;
		AdapterContextMenuInfo menuInfo = (AdapterContextMenuInfo) item.getMenuInfo();
		Log.v(LOG_TAG, "onCreateContextMenu() : list item position => " + menuInfo.position);
		Log.v(LOG_TAG, "onCreateContextMenu() : list item id => " + menuInfo.id);
		Log.v(LOG_TAG, "onCreateContextMenu() : list item targetView => " + menuInfo.targetView);
		Log.v(LOG_TAG, "onCreateContextMenu() : list item userInfo => " + userList.get(menuInfo.position));

		int itemId = item.getItemId();
		switch (itemId)
		{
			case R.id.edit_menuitem:
				editUserAt(menuInfo.position);
				result = true;
				break;
			case R.id.delete_menuitem:
				deleteUserAt(menuInfo.position);
				result = true;
				break;
			default:
				result = super.onContextItemSelected(item);
		}

		return result;
	}

	public void onItemClick(AdapterView<?> parentView, View view, int position, long id)
	{
		Log.v(LOG_TAG, "onItemClick() : Hello");
		Log.d(LOG_TAG, "onItemClick() : position => " + position);
		viewUserDetailAt(position);

		Log.v(LOG_TAG, "onItemClick() : Bye");
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu)
	{
		MenuInflater menuInflater = getMenuInflater();
		menuInflater.inflate(R.menu.user_list_option_menu, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item)
	{
		int itemId = item.getItemId();
		switch (itemId)
		{
			case R.id.add_menuitem:
				addNewUser();
				break;
			case R.id.delete_selected_menuitem:
				setEditMode(true);
				break;
		}
		return super.onOptionsItemSelected(item);
	}

	public void onClick(View view)
	{
		int viewId = view.getId();
		switch (viewId)
		{
			case R.id.cancel_button:
				setEditMode(false);
				break;
			case R.id.delete_button:
				deleteCheckedUser();
				setEditMode(false);
				break;
		}
	}

	private void loadUserList()
	{
		try
		{
			Log.d(LOG_TAG, "Load data from file.");
			File userListFilePath = getFileStreamPath(USER_LIST_FILE_NAME);
			FileInputStream fileInputStream = new FileInputStream(userListFilePath);
			try
			{
				ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
				Object readObject = objectInputStream.readObject();
				if (readObject instanceof List)
				{
					List<UserInfo> loadedUserList = (List<UserInfo>) readObject;
					userList.clear();
					userList.addAll(loadedUserList);
				}
			}
			finally
			{
				fileInputStream.close();
			}
		}
		catch (IOException ex)
		{
			Log.e(LOG_TAG, "Load user list from file.", ex);
		}
		catch (ClassNotFoundException ex)
		{
			Log.e(LOG_TAG, "Load user list from file.", ex);
		}

		if (userList.isEmpty())
		{
			loadInitialData();
		}
	}

	private void loadInitialData()
	{
		Log.d(LOG_TAG, "Load initial data from resources.");
		// initial data
		String[] firstNames = getResources().getStringArray(R.array.first_names);
		String[] lastNames = getResources().getStringArray(R.array.last_names);
		String[] emails = getResources().getStringArray(R.array.emails);
		int[] ages = getResources().getIntArray(R.array.ages);
		for (int i = 0; i < firstNames.length; i++)
		{
			UserInfo userInfo = new UserInfo(firstNames[i], lastNames[i], emails[i], ages[i]);
			userList.add(userInfo);
		}
	}

	private void saveUserList()
	{
		Log.v(LOG_TAG, "saveUserList() : Hello");

		try
		{
			File userListFilePath = getFileStreamPath(USER_LIST_FILE_NAME);
			FileOutputStream fileOutputStream = new FileOutputStream(userListFilePath);
			try
			{
				ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
				objectOutputStream.writeObject(userList);
			}
			finally
			{
				fileOutputStream.close();
			}
		}
		catch (IOException ex)
		{
			Log.e(LOG_TAG, "Load user list from file.", ex);
		}

		Log.v(LOG_TAG, "saveUserList() : Bye");
	}

	private void addNewUser()
	{
		Intent intent = new Intent(this, UserDetailEditActivity.class);
		intent.setAction(Intent.ACTION_INSERT);
		startActivityForResult(intent, REQUEST_CODE_ADD_USER);
	}

	private void viewUserDetailAt(int index)
	{
		UserInfo userInfo = userList.get(index);
		String firstName = userInfo.getFirstName();
		String lastName = userInfo.getLastName();
		String email = userInfo.getEmail();
		int age = userInfo.getAge();

		Intent intent = new Intent(this, UserDetailViewActivity.class);
		intent.setAction(Intent.ACTION_VIEW);
		intent.putExtra(EXTRA_ID, index);
		intent.putExtra(EXTRA_FIRST_NAME, firstName);
		intent.putExtra(EXTRA_LAST_NAME, lastName);
		intent.putExtra(EXTRA_EMAIL, email);
		intent.putExtra(EXTRA_AGE, age);
		startActivityForResult(intent, REQUEST_CODE_VIEW_USER);
	}

	private void editUserAt(int index)
	{
		UserInfo userInfo = userList.get(index);
		String firstName = userInfo.getFirstName();
		String lastName = userInfo.getLastName();
		String email = userInfo.getEmail();
		int age = userInfo.getAge();

		Intent intent = new Intent(this, UserDetailEditActivity.class);
		intent.setAction(Intent.ACTION_EDIT);
		intent.putExtra(EXTRA_ID, index);
		intent.putExtra(EXTRA_FIRST_NAME, firstName);
		intent.putExtra(EXTRA_LAST_NAME, lastName);
		intent.putExtra(EXTRA_EMAIL, email);
		intent.putExtra(EXTRA_AGE, age);
		startActivityForResult(intent, REQUEST_CODE_EDIT_USER);
	}

	private void deleteUserAt(int index)
	{
		Log.v(LOG_TAG, "deleteUser() : Hello");
		if (index >= 0 && index < userList.size())
		{
			userList.remove(index);
			userListAdapter.notifyDataSetChanged();
			Log.v(LOG_TAG, "deleteUser() : user removed at => " + index);
		}
		Log.v(LOG_TAG, "deleteUser() : Bye");
	}

	private void enterViewMode()
	{
		Log.v(LOG_TAG, "enterViewMode() : Hello");

		ListView listView = getListView();
		listView.setChoiceMode(ListView.CHOICE_MODE_NONE);
		listView.setOnItemClickListener(this);
		registerForContextMenu(listView);

		View editModeActionbarView = findViewById(R.id.edit_mode_actionbar);
		editModeActionbarView.setVisibility(View.GONE);

		userListAdapter.setCheckable(false);
		userListAdapter.notifyDataSetChanged();

		Log.v(LOG_TAG, "enterViewMode() : Bye");
	}

	private void enterEditMode()
	{
		Log.v(LOG_TAG, "enterEditMode() : Hello");

		ListView listView = getListView();
		listView.clearChoices();
		listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
		listView.setOnItemClickListener(null);
		unregisterForContextMenu(listView);

		View editModeActionbarView = findViewById(R.id.edit_mode_actionbar);
		editModeActionbarView.setVisibility(View.VISIBLE);

		userListAdapter.setCheckable(true);
		userListAdapter.notifyDataSetChanged();

		Log.v(LOG_TAG, "enterEditMode() : Bye");
	}

	private void deleteCheckedUser()
	{
		Log.v(LOG_TAG, "deleteCheckedUser() : Hello");
		SparseBooleanArray checkedItemPositions = getListView().getCheckedItemPositions();
		for (int i = checkedItemPositions.size() - 1; i >= 0; i--)
		{
			int userListIndex = checkedItemPositions.keyAt(i);
			boolean checked = checkedItemPositions.get(userListIndex);
			Log.v(LOG_TAG, "deleteCheckedUser() : i => " + i + ", key => " + userListIndex + ", checked => " + checked);
			if (checked)
			{
				userList.remove(userListIndex);
			}
		}

		Log.v(LOG_TAG, "deleteCheckedUser() : Bye");
	}
}
