package gov.va.vinci.dart.json.builder;

import java.text.SimpleDateFormat;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

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

import gov.va.vinci.dart.common.exception.ObjectNotFoundException;
import gov.va.vinci.dart.biz.DartRequest;
import gov.va.vinci.dart.biz.DataSource;
import gov.va.vinci.dart.biz.OperationalRequest;
import gov.va.vinci.dart.biz.PreparatoryRequest;
import gov.va.vinci.dart.biz.Request;
import gov.va.vinci.dart.biz.WorkflowTemplate;
import gov.va.vinci.dart.json.RequestDataSourcesView;

public class RequestDataSourcesViewBuilder {
	private static Log log = LogFactory.getLog(RequestDataSourcesViewBuilder.class);

	public static final SimpleDateFormat SDF = new SimpleDateFormat("MM/dd/yyyy");

	public RequestDataSourcesView build(final Request request, final int userId) {
		RequestDataSourcesView result = new RequestDataSourcesView();
		
		if( request != null ) {
			
			result.setRequestId(request.getId());
			result.setUserId(userId);
			
			if (DartRequest.class.isAssignableFrom(request.getClass())) {
				DartRequest dartRequest = (DartRequest)request;
				
				result.setHipaaAuth(dartRequest.isHipaaConsent());
				result.setHipaaWaiver(dartRequest.isHipaaWaiver());
				result.setStartDate(dartRequest.getDataSourceStartDate()==null?null:SDF.format(dartRequest.getDataSourceStartDate()));
				result.setEndDate(dartRequest.getDataSourceEndDate()==null?null:SDF.format(dartRequest.getDataSourceEndDate()));
				result.setLocationName(dartRequest.getDataSourceLocation());

				result.setDataMart(dartRequest.isDataMart());
				result.setLocalServer(dartRequest.isLocalServer());
				
				result.setLocalServerLocation(dartRequest.getLocalServerLocation());
				result.setLocalServerAddress(dartRequest.getLocalServerAddress());
				result.setLocalServerBuilding(dartRequest.getLocalServerBuilding());
				result.setLocalServerRoomNumber(dartRequest.getLocalServerRoomNumber());
	
	            result.setTransferredExternal(dartRequest.isTransferredExternal());
	            result.setExternalDestination(dartRequest.getExternalDestination());
	            result.setExternalStreet(dartRequest.getExternalStreet());
	            result.setExternalCity(dartRequest.getExternalCity());
	            result.setExternalState(dartRequest.getExternalState());
	            result.setExternalZipCode(dartRequest.getExternalZipCode());
	
				result.setRealSSNIdentifier(dartRequest.isRealSSN());
				result.setScrambledSSNIdentifier(dartRequest.isScrambledSSN());
				result.setPhiDataIdentifier(dartRequest.isPhiData());				
	
				for (DataSource ds : dartRequest.getDataSources()) {
					// sure we only send back the data source ids...
					result.getDataSources().add(ds.getId());
				}


				buildEditable(request, result);
				
				
			} else if( OperationalRequest.class.isAssignableFrom(request.getClass()) ) {
	
				OperationalRequest opRequest = (OperationalRequest)request;
	
				result.setDataMart(opRequest.isDataMart());
				result.setLocalServer(opRequest.isLocalServer());
				
				result.setLocalServerLocation(opRequest.getLocalServerLocation());
				result.setLocalServerAddress(opRequest.getLocalServerAddress());
				result.setLocalServerBuilding(opRequest.getLocalServerBuilding());
				result.setLocalServerRoomNumber(opRequest.getLocalServerRoomNumber());
				
				for (DataSource ds : opRequest.getDataSources()) {
					// sure we only send back the data source ids...
					result.getDataSources().add(ds.getId());
				}

			} else if (PreparatoryRequest.class.isAssignableFrom(request.getClass())) {
			    PreparatoryRequest preparatoryRequest = (PreparatoryRequest)request;

                result.setLocationName(preparatoryRequest.getDataSourceLocation());
                result.setDataMart(preparatoryRequest.isDataMart());
                result.setRealSSNIdentifier(preparatoryRequest.isRealSSN());
                result.setScrambledSSNIdentifier(preparatoryRequest.isScrambledSSN());
                result.setPhiDataIdentifier(preparatoryRequest.isPhiData());               
    
                for (DataSource ds : preparatoryRequest.getDataSources()) {
                    result.getDataSources().add(ds.getId());
                }

                buildEditable(request, result);
            } 
		}

		return result;
	}

    private void buildEditable(final Request request, RequestDataSourcesView result) {

        //Determine if any of the data sources are already approved or if the request/workflow is not currently editable
        try {
        	if( request.isEditable(null) ) {	//only need to retrieve the already approved data sources if the request is editable

        		//cannot alter the data sources for workflows that are not currently editable (current request)
        		Set<DataSource> lockedDataSources = request.getLockedDataSources();
        		if( lockedDataSources != null && lockedDataSources.size() > 0 ) {
        			for( DataSource ds : lockedDataSources ) {
        				if( ds != null ) {
        					// sure we only send back the data source ids...
        					result.getLockedDataSources().add(ds.getId());	
        					//add this DataSource id to the list of locked data sources
        				}
        			}
        		}

        		
        		//already approved data sources cannot be removed (current request)
        		Set<DataSource> approvedDataSources = request.getSelectedAndApprovedDataSources();
        		if( approvedDataSources != null && approvedDataSources.size() > 0 ) {
        			for( DataSource ds : approvedDataSources ) {
        				if( ds != null ) {

        					// sure we only send back the data source ids...
        					result.getApprovedDataSources().add(ds.getId());	
        					//add this DataSource id to the list of approved data sources
        				}
        			}
        		}


        		List<Integer> disabledDataSourceIDs = DataSource.findDisabledIdByRequestType(request.getRequestType());	//currently disabled data sources
        		if( disabledDataSourceIDs != null && disabledDataSourceIDs.size() > 0 ) {
        			for( Integer dsID : disabledDataSourceIDs ) {
        				if( dsID != null ) {
        					// sure we only send back the data source ids...
        					result.getDisabledDataSources().add( dsID );	
        					//add this DataSource id to the list of disabled data sources
        				}
        			}
        		}

        		//Approved data sources cannot be removed during an amendment.  New data sources can be added to the set of approved data sources.
        		if( request.isAmendment() ) {

        			Set<Integer> approvedDataSourceSet = new HashSet<Integer>();

        			//get the approved data sources for the previous request in the chain
        			//List<Request> prevReqList = Request.listAllPreviousRequests(request.getHeadId(), request.getTrackingNumber());
        			List<Request> prevReqList = Request.listAllPreviousRequests(request.getHeadId(), request.getCreatedOn());
        			if( prevReqList != null && prevReqList.size() > 0 ) {

        				Request prevRequest = prevReqList.get(0);	//only use the most recent request, because some of the approved data sources may have been removed before this requirements change (3/22/2015)

        				if( prevRequest != null ) {

        					Set<DataSource> prevApprovedDataSourceSet = prevRequest.getSelectedAndApprovedDataSources();
        					if( prevApprovedDataSourceSet != null && prevApprovedDataSourceSet.size() > 0 ) {

        						//add the selected data sources for the previous approved request (either the top-level request was approved or the workflow was approved)
        						for( DataSource prevDS : prevApprovedDataSourceSet ) {

        							if( disabledDataSourceIDs != null && disabledDataSourceIDs.isEmpty() == false ) {	//have some disabled data sources

        								if( disabledDataSourceIDs.contains( prevDS.getId() ) == false ) {	//don't require the disabled data sources from the previous request
        									approvedDataSourceSet.add( prevDS.getId() );
        								}//end if
        								
        							} else {	//nothing disabled, so keep all of the data sources
        								approvedDataSourceSet.add( prevDS.getId() );
        							}
        						}
        					}
        				}
        			}
        			result.getApprovedDataSources().addAll( approvedDataSourceSet );	//add all of the previously approved data sources to the list
        		}
        	}
        } catch (ObjectNotFoundException e) {
        	log.error("Error retrieving the request status: " + e.getMessage());
        	e.printStackTrace();
        }
    }
}
