package gov.va.vinci.dart;

import gov.va.vinci.dart.biz.Activity;
import gov.va.vinci.dart.biz.DartRequest;
import gov.va.vinci.dart.biz.DataSource;
import gov.va.vinci.dart.biz.DocumentTemplate;
import gov.va.vinci.dart.biz.OperationalRequest;
import gov.va.vinci.dart.biz.Person;
import gov.va.vinci.dart.biz.PreparatoryRequest;
import gov.va.vinci.dart.biz.Request;
import gov.va.vinci.dart.biz.Role;
import gov.va.vinci.dart.common.exception.ObjectNotFoundException;
import gov.va.vinci.dart.common.json.ErrorView;
import gov.va.vinci.dart.db.util.HibernateSessionManager;
import gov.va.vinci.dart.json.DataSourceIdView;
import gov.va.vinci.dart.json.DataSourceListView;
import gov.va.vinci.dart.json.DataSourceView;
import gov.va.vinci.dart.json.DocumentTemplateListView;
import gov.va.vinci.dart.json.DocumentTemplateView;
import gov.va.vinci.dart.json.RequestIdView;
import gov.va.vinci.dart.json.SaveRequestDataSourcesView;
import gov.va.vinci.dart.json.builder.RequestDataSourcesViewBuilder;
import gov.va.vinci.dart.usr.UserPreferences;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class DataSourceController extends DartController {
	public static final SimpleDateFormat SDF = new SimpleDateFormat("MM/dd/yyyy");
	private static Log log = LogFactory.getLog(DataSourceController.class);
	
	
	@RequestMapping(value = "/getAllDataSources", method = RequestMethod.POST)
	@ResponseBody
	public Object getAllDataSources(final HttpServletRequest request) {

		log.debug("getAllDataSources");

		try {
			HibernateSessionManager.start();

			List<DataSource> dslist = DataSource.listAll();
		
			DataSourceListView result = new DataSourceListView();
			
			for (DataSource ds : dslist) {
				DataSourceView view = new DataSourceView();
				view.setId(ds.getId());
				view.setName(ds.getName());
				view.setDescription(ds.getDescription());
				view.setDomainName(ds.getDomainName());
	//			view.setFields(ds.getFields());
				view.setInfoSite(ds.getInfoSite());
				result.getDataSources().add(view);
			}

			return result;
		} catch (Exception e) {
			log.error("Error retrieving data sources.", e);
			HibernateSessionManager.rollback();
			return new ErrorView("Error retrieving data sources.");
		} finally {
			HibernateSessionManager.close();
		}
	}
	
	
	@RequestMapping(value = "/saveRequestDataSources", method = RequestMethod.POST)
	@ResponseBody
	public Object saveRequestDataSources(@RequestBody @Valid final SaveRequestDataSourcesView view) {
		
		log.debug("saveRequestDataSources");
		
		try {
			HibernateSessionManager.start();
			
			UserPreferences prefs = getUserPreferences();

			Person person = null;
			try {
				person = Person.findById(prefs.getUserId());
			} catch (ObjectNotFoundException e) {
				return new ErrorView("Error: Cannot find user " + prefs.getUserId());
			}
			Role.initialize();

			Request req = RequestController.retrieveRequest(view.getRequestId());
			if (req == null) {
				return new ErrorView("Error retrieving request.");
			}

			// is request changeable?
			if (req.isEditable(null) == false) {
				return new ErrorView("Error: request is not in editable state.");
			}

			//verify the access permissions
			if( req.hasCreatorOrParticipant(person) == false ) {	//participant or the request creator?
				return new ErrorView("Error: User does not have permission to perform this action.");
			}
			if( person.hasRole(Role.SUPER_USER) == true || person.hasRole(Role.NDS_ADMIN) == true || person.hasRole(Role.REVIEWER) == true || person.hasRole(Role.READ_ONLY_STAFF) == true ) {
				return new ErrorView("Error: User does not have permission to perform this action.");
			}


			Date startDate = isEmpty(view.getStartDate())==true ? null : SDF.parse(view.getStartDate());
			Date endDate = isEmpty(view.getEndDate())==true ? null : SDF.parse(view.getEndDate());

			if (DartRequest.class.isAssignableFrom(req.getClass()) == true) {
				DartRequest dartRequest = (DartRequest)req;
				dartRequest.setHipaaConsent(view.isHipaaAuth());
				dartRequest.setHipaaWaiver(view.isHipaaWaiver());
				dartRequest.setDataSourceLocation(view.getLocationName());	//not currently exposing this location field on the UI
				
				dartRequest.setDataMart(view.isDataMart());
				dartRequest.setLocalServer(view.isLocalServer());
				
				dartRequest.setLocalServerLocation(view.getLocalServerLocation());
				dartRequest.setLocalServerAddress(view.getLocalServerAddress());
				dartRequest.setLocalServerBuilding(view.getLocalServerBuilding());
				dartRequest.setLocalServerRoomNumber(view.getLocalServerRoomNumber());

                dartRequest.setTransferredExternal(view.isTransferredExternal());
                dartRequest.setExternalDestination(view.getExternalDestination());
                dartRequest.setExternalStreet(view.getExternalStreet());
                dartRequest.setExternalCity(view.getExternalCity());
                dartRequest.setExternalState(view.getExternalState());
                dartRequest.setExternalZipCode(view.getExternalZipCode());
				
				dartRequest.modify(req.getName(), startDate, endDate, req.getIrbNumber(), req.getIrbExpiration(), prefs.getUserLoginId());
				
				dartRequest.setRealSSN(view.isRealSSNIdentifier());
				dartRequest.setScrambledSSN(view.isScrambledSSNIdentifier());
				dartRequest.setPhiData(view.isPhiDataIdentifier());


				dartRequest.getDataSources().clear();
				for (Integer dsId : view.getDataSources()) {
					DataSource ds = DataSource.findById(dsId);
					dartRequest.getDataSources().add(ds);	
				}



				if( view.isMovingToDocsPage() ) {	//only bother to update the documents if we're moving forward in the wizard (linear movement only on create)

					//To handle the old Dart data:  if the request is not yet in a "final" state, get the possibly modified documents
					if( req.isCompletedStatus() == false ) {	//request is not yet in a "final" state

							// change the required documents.
							dartRequest.createDocuments(prefs.getUserLoginId());

					}//end if -- not yet in a final state
				}//end if
			} else if (PreparatoryRequest.class.isAssignableFrom(req.getClass())) {
			    PreparatoryRequest preparatoryRequest = (PreparatoryRequest)req;

                preparatoryRequest.setDataSourceLocation(view.getLocationName());  //not currently exposing this location field on the UI
                
                preparatoryRequest.setDataMart(view.isDataMart());

                
                preparatoryRequest.modify(req.getName(), preparatoryRequest.getExpectedIRBSubmissionDate(), prefs.getUserLoginId());
                
                preparatoryRequest.setRealSSN(view.isRealSSNIdentifier());
                preparatoryRequest.setScrambledSSN(view.isScrambledSSNIdentifier());
                preparatoryRequest.setPhiData(view.isPhiDataIdentifier());


                preparatoryRequest.getDataSources().clear();
                for (Integer dsId : view.getDataSources()) {
                    DataSource ds = DataSource.findById(dsId);
                    preparatoryRequest.getDataSources().add(ds);   
                }



                if( view.isMovingToDocsPage() ) {   //only bother to update the documents if we're moving forward in the wizard (linear movement only on create)

                    //To handle the old Dart data:  if the request is not yet in a "final" state, get the possibly modified documents
                    if( req.isCompletedStatus() == false ) {    //request is not yet in a "final" state

                            // change the required documents.
                            preparatoryRequest.createDocuments(prefs.getUserLoginId());

                    }//end if -- not yet in a final state
                }//end if
            }
			else if (OperationalRequest.class.isAssignableFrom(req.getClass()) == true) {
				OperationalRequest oReq = (OperationalRequest)req;
				
				oReq.setDataMart(view.isDataMart());
				oReq.setLocalServer(view.isLocalServer());
				
				oReq.setLocalServerLocation(view.getLocalServerLocation());
				oReq.setLocalServerAddress(view.getLocalServerAddress());
				oReq.setLocalServerBuilding(view.getLocalServerBuilding());
				oReq.setLocalServerRoomNumber(view.getLocalServerRoomNumber());


				oReq.getDataSources().clear();
				for (Integer dsId : view.getDataSources()) {
					DataSource ds = DataSource.findById(dsId);
					oReq.getDataSources().add(ds);	
				}


				if( view.isMovingToDocsPage() ) {	//only bother to update the documents if we're moving forward in the wizard (linear movement only on create)

					//To handle the old Dart data:  if the request is not yet in a "final" state, get the possibly modified documents
					if( req.isCompletedStatus() == false ) {	//request is not yet in a "final" state

							// change the required documents.
							oReq.createDocuments(prefs.getUserLoginId());

					}//end if -- not yet in a final state
				}//end if
			}
			
		} catch (Exception e) {
			log.error("Error saving request data sources.", e);
			HibernateSessionManager.rollback();
			return new ErrorView("Error saving request data sources.");
		} finally {
			HibernateSessionManager.close();
		}
		
		return new ErrorView("OK");
	}

	public static boolean isEmpty(String str) {
		return str == null || str.length() < 1;
	}
	
	@RequestMapping(value = "/getRequestDataSources", method = RequestMethod.POST)
	@ResponseBody
	public Object getRequestDataSources(@RequestBody @Valid final RequestIdView view) {
		log.debug("getRequestDataSources");
		
		try {
			HibernateSessionManager.start();

			UserPreferences prefs = getUserPreferences();
		
			Person person = null;
			try {
				person = Person.findById(prefs.getUserId());
			} catch (ObjectNotFoundException e) {
				return new ErrorView("Error: Cannot find user " + prefs.getUserId());
			}
			Role.initialize();

			Request request = null;
			try {
				request = RequestController.retrieveRequest(view.getRequestId());
				
			} catch (ObjectNotFoundException e) {
				log.error("Error loading request " + view.getRequestId(), e);
				return new ErrorView("Error loading request " + view.getRequestId());
			}
			
			if (request == null) {
				return new ErrorView("Error loading request " + view.getRequestId());
			}

			Activity activity = request.getActivity();
			if( activity == null ) {
				return new ErrorView("Error retrieving activity.");
			}
			
			//verify the access permissions
			if( activity.verifyReadAccessPermissions(person) == false ) {
				return new ErrorView("Error: User does not have permission to perform this action.");
			}
			
			
			return new RequestDataSourcesViewBuilder().build(request, prefs.getUserId());
			
		} catch (Exception e) {
			log.error("Error retrieving request data sources.", e);
			HibernateSessionManager.rollback();
			return new ErrorView("Error retrieving request data sources.");
		} finally {
			HibernateSessionManager.close();
		}
	}

	@RequestMapping(value = "/getDataSourceInfo", method = RequestMethod.POST)
	@ResponseBody
	public Object getDataSourceInfo(@RequestBody @Valid final DataSourceIdView view) {
		
		log.debug("getDataSourceInfo");
		try {
			HibernateSessionManager.start();

			DataSource ds = DataSource.findById(view.getId());
			
			DataSourceView result = new DataSourceView();
			result.setId(ds.getId());
			result.setName(ds.getName());
			result.setDescription(ds.getDescription());
			result.setDomainName(ds.getDomainName());
			result.setFields("fields fields fields");
			result.setInfoSite(ds.getInfoSite());
			
			return result;
			
		} catch (Exception e) {
			log.error("Error retrieving request data sources.", e);
			HibernateSessionManager.rollback();
			return new ErrorView("Error retrieving request data sources.");
		} finally {
			HibernateSessionManager.close();
		}
	}
		
	@SuppressWarnings("unchecked")
	@RequestMapping(value = "/listDocumentTemplatesByDataSource", method = RequestMethod.POST)
	@ResponseBody
	public Object listDocumentTemplatesByDataSource(@RequestBody @Valid final DataSourceIdView request) {
		
		log.debug("listDocumentTemplatesByDataSource");
		try {
			HibernateSessionManager.start();

			DataSource ds = DataSource.findById(request.getId());
			
			DocumentTemplateListView result = new DocumentTemplateListView();
			
			List<DocumentTemplate> dlist = new ArrayList<DocumentTemplate>();
			dlist.addAll(ds.getDocumentTemplates());
			
			// sort the list!
			Collections.sort(dlist, DocumentTemplate.getComparator());
			
			for (DocumentTemplate temp : dlist) {
				DocumentTemplateView view = new DocumentTemplateView();
				view.setId(temp.getId());
				view.setName(temp.getName());
				
				//if we have no document description, then use the template name (we might NOT want this permanently)
				String descrStr = temp.getDescription();
				if(descrStr == null || descrStr.isEmpty()) {
					descrStr = temp.getName();
				}
				view.setDescription(descrStr);
				log.debug("DocumentTemplate description:  " + descrStr);
	
				
				view.setLocation(temp.isLocation());
				view.setParticipant(temp.isParticipant());
				view.setPrincipalInvestigator(temp.isPrincipalInvestigator());
				view.setAdministrator(temp.isAdministrator());
				view.setActivityType(temp.getActivityType());
				view.setSortOrder(temp.getSortOrder());
				
				result.getTemplates().add(view);
			}
			
			return result;
		} catch (Exception e) {
			log.error("Error retrieving request data sources.", e);
			HibernateSessionManager.rollback();
			return new ErrorView("Error retrieving request data sources.");
		} finally {
			HibernateSessionManager.close();
		}
	}
}
