/*
 *
 * Sample program for use with the Product
 * Licensed Materials  - Property of IBM
 * 5724-I66
 * (c) Copyright IBM Corp.  2006, 2009
 *   
 */
package com.ibm.wbit.tel.client.jsf.handler;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

import com.ibm.bpc.clientcore.ClientException;
import com.ibm.bpc.clientcore.MessageWrapper;
import com.ibm.bpe.jsf.handler.BPCListHandler;
import com.ibm.bpe.jsf.handler.ItemListener;
import com.ibm.bpe.jsf.handler.ItemProvider;
import com.ibm.task.api.HumanTaskManagerService;
import com.ibm.task.api.ObjectDoesNotExistException;
import com.ibm.task.api.Task;
import com.ibm.task.clientmodel.bean.TaskInstanceBean;
import com.ibm.wbit.tel.client.jsf.bean.ToDoInstance;
import com.ibm.wbit.tel.client.jsf.infrastructure.FacesUtils;
import com.ibm.wbit.tel.client.jsf.infrastructure.Messages;
import com.ibm.wbit.tel.client.jsf.infrastructure.ServiceFactory;
import com.ibm.wbit.tel.client.jsf.infrastructure.SharedConstants;
import com.ibm.wbit.tel.client.jsf.query.SubToDosQuery;

/**
 * ToDoMessageHandler is an item listener for the task lists. It also implements
 * the ItemProvider interface and can therefore be used as a model in the
 * command bar component. Furthermore it extends SubviewHandler to bring up a
 * page which shows the input message and output message for the selected task.
 */
public class ToDoMessageHandler extends SubviewHandler implements ItemListener, ItemProvider, SharedConstants {

	/**
	 * The ToDo selected in the list
	 */
	private ToDoInstance toDoInstance = null;

	/**
	 * Contains the navigation rule for next page after itemChanged has been
	 * executed on list of open ToDos
	 */
	private String nextViewOpenList = null;

	/**
	 * Contains the navigation rule for next page after itemChanged has been
	 * executed on list of under work ToDos
	 */
	private String nextViewUnderWorkList = null;

	/**
	 * Contains the navigation rule of the list which triggered itemChanged.
	 */
	private String lastList = null;

	/**
	 * Boolean indicating if state of open ToDo in list differs from sate of
	 * this ToDo on server
	 */
	private boolean openToDoValid = true;

	/**
	 * Boolean indicating if state of under work ToDo in list differs from sate
	 * of this ToDo on server
	 */
	private boolean underWorkToDoValid = true;
	
	/**
	 * Boolean indicating if sub task templates are available.
	 */
	private boolean subTaskTemplatesAvailable; 

	/**
	 * Notification, when a ToDo was selected in list Open ToDo's of Under Work
	 * ToDo's Set input and output message of ToDoInstance and provide subview
	 * IDs to render the ToDo messages.
	 * 
	 * @see com.ibm.bpe.jsf.handler.ItemListener#itemChanged(java.lang.Object)
	 */
	public void itemChanged(Object item) throws ClientException {
		nextViewOpenList = null;
		nextViewUnderWorkList = null;
		nextSubviewInput((String) null);
		nextSubviewOutput((String) null);

		if (item != null && item instanceof ToDoInstance) {
			toDoInstance = (ToDoInstance) item;
			Object object;

			// check if state of ToDo in list is still valid
			if (!stateValid()) {
				return;
			}

			// get input message and convert to HashMap
			object = toDoInstance.getInputMessageWrapper().getMessage();
			toDoInstance.setInputValuesAll( object );
						
			String inputMessageType = toDoInstance.getInputMessageTypeName();
			nextSubviewInput(toDoInstance);

			// outputmessage defined?
			String outputMessageType = toDoInstance.getOutputMessageTypeName();
			if (outputMessageType != null) {
				nextSubviewOutput(toDoInstance);
				MessageWrapper outputMessage = toDoInstance.getOutputMessageWrapper();
				// does outputmessage already contain values?
				if (outputMessage != null && outputMessage.getMessage() != null) {
					object = outputMessage.getMessage();
					toDoInstance.setOutputValuesAll( object );
				} else if (inputMessageType.equals(outputMessageType)) {
					// initialize output with input, applicable for all message styles,
					// but minor changes in WSDL portType operation necessary
					toDoInstance.setOutputValuesAll(new HashMap<String, Object>(toDoInstance.getInputValuesAll()));
				} else {
					HashMap<String, Object> initValues = FacesUtils.getValueMapInOut(toDoInstance);
					
					boolean isSuppressPrePopulation = FacesUtils.isSuppressPrePopulation(toDoInstance);
					
					// only prepopulate if it is not suppressed
					if (initValues != null  && !isSuppressPrePopulation) {
						// initialize output with input, applicable for doc./lit. wrapped,
						// no changes in WSDL portType operation necessary
						toDoInstance.setOutputValuesAll(initValues);
					} else {
						toDoInstance.setOutputValuesAll(new HashMap<String, Object>());
					}
				}
			} else {
				toDoInstance.setOutputValuesAll(null);
			}

			nextViewOpenList = DETAILS_TODOS_OPEN;
			nextViewUnderWorkList = DETAILS_TODO_UNDER_WORK;
			setNavigationInfo();
			propagateMainToDo();
		}
	}

	/**
	 * Check if state of ToDo in list is still valid, which means compare sate
	 * of ToDo in list with actual state of ToDo on server.
	 * 
	 * @return boolean indicating whether of not state of ToDo in list is still valid
	 */
	private boolean stateValid() throws ClientException {
		boolean valid = true;
		int stateInList = toDoInstance.getState();
		HumanTaskManagerService htm;

		try {
			htm = ServiceFactory.getInstance().getHumanTaskManagerService();

			Task task = htm.getTask(toDoInstance.getID());
			if (task.getState() != stateInList) {
				valid = false;
			}
		} catch (ObjectDoesNotExistException odnee) {
			valid = false;
		} catch (Exception e) {
			throw new ClientException(NLS_CATALOG, SERVICE_FAILED_HUMAN_TASK_MANAGER, null, e);
		}

		// did we check state for open ToDo list?
		if (stateInList == TaskInstanceBean.STATE_READY) {
			openToDoValid = valid;
		} else { // so we checked state for under work list
			underWorkToDoValid = valid;
		}

		return valid;
	}

	/**
	 * Boolean indicating if state of open ToDo in list differs from sate of
	 * this ToDo on server
	 * 
	 * @return Boolean indicating if state of open ToDo in list differs from state on server
	 */
	public boolean isOpenToDoValid() {
		return openToDoValid;
	}

	/**
	 * Boolean indicating if state of under work ToDo in list differs from sate
	 * of this ToDo on server
	 * 
	 * @return Boolean indicating if state of under work ToDo in list differs
	 *         from sate of this ToDo on server
	 */
	public boolean isUnderWorkToDoValid() {
		return underWorkToDoValid;
	}

	/**
	 * Refreshes list of open ToDos.
	 * 
	 * @return navigtion rule as of faces config for list with open ToDos
	 */
	public String refreshOpenList() {

		Object listHandler = FacesUtils.getManagedBeanInstance("toDosOpenListHandler", BPCListHandler.class);
		((BPCListHandler) listHandler).refreshList();

		openToDoValid = true;
		return LIST_TODOS_OPEN;
	}

	/**
	 * Refreshes list of under work ToDos.
	 * 
	 * @return navigtion rule as of faces config for list with under work ToDos
	 */
	public String refreshUnderWorkList() {

		Object listHandler = FacesUtils.getManagedBeanInstance("toDosUnderWorkListHandler", BPCListHandler.class);
		((BPCListHandler) listHandler).refreshList();

		underWorkToDoValid = true;
		return LIST_TODOS_UNDER_WORK;
	}

	/**
	 * Refreshes that list for which itemChanged has been executed last
	 * recently.
	 */
	public void refreshLastList() {

		if (getLastList() == null) {
			refreshOpenList();
			refreshUnderWorkList();
		} else if (getLastList().equals(LIST_TODOS_OPEN)) {
			refreshOpenList();
		} else {
			refreshUnderWorkList();
		}

	}

	/**
	 * Returns the navigation rule which should apply after itemChanged has been
	 * executed for list of open ToDos. Only the ToDosOpen list should call this method.
	 * 
	 * @return navigation rule which should apply after itemChanged has been
	 *         executed, return value null means stay on current page
	 */
	public String getNextViewOpenList() {
		lastList = LIST_TODOS_OPEN;
		return nextViewOpenList;
	}

	/**
	 * Returns the navigation rule which should apply after itemChanged has
	 * been executed for list of under work ToDos. Only the ToDosUnderWork list
	 * should call this method.
	 * 
	 * @return navigation rule which should apply after itemChanged has been
	 *         executed, return value null means stay on current page
	 */
	public String getNextViewUnderWorkList() {
		lastList = LIST_TODOS_UNDER_WORK;
		return nextViewUnderWorkList;
	}

	/**
	 * Set navigation info to be shown in the JSF pages.
	 */
	private void setNavigationInfo() {

		int stateInList = toDoInstance.getState();
		String preNavigation;

		// from which list are we comming?
		if (stateInList == TaskInstanceBean.STATE_READY) {
			preNavigation = Messages.getString("LINE_TODOS_OPEN", FacesUtils.getLocale());
		} else {
			preNavigation = Messages.getString("LINE_TODOS_CLAIMED", FacesUtils.getLocale());
		}
		setNavigationInfo(preNavigation + " > " + toDoInstance.getName());
	}

	/**
	 * Propagate the just set main ToDo.
	 */
	private void propagateMainToDo() {

		Object subToDosQuery = FacesUtils.getManagedBeanInstance("subToDosQuery", SubToDosQuery.class);
		((SubToDosQuery) subToDosQuery).setMainToDoID(toDoInstance.getID().toString());

	}

	/**
	 * Contains the navigation rule of that list which triggered itemChanged.
	 * 
	 * @return navigation rule of the list which triggered itemChanged
	 */
	public String getLastList() {
		return lastList;
	}

	/**
	 * Provide the ToDo selected in the list, e.g. to the command bar component.
	 * 
	 * @see com.ibm.bpe.jsf.handler.ItemProvider#getSelectedItems()
	 */
	public List<ToDoInstance> getSelectedItems() {

		List<ToDoInstance> list = Collections.emptyList();
		if (toDoInstance != null) {
			list = new ArrayList<ToDoInstance>(1);
			list.add(toDoInstance);
		}
		return list;
	}

	/**
	 * Get the ToDo selected in the list
	 * 
	 * @return ToDo selected in the list
	 */
	public ToDoInstance getToDoInstance() {
		return toDoInstance;
	}
	
	/**
	 * Set boolean indicating if sub task templates are available.
	 */
	public void setSubTaskTemplatesAvailable(boolean subTaskTemplatesAvailable) {
		this.subTaskTemplatesAvailable = subTaskTemplatesAvailable;
	}

	/**
	 * Defines whether or not a bpe:commandbar is needed.
	 * 
	 * @return boolean indicating whether or not a bpe:commandbar is needed.
	 */
	public boolean isCommandBarNeeded() {
		return isJSFClientType(toDoInstance);
	}

	/**
	 * Boolean indicating whether it is allowed to create a sub ToDo for current
	 * toDoInstance and if potential sub ToDos are available.
	 * 
	 * @return boolean indicating whether it is allowed to create a sub ToDo for
	 *         current toDoInstance
	 */
	public boolean isSubToDoCreationAllowed() {
		boolean ret = false;
		
		if ((toDoInstance != null) && (subTaskTemplatesAvailable)) {
			ret = toDoInstance.supportsSubTasks();
		}
		return ret;
	}
}
