/* 
 *  InteractionEventTask.java
 * 
 *  Copyright 2016 Avaya Inc. All Rights Reserved.
 * 
 *  Usage of this source is bound to the terms described
 *  in AvayaLicenseSDK.rtf.
 * 
 *  Avaya - Confidential & Proprietary. Use pursuant to your signed agreement
 *  or Avaya Policy
 * 
 */
package com.avaya.ccs.javafxrefclient;

import com.avaya.ccs.api.*;
import com.avaya.ccs.api.enums.CodeType;
import com.avaya.ccs.api.enums.ContactType;
import com.avaya.ccs.api.enums.InteractionState;
import com.avaya.ccs.api.enums.NotificationType;
import com.avaya.ccs.api.enums.StateReason;
import com.avaya.ccs.api.exceptions.ObjectInvalidException;
import com.avaya.ccs.core.*;

import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.concurrent.WorkerStateEvent;

public class InteractionEventTask extends Task<Object> {

    private final NotificationEventI<InteractionI> interactionEvent;
    private final InteractionDataGUI gui;
    private final SupervisorDataGUI superGui;
    private static final Logger LOG = Logger.getLogger(InteractionEventTask.class);
    
    InteractionExecutor interactionExecutor;

    public InteractionEventTask(NotificationEventI<InteractionI> interactionEvent, InteractionDataGUI gui,
            SupervisorDataGUI gui2, InteractionExecutor interactionExecutor) {
    	this.interactionEvent = interactionEvent;
        this.gui = gui;
        this.superGui = gui2;
        this.interactionExecutor=interactionExecutor;
        setupJavaFXApplicationSucceededHandler();
    }

    private void setupJavaFXApplicationSucceededHandler() {
        this.setOnSucceeded((WorkerStateEvent t) -> {
            String methodName = "succeededHandler() ";
            Object value = t.getSource().getValue();
            if (value == null) {
                LOG.debug(methodName + "NULL");
            } else if (value instanceof InteractionData) {
                InteractionData newData = (InteractionData) value;
                if (!newData.isDeleted())
                    LOG.info(methodName + "InteractionData:" + newData);
                else
                    LOG.info(methodName + "Deletion of InteractionData-ID:" + newData.getId());
                gui.UpdateInteractionData(newData);
                superGui.updateInteraction(newData);
                if (newData.getState() ==InteractionState.Initiated && newData.getContactType()==ContactType.EMail) {
                	//this is an ad-hoc email. Doesn't need to be Answered: just send the Media GET request
                	interactionExecutor.openInteractionMedia(newData.getId());
                }              
            } else if (value instanceof CodeListI) {
                CodeListI codes = (CodeListI) value;
                LOG.info(methodName + "CodeListI:" + codes);
                gui.updateCodeSectionForm(codes);
                InteractionI thisInteraction = interactionEvent.getNotificationObject();
                
                try {
					if (thisInteraction.getContactType() ==ContactType.EMail) {
						if (codes.getCodeType()==CodeType.Activity) {
							gui.getEmailFormForContact(thisInteraction.getId()).setActivityCodes(codes);
	                	} else if (codes.getCodeType()==CodeType.Disposition) {
	                		gui.getEmailFormForContact(thisInteraction.getId()).setDispositionCodes(codes);
	                	}	
					} 

					else if (thisInteraction.getContactType() ==ContactType.Web_Communications) {
						
						WebchatForm form=null;
						if (thisInteraction.getStateReason()==StateReason.BargeIn || thisInteraction.getStateReason()==StateReason.Observe) {
	            			//the chat form will be held by the Supervisor form
	            			form=superGui.getWebChatFormForContact(thisInteraction.getId());
	            		} else {
	            			form = gui.getWebChatFormForContact(thisInteraction.getId());
	            		}
	            		if (codes.getCodeType() ==CodeType.Disposition) {
	            			form.setDispositionCodes(codes);
	            		} else if (codes.getCodeType()==CodeType.Activity)
	            			form.setActivityCodes(codes);
	            		}
				} catch (ObjectInvalidException e) {
					LOG.error(methodName, e);
				}
                
            } else if (value instanceof DestinationListI) {
                DestinationListI destinations = (DestinationListI) value;
                LOG.info(methodName + "DestinationListI:" + destinations);
//              if (destinations.getListType() == DestinationListType.Consult) { 
                InteractionI interaction= interactionEvent.getNotificationObject();
                try {
                    if (interaction.getContactType()==ContactType.EMail) {
                        if (interaction.getState()==InteractionState.Initiated) { //an email with InteractionState.Initiated indicates an ad-hoc email
                            gui.getEmailFormForContact(interaction.getId()).setOriginators(destinations);
                        }

                        gui.getEmailFormForContact(interaction.getId()).getConsultForm().updateDestinationList(interactionEvent.getNotificationObject().getId(), destinations);
                    }
                    else if (interaction.getContactType()==ContactType.Web_Communications)
                        gui.getWebChatFormForContact(interaction.getId()).getConsultForm().updateDestinationList(interactionEvent.getNotificationObject().getId(), destinations);
                    else
                        gui.getConsultForm().updateDestinationList(interactionEvent.getNotificationObject().getId(), destinations);
                } catch (ObjectInvalidException e) {
                    LOG.error(methodName, e);
                }

//                } else if (destinations.getListType() == DestinationListType.Callback) { //TODO conroy1 implement callbacks in a future release
//                    gui.getCallbackForm().updateDestinationList(interactionEvent.getNotificationObject().getId(),
//                            destinations); 
//                }
            } else if (value instanceof CustomerHistoryI ) {
            	try {
            		CustomerHistory custHistory = (CustomerHistory) value;
                    LOG.info(methodName + "CustomerHistory:" + custHistory);
                    InteractionI thisInteraction = interactionEvent.getNotificationObject();
					if (interactionEvent.getNotificationObject().getContactType()==ContactType.Web_Communications) {
						gui.getWebChatFormForContact(thisInteraction.getId()).setCustomerHistory(custHistory);
						gui.getWebChatFormForContact(interactionEvent.getNotificationObject().getId()).updateForm();
					} else if (interactionEvent.getNotificationObject().getContactType()==ContactType.EMail) {
						if (interactionEvent.getNotificationObject().getContactType()==ContactType.EMail) {
							gui.getEmailFormForContact(thisInteraction.getId()).setCustomerHistory(custHistory);
							gui.getEmailFormForContact(interactionEvent.getNotificationObject().getId()).updateForm();
						}
					}
				} catch (ObjectInvalidException e) {
					LOG.error(methodName, e);
				}
            } else if (value instanceof CustomerInteractionMediaList) {
            	try {
					if (interactionEvent.getNotificationObject().getContactType()==ContactType.EMail)
						gui.getEmailFormForContact(interactionEvent.getNotificationObject().getId()).setCustomerInteractionMediaList((CustomerInteractionMediaList)value);
					else if (interactionEvent.getNotificationObject().getContactType()==ContactType.Web_Communications)
						gui.getWebChatFormForContact(interactionEvent.getNotificationObject().getId()).setCustomerInteractionMediaList((CustomerInteractionMediaList)value);
				} catch (ObjectInvalidException e) {
					LOG.error("Ex.", e);
				}
            } else if (value instanceof CustomFieldListI) {
                CustomFieldListI customFields = (CustomFieldListI) value;
                LOG.info(methodName + "CustomFieldListI:" + customFields);
                gui.getSideBar().updateCustomFields(customFields);
            } else if (value instanceof PagePushUrlListI) {
            	gui.getWebChatFormForContact(interactionEvent.getNotificationObject().getId()).setPagePushUrls((PagePushUrlListI) value);
            } else if (value instanceof AutoPhrasesI) {
            	gui.getWebChatFormForContact(interactionEvent.getNotificationObject().getId()).setAutoPhrases((AutoPhrasesI) value);
            } else if(value instanceof ApprovalInformationI) {
				ApprovalInformation approvalInfo = (ApprovalInformation) value;
				try {
					if (interactionEvent.getNotificationObject().getContactType()==ContactType.EMail) {
						InteractionI thisInteraction = interactionEvent.getNotificationObject();
						gui.getEmailFormForContact(thisInteraction.getId()).setIsForAudit(approvalInfo);
						gui.getEmailFormForContact(interactionEvent.getNotificationObject().getId()).updateForm();

					}
				} catch (ObjectInvalidException e) {
					LOG.error(methodName, e);
				}
			}else if(value instanceof  ApprovalAuditInformationI) {
				ApprovalAuditInformation approvalAuditInfo = (ApprovalAuditInformation) value;
				try {
					if (interactionEvent.getNotificationObject().getContactType()==ContactType.EMail) {
						InteractionI thisInteraction = interactionEvent.getNotificationObject();
						gui.getEmailFormForContact(thisInteraction.getId()).addApprovalId(approvalAuditInfo);
						gui.getEmailFormForContact(interactionEvent.getNotificationObject().getId()).updateForm();
					}
				} catch (ObjectInvalidException e) {
					LOG.error(methodName, e);
				}
			}
        });
    }
    
    /**
     * The call method executes on the incomingEvent thread
     *
     * @return
     * @throws Exception
     */
    @Override
    protected Object call() throws Exception {
        String methodName = "call() ";
        InteractionData data = null;      
        NotificationType type = interactionEvent.getNotificationType();
        LOG.debug(methodName + "Type:" + type + " ID:" + interactionEvent.getNotificationObject().getId());
    	gui.redrawControls();
    	
        switch (type) {
	        case UPDATE:
	            data = new InteractionData(interactionEvent.getNotificationObject());
	            switch (data.getState()) {
		            case Wrapup:
		                if (data.getWrapupTimer() >= 0) {
		                    LOG.debug(methodName + " create wrapup timer if not already running");
		                    InteractionExecutor.getTimers().startWrapUp(data.getWrapupTimer(), data.getId(), this.gui);
		                    data.setTimeLeft(data.getWrapupTimer());
		                }
		                break;
		            case Active:
		            	if (interactionEvent.getNotificationObject().isMultimedia()) {
		            		//open the multimedia stream
		            		LOG.debug(methodName + " canOpenMedia: " + data.canOpenMedia());
		            		if (data.canOpenMedia())
		            			interactionExecutor.openInteractionMedia(interactionEvent.getNotificationObject().getId()); 
		            		
		            		String id=interactionEvent.getNotificationObject().getId();
		            		
		            		if (data.getContactType()==ContactType.Web_Communications) {
		             			WebchatForm form =null;
			            		
		             			if (data.getStateReason()==StateReason.BargeIn || data.getStateReason()==StateReason.Observe) {
			            			form=superGui.getWebChatFormForContact(id);
			            		} else {
			            			form = gui.getWebChatFormForContact(id);
			            		}
			            		
			            		if (form==null) {
			            			LOG.debug(methodName + " no form found for id: "+id);
			            			
			            			if (data.getStateReason()==StateReason.ConferenceComplete) {
			            				gui.createAndAddNewWebchatForm(data.getId());
			            				form = gui.getWebChatFormForContact(data.getId());
			                    		LOG.debug("got the form? " + (form==null));
			                    		form.setInteractionData(data);
			            			}
			            		} 
			            		LOG.info(methodName +"form interactionId: "+form.getInteractionId());
			            		
			            		try {
				            		if (form.isInteractionDataSet())
				            			form.updateInteractionData(data);
				            		else
				            			form.setInteractionData(data);
			            			
			            		} catch (Exception e) {
			            			LOG.error(methodName, e);
			            		}
		            		} 
		            	}
		            	return data;
	            case Dropped: // happens in the case of a WebChat, where the customer disconnected
	            	LOG.debug(methodName + " InteractionEventTask case Dropped");
	            	data = new InteractionData(interactionEvent.getNotificationObject().getId(), true);
	            	InteractionExecutor.getTimers().stop(interactionEvent.getNotificationObject().getId());
	                break;
	            case Held:
	            	LOG.debug(methodName + " InteractionEventTask case Held");
	            	data = new InteractionData(interactionEvent.getNotificationObject());
	            	WebchatForm form = gui.getWebChatFormForContact(interactionEvent.getNotificationObject().getId());
	            	if (form != null) {
	            		form.updateInteractionData(data);
	            	}
	            	InteractionExecutor.getTimers().stop(interactionEvent.getNotificationObject().getId());
	            	break;
	            case Dialing:
	            case Pending:
	            case Ringing:
	            case Unknown:
	            default:
	                InteractionExecutor.getTimers().stop(interactionEvent.getNotificationObject().getId());
	                break;
	            }
            break;
        case DELETE:
        	if (interactionEvent.getNotificationObject().getStateReason().equals(StateReason.ConferenceComplete) && interactionEvent.getNotificationObject().getState().equals(InteractionState.Dropped))  {
        		WebchatForm thisForm= gui.getWebChatFormForContact(interactionEvent.getNotificationObject().getId());
        		//TODO conroy1 possible race condition here? Can the form interaction be deleted before the .close() action is performed on the required form?
        		Platform.runLater(()->{
        			thisForm.close();
        		});
        	} else if (interactionEvent.getNotificationObject().getStateReason()==StateReason.TransferComplete) {
        		LOG.debug("DELETE and TransferComplete: will close the form");
        		WebchatForm thisForm= gui.getWebChatFormForContact(interactionEvent.getNotificationObject().getId());
        		//TODO conroy1 possible race condition here? Can the form interaction be deleted before the .close() action is performed on the required form?      		
        		Platform.runLater(()->{
        			thisForm.close();
        		});
        	}
        		
            InteractionExecutor.getTimers().stop(interactionEvent.getNotificationObject().getId());
            data = new InteractionData(interactionEvent.getNotificationObject().getId(), true);
            break;
        case ERROR:
            LOG.errorStatus(interactionEvent.getError());
            break;
        case NEW:
            data = new InteractionData(interactionEvent.getNotificationObject());
            switch (data.getState()) {
            case Preview:
                if (data.getPreviewTimer() >= 0) {
                    LOG.debug(methodName + "New interaction in preview state, start preview timer");
                    InteractionExecutor.getTimers().startPreview(data.getPreviewTimer(), data.getId(),
                            data.getDefaultOrFirstContactNumber(), this.gui);
                    data.setTimeLeft(data.getPreviewTimer());
                }
                break;

            case Active:  
            	if (data.getContactType()==ContactType.Web_Communications) {
            		if (data.getStateReason()==StateReason.Observe) { //this is an observed webchat
                		String id = interactionEvent.getNotificationObject().getId();
                		LOG.info("Observed Interaction. id: "+id);
                		
                		WebchatForm form=null;
                		if (data.getStateReason()==StateReason.BargeIn || data.getStateReason()==StateReason.Observe) {
	            			//the chat form will be held by the Supervisor form
	            			form=superGui.getWebChatFormForContact(id);
	            			if (form==null)
	            				LOG.warn(methodName, "No form found");
	            		} else {
	            			form = gui.getWebChatFormForContact(id);
	            		}
                		
                		form.setInteractionData(data);
                		if (data.canOpenMedia()) {
                			interactionExecutor.openInteractionMedia(interactionEvent.getNotificationObject().getId()); 
                 		}
            		} else if (data.getStateReason().equals(StateReason.TransferComplete)) {
        				gui.createAndAddNewWebchatForm(data.getId());
        				Thread.currentThread().sleep(300); //conroy1 workaround to get past race conditions-- the new form might take a few cycles to be created
                		WebchatForm form = gui.getWebChatFormForContact(data.getId());
                		
                		form.setInteractionData(data);
                		if (data.canOpenMedia()) {
                			interactionExecutor.openInteractionMedia(data.getId()); 
                 		}
                	}
            	
                    }
                break;
            }
            break;
        case RESPONSE:
            ResponseData resp = interactionEvent.getResponseData();
            return resp;
        case UNKNOWN:
        	data = new InteractionData(interactionEvent.getNotificationObject());
        	break;
        }
        return data;
    }
}
