/*
 * @copyright 2013 Philip Warner
 * @license GNU General Public License
 * 
 * This file is part of Book Catalogue.
 *
 * Book Catalogue is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Book Catalogue is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Book Catalogue.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.eleybourn.bookcatalogue;

import java.util.ArrayList;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;

import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.MenuItem;
import com.eleybourn.bookcatalogue.Fields.AfterFieldChangeListener;
import com.eleybourn.bookcatalogue.Fields.Field;
import com.eleybourn.bookcatalogue.compat.BookCatalogueFragment;
import com.eleybourn.bookcatalogue.datamanager.DataEditor;
import com.eleybourn.bookcatalogue.datamanager.DataManager;
import com.eleybourn.bookcatalogue.utils.BookUtils;
import com.eleybourn.bookcatalogue.utils.Logger;
import com.eleybourn.bookcatalogue.utils.Utils;

/**
 * Based class for all fragments that appear in the BookEdit activity
 * 
 * @author pjw
 */
public abstract class BookEditFragmentAbstract extends BookCatalogueFragment implements DataEditor {
	protected Fields mFields;
	
	private static final int DELETE_ID = 1;
	private static final int DUPLICATE_ID = 3; //2 is taken by populate in anthology
	private static final int SHARE_ID = 4;
	protected static final int THUMBNAIL_OPTIONS_ID = 5;
	private static final int EDIT_OPTIONS_ID = 6;
	
	/**
	 * Interface that any containing activity must implement.
	 * 
	 * @author pjw
	 */
	public interface BookEditManager {
		//public Fields getFields();
		public void setShowAnthology(boolean showAnthology);
		public void setDirty(boolean isDirty);
		public boolean isDirty();
		public BookData getBookData();
		public void setRowId(Long id);
		public ArrayList<String> getFormats();
		public ArrayList<String> getGenres();
		public ArrayList<String> getLanguages();
		public ArrayList<String> getPublishers();
	}

	/** A link to the BookEditManager for this fragment (the activity) */
	protected BookEditManager mEditManager;
	/** Database instance */
	protected CatalogueDBAdapter mDbHelper;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		this.setHasOptionsMenu(true);	
	}

	@Override
	public void onAttach(Activity a) {
		super.onAttach(a);

		if (! (a instanceof BookEditManager))
			throw new RuntimeException("Activity " + a.getClass().getSimpleName() + " must implement BookEditManager");
		
		mEditManager = (BookEditManager)a;
		mDbHelper = new CatalogueDBAdapter(a);
		mDbHelper.open();
	}

	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
		super.onActivityCreated(savedInstanceState);
		mFields = new Fields(this);		
	}

	/**
	 * Define the common menu options; each subclass can add more as necessary
	 */
	@Override
	public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
		super.onCreateOptionsMenu(menu, inflater);
		//menu.clear();
		final Long currRow = mEditManager.getBookData().getRowId();
		if (currRow != null && currRow != 0) {
			MenuItem delete = menu.add(0, DELETE_ID, 0, R.string.menu_delete);
			delete.setIcon(android.R.drawable.ic_menu_delete);

			MenuItem duplicate = menu.add(0, DUPLICATE_ID, 0, R.string.menu_duplicate);
			duplicate.setIcon(android.R.drawable.ic_menu_add);
		}

		// TODO: Consider allowing Tweets (or other sharing methods) to work on un-added books.
		MenuItem tweet = menu.add(0, SHARE_ID, 0, R.string.menu_share_this);
		tweet.setIcon(R.drawable.ic_menu_twitter);
		// Very rarely used, and easy to miss-click.
		//tweet.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);

		if(this instanceof BookDetailsReadOnly){
			menu.add(0, EDIT_OPTIONS_ID, 0, R.string.edit_book)
				.setIcon(android.R.drawable.ic_menu_edit)
				.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
				;
		}

		boolean hasAuthor = mEditManager.getBookData().getAuthorList().size() > 0;
		if (hasAuthor) {
			MenuItem item = menu.add(0, R.id.MENU_AMAZON_BOOKS_BY_AUTHOR, 0, R.string.amazon_books_by_author);
			item.setIcon(R.drawable.ic_www_search_2_holo_dark);
		}
		
		if (mEditManager.getBookData().getSeriesList().size() > 0) {
			if (hasAuthor) {
				MenuItem item = menu.add(0, R.id.MENU_AMAZON_BOOKS_BY_AUTHOR_IN_SERIES, 0, R.string.amazon_books_by_author_in_series);
				item.setIcon(R.drawable.ic_www_search_2_holo_dark);
			}
			{
				MenuItem item = menu.add(0, R.id.MENU_AMAZON_BOOKS_IN_SERIES, 0, R.string.amazon_books_in_series);
				item.setIcon(R.drawable.ic_www_search_2_holo_dark);
			}			
		}
	}

	/**
	 * This will be called when a menu item is selected. A large switch
	 * statement to call the appropriate functions (or other activities)
	 */
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		final Long currRow = mEditManager.getBookData().getRowId();

		try {
			switch (item.getItemId()) {
			case THUMBNAIL_OPTIONS_ID:
				if (this instanceof BookEditFields) {
					((BookEditFields) this).showCoverContextMenu();
					return true;
				}
				break;
			case SHARE_ID:
				BookUtils.shareBook(getActivity(), mDbHelper, currRow);
				return true;
			case DELETE_ID:
				BookUtils.deleteBook(getActivity(), mDbHelper, currRow,
						new Runnable() {
							@Override
							public void run() {
								getActivity().finish();
							}
						});
				return true;
			case DUPLICATE_ID:
				BookUtils.duplicateBook(getActivity(), mDbHelper, currRow);
				return true;
			case EDIT_OPTIONS_ID:
				BookEdit.editBook(getActivity(), currRow, BookEdit.TAB_EDIT);
				return true;

			case R.id.MENU_AMAZON_BOOKS_BY_AUTHOR:
			{
				String author = getAuthorFromBook();
				Utils.openAmazonSearchPage(getActivity(), author, null);
				return true;
			}
			case R.id.MENU_AMAZON_BOOKS_IN_SERIES:
			{
				String series = getSeriesFromBook();
				Utils.openAmazonSearchPage(getActivity(), null, series);
				return true;
			}
			
			case R.id.MENU_AMAZON_BOOKS_BY_AUTHOR_IN_SERIES:
			{
				String author = getAuthorFromBook();
				String series = getSeriesFromBook();
				Utils.openAmazonSearchPage(getActivity(), author, series);
				return true;
			}
			}

		} catch (NullPointerException e) {
			Logger.logError(e);
		}
		return false;
	}

	private String getAuthorFromBook() {
		ArrayList<Author> authors = mEditManager.getBookData().getAuthorList();
		if (authors.size() > 0)
			return authors.get(0).getDisplayName();
		else
			return null;
	}

	private String getSeriesFromBook() {
		ArrayList<Series> list = mEditManager.getBookData().getSeriesList();
		if (list.size() > 0)
			return list.get(0).name;
		else
			return null;
	}

	@Override
	public void onPause() {
		super.onPause();
		// This is now done in onPause() since the view may have been deleted when this is called
		onSaveBookDetails(mEditManager.getBookData());	
	}

	/**
	 * Called to load data from the BookData object when needed.
	 * 
	 * @param book			BookData to load from
	 * @param setAllDone	Flag indicating setAll() has already been called on the mFields object
	 */
	abstract protected void onLoadBookDetails(BookData book, boolean setAllDone);

	/**
	 * Default implementation of code to save existing data to the BookData object
	 * 
	 * @param book
	 */
	protected void onSaveBookDetails(BookData book) {
		mFields.getAll(book);
	}
	
	@Override
	public void onResume() {
		//double t0 = System.currentTimeMillis();

		super.onResume();

		// Load the data and preserve the isDirty() setting
		mFields.setAfterFieldChangeListener(null);
		final boolean wasDirty = mEditManager.isDirty();
		BookData book = mEditManager.getBookData();
		onLoadBookDetails(book, false);
		mEditManager.setDirty(wasDirty);

		// Set the listener to monitor edits
		mFields.setAfterFieldChangeListener(new AfterFieldChangeListener(){
			@Override
			public void afterFieldChange(Field field, String newValue) {
				mEditManager.setDirty(true);
			}});
		//System.out.println("BEFA resume: " + (System.currentTimeMillis() - t0));
	}

	/**
	 * Cleanup
	 */
	@Override
	public void onDestroy() {
		super.onDestroy();
		mDbHelper.close();
	}
	
	@Override
	public void saveAllEdits(DataManager data) {
		mFields.getAll(mEditManager.getBookData());
	}

	/**
	 * This is 'final' because we want inheritors to implement onLoadBookDetails()
	 */
	@Override
	public final void reloadData(DataManager data) {
		final boolean wasDirty = mEditManager.isDirty();
		onLoadBookDetails(mEditManager.getBookData(), false);
		mEditManager.setDirty(wasDirty);
	}
	
	/**
	 * Show or Hide text field if it has not any useful data.
	 * Don't show a field if it is already hidden (assumed by user preference)
	 * @param hideIfEmpty TODO
	 * @param resId layout resource id of the field
	 * @param relatedFields list of fields whose visibility will also be set based on the first field
	 *
	 * @return The resulting visibility setting value (VISIBLE or GONE)
	 */
	protected int showHideField(boolean hideIfEmpty, int resId, int...relatedFields) {
		// Get the base view
		final View v = getView().findViewById(resId);
		int visibility;
		if (v == null) {
			visibility = View.GONE;
		} else {
			visibility = v.getVisibility();
			if (hideIfEmpty) {
				if (v.getVisibility() != View.GONE) {
					// Determine if we should hide it
					if (v instanceof ImageView) {
						visibility = v.getVisibility();
					} else {
						final String value = mFields.getField(resId).getValue().toString();
						final boolean isExist = value != null && !value.equals("");
						visibility = isExist ? View.VISIBLE : View.GONE;
						v.setVisibility(visibility);										
					}
				}				
			}
			// Set the related views
			for(int i: relatedFields) {
				View rv = getView().findViewById(i);
				if (rv != null)
					rv.setVisibility(visibility);
			}
		}
		return visibility;
	}	

	/**
	 * Hides unused fields if they have not any useful data. Checks all text fields
	 * except of author, series and loaned. 
	 */
	protected void showHideFields(boolean hideIfEmpty) {
		mFields.resetVisibility();
	
		// Check publishing information; in reality only one of these fields will exist
		showHideField(hideIfEmpty, R.id.publishing_details, R.id.lbl_publishing, R.id.row_publisher);
		showHideField(hideIfEmpty, R.id.publisher, R.id.lbl_publishing, R.id.row_publisher);

		showHideField(hideIfEmpty, R.id.date_published, R.id.row_date_published);

		//		if (showHideFieldIfEmpty(R.id.publisher) == View.GONE && showHideFieldIfEmpty(R.id.date_published) == View.GONE) {
//			getView().findViewById(R.id.lbl_publishing).setVisibility(View.GONE);
//		}

		showHideField(hideIfEmpty, R.id.row_img, R.id.image_wrapper);
//		boolean hasImage = getView().findViewById(R.id.row_img).getVisibility() != View.GONE;
//		if (!hasImage) {
//			getView().findViewById(R.id.image_wrapper).setVisibility(View.GONE);						
//		}

		// Check format information
		showHideField(hideIfEmpty, R.id.pages, R.id.row_pages);
		//boolean hasPages = (showHideField(true, R.id.pages) == View.VISIBLE);
		//if (!hasPages) {
		//	getView().findViewById(R.id.pages).setVisibility(View.GONE);			
		//}
		showHideField(hideIfEmpty, R.id.format, R.id.row_format);

		// Check genre
		showHideField(hideIfEmpty, R.id.genre, R.id.lbl_genre, R.id.row_genre);

		// Check language
		showHideField(hideIfEmpty, R.id.language, R.id.lbl_language, R.id.row_language);

		// Check ISBN
		showHideField(hideIfEmpty, R.id.isbn, R.id.row_isbn);

		// Check ISBN
		showHideField(hideIfEmpty, R.id.series, R.id.row_series, R.id.lbl_series);

		// Check list price
		showHideField(hideIfEmpty, R.id.list_price, R.id.row_list_price);

		// Check description
		showHideField(hideIfEmpty, R.id.description, R.id.descriptionLabel, R.id.description_divider);

		// **** MY COMMENTS SECTION ****
		// Check notes
		showHideField(hideIfEmpty, R.id.notes, R.id.lbl_notes, R.id.row_notes);

		// Check date start reading
		showHideField(hideIfEmpty, R.id.read_start, R.id.row_read_start);

		// Check date end reading
		showHideField(hideIfEmpty, R.id.read_end, R.id.row_read_end);

		// Check location
		showHideField(hideIfEmpty, R.id.location, R.id.row_location, R.id.row_location);

		// Check signed flag
		showHideField(hideIfEmpty, R.id.signed, R.id.row_signed);

	}
}
