package gov.va.vinci.dart.wf2;

import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import gov.va.vinci.dart.common.ValidationHelper;
import gov.va.vinci.dart.common.exception.ValidationException;
import gov.va.vinci.dart.biz.Group;
import gov.va.vinci.dart.biz.GroupTask;
import gov.va.vinci.dart.biz.Person;
import gov.va.vinci.dart.biz.PersonTask;
import gov.va.vinci.dart.biz.Request;
import gov.va.vinci.dart.biz.RequestWorkflow;
import gov.va.vinci.dart.biz.Role;
import gov.va.vinci.dart.biz.Task;

/** Utilities for managing tasks created by workflows.
 * 
 */
public abstract class TaskUtils {
	
	private static Log log = LogFactory.getLog(TaskUtils.class);

	/** Complete a task.
	 * 
	 * @param task
	 * @param userLoginId
	 * @throws ValidationException
	 */
	protected static void completeTask(final Task task, final String userLoginId) throws ValidationException {

		if (task == null) {
			throw new ValidationException("Error closing task:  no task to close");
		}
		
		//log.debug("completeTask " + task.getId());

		task.complete(userLoginId);	
	}

	
	/**
	 * When the request is submitted, close all associated PersonTasks (for this workflow).
	 * 		Currently, these will only be Change Request tasks.
	 * 		Close all requestor tasks on submission, even if a participant submitted the request rather than the original requestor.
	 * 
	 * @param request
	 * @param userLoginId
	 * @throws ValidationException
	 */
	public static void closeUserTasksForChangeRequest( final RequestWorkflow workflow, final Request request, final String userLoginId ) throws ValidationException {

		ValidationHelper.required("Request", request);
		ValidationHelper.required("User ID", userLoginId);		
		
		try {

			List<PersonTask> tlist = null;
			
			if( workflow != null ) {
				tlist = PersonTask.listOpenByWorkflowAndRequestId(workflow.getId(), request.getId());	//get all of the open tasks for this request, for this specific workflow 
			} else {
				tlist = PersonTask.listOpenByRequestId(request.getId());	//get all of the open tasks for this request (regardless of workflow)
			}
			
			
			//step through the open PersonTasks for this request
			if( tlist != null ) {
				for (Task task : tlist) {
					if (task.getCompletedOn() == null) {	//not completed
											
						//close this task
						//	ignoring the ownerId, so that if a participant resubmits the request, the original requestor task is closed
						completeTask( task, userLoginId );
						
					}
				}
			}
					
		} catch (Exception e) {
		    log.error("Failed to close Tasks: Exception message: " + e.getMessage());
			throw new ValidationException(e);
		}
	}

	
	/**
	 * When the NDS initial/final review is performed, close all associated review tasks.  (Close the review task for each member of the NDS_ADMIN group.)
	 * @param request
	 * @param userLoginId
	 * @throws ValidationException
	 */
	public static void closeGroupTasksForNDSReview( final Request request, final String userLoginId ) throws ValidationException {		
		
		ValidationHelper.required("Request", request);
		ValidationHelper.required("User ID", userLoginId);		
		
		try {

//TODO: pass in the workflow, just in case there are multiple NDS workflows attached to this request?

			Role.initialize(); 
			Group.initialize();

			
			// first - is user an NDS reviewer?
			Person person = Person.findByName( userLoginId );
			if (person.hasRole(Role.NDS_ADMIN) == false) {
				throw new ValidationException("User does not have necessary permission to complete this task.");
			}


			List<GroupTask> glist = GroupTask.listOpenByOwnerAndRequestId( Group.NDS.getId(), request.getId() );	//get open tasks for NDS (for this request)
			
			for (Task task : glist) {
				if (task.getCompletedOn() == null) {	//not completed
						
					//close this task
					completeTask( task, userLoginId );
					
				}//end if
			}//end for

		} catch (Exception e) {
		    log.error("Failed to close Tasks: Exception message: " + e.getMessage());
			throw new ValidationException(e);
		}	
	}

	
	/**
	 * Closes the GroupTask entries for the specified request and group (for this workflow).
	 * When a review for this group is performed, close all associated tasks.  (Close the review task for each member of this group.)
	 * 
	 * @param group
	 * @param request
	 * @param userLoginId
	 * @throws ValidationException
	 */
	public static void closeTasksForWorkflowAndGroup( final RequestWorkflow workflow, final Group group, final Request request, final String userLoginId ) throws ValidationException {		

		ValidationHelper.required("Request", request);
		ValidationHelper.required("User ID", userLoginId);		

		try {

			if(group != null) {

				Role.initialize();
				Person person = Person.findByName( userLoginId );
				if (person.hasRole(Role.REVIEWER) == false) {
					throw new ValidationException("User does not have necessary permission for this review.");
				}
				if( person.inGroup(group) == false ) {
					throw new ValidationException("User is not a member of " + group.getShortName() + ". Cannot close tasks for this group.");
				}


				List<GroupTask> glist = null;

				if( workflow != null ) {
					glist = GroupTask.listOpenByWorkflowAndOwnerAndRequestId( workflow.getId(), group.getId(), request.getId() );	//get the open tasks for this group (for this request), for this specific workflow
				} else {
					glist = GroupTask.listOpenByOwnerAndRequestId( group.getId(), request.getId() );	//get the open tasks for this group (for this request), regardless of workflow
				}


				if( glist != null ) {
					for (Task task : glist) {
						if (task.getCompletedOn() == null) {	//not completed

							//close this task
							completeTask( task, userLoginId );

						}//end if
					}//end for -- task
				}//end if
			}//end if -- group
			
		} catch (Exception e) {
		    log.error("Failed to close Tasks: Exception message: " + e.getMessage());
			throw new ValidationException(e);
		}
	}
	
	 /**
     * Allows and NDS Admin to withdraw a Review and close the specific request's 
     * GroupTask and PersonTask for individuals within the group for the provided workflow
     * When NDS withdraws the review for this group, close all associated tasks.  
     * 
     * @param group
     * @param request
     * @param userLoginId
     * @throws ValidationException
     */
    public static void closeTasksForWorkflowAndGroupByNDS( final RequestWorkflow workflow, final Group group, final Request request, final String userLoginId ) throws ValidationException {     

        ValidationHelper.required("Request", request);
        ValidationHelper.required("User ID", userLoginId);      

        try {

            if(group != null) {

                Role.initialize();
                Person person = Person.findByName( userLoginId );
                if (!person.hasRole(Role.NDS_ADMIN) ) {
                    throw new ValidationException("User does not have necessary permission for this review.");
                }
                

                List<GroupTask> glist = null;

                if( workflow != null ) {
                  //get the open tasks for this group (for this request), for this specific workflow
                    glist = GroupTask.listOpenByWorkflowAndOwnerAndRequestId( workflow.getId(), group.getId(), request.getId() );   
                } else {
                  //get the open tasks for this group (for this request), regardless of workflow
                    glist = GroupTask.listOpenByOwnerAndRequestId( group.getId(), request.getId() );    
                }


                if( glist != null ) {
                    for (Task task : glist) {
                        if (task.getCompletedOn() == null) { 

                            completeTask( task, userLoginId );

                        }
                    }
                }
            }
            
        } catch (Exception e) {
            log.error("Failed to close Tasks: Exception message: " + e.getMessage());
            throw new ValidationException(e);
        }
    }
	
	/**
	 * When the request is closed or denied, close all associated tasks (for this workflow).
	 * Closes both PersonTasks and GroupTasks.  (Request is put into a final state with no more open tasks.)
	 * 
	 * @param request
	 * @param userLoginId
	 * @throws ValidationException
	 */
	public static void closeAllTasksForWorkflowAndRequest( final RequestWorkflow workflow, final Request request, final String userLoginId ) throws ValidationException {

		ValidationHelper.required("Request", request);
		ValidationHelper.required("User ID", userLoginId);
		
		try {

			List<Task> tlist = null;
			
			if( workflow != null ) {
				tlist = Task.listOpenByWorkflowAndRequest(workflow.getId(), request.getId());	//get all of the open tasks for this request, for this specific workflow 
			} else {
				tlist = Task.listOpenByRequest(request.getId());	//get all of the open tasks for this request (regardless of workflow)
			}
			
			
			//step through the open tasks for this request and close them
			if( tlist != null ) {
				for (Task task : tlist) {
					if (task.getCompletedOn() == null) {	//not completed

						//close this task
						completeTask( task, userLoginId );								

					}//end if
				}//end for -- task list
			}//end if
					
		} catch (Exception e) {
		    log.error("Failed to close Tasks: Exception message: " + e.getMessage());
			throw new ValidationException(e);
		}
	}
}
