package com.agilex.healthcare.schedulingmanager.datalayer;

import com.agilex.healthcare.mobilehealthplatform.domain.PatientIdentifier;
import com.agilex.healthcare.mobilehealthplatform.domain.filter.datefilter.DateFilter;
import com.agilex.healthcare.schedulingmanager.domain.*;
import com.agilex.healthcare.schedulingmanager.domain.CancelAppointment;
import com.agilex.healthcare.schedulingmanager.mdws.MdwsSchedulingDataLayer;
import com.agilex.healthcare.schedulingmanager.mdws.MdwsResponseValidator;
import com.agilex.healthcare.schedulingmanager.mdws.connection.SchedulingConnection;
import com.agilex.healthcare.schedulingmanager.mdws.connection.MdwsConfiguration;
import com.agilex.healthcare.schedulingmanager.mdws.connection.MdwsConfigurationHelper;
import com.agilex.healthcare.schedulingmanager.mdws.generatedwsdl.schedulingservice.*;
import com.agilex.healthcare.schedulingmanager.mdws.translator.*;
import com.agilex.healthcare.schedulingmanager.validator.ResponseValidator;
import com.agilex.healthcare.utility.DateHelper;
import com.agilex.healthcare.utility.NullChecker;

import javax.annotation.Resource;

/**
 * Created with IntelliJ IDEA.
 * User: patelh
 * Date: 9/11/13
 * Time: 9:27 AM
 * To change this template use File | Settings | File Templates.
 */
public class SchedulingDataLayerMdws extends MdwsSchedulingDataLayer implements SchedulingDataLayer {

    @Resource
    ResponseValidator responseValidator;

    private final static org.apache.commons.logging.Log logger = org.apache.commons.logging.LogFactory.getLog(SchedulingDataLayerMdws.class);

    private static final String EWL_WAIT_LIST = "ewl";
    private static final String NEAR_WAIT_LIST = "near";
    private static final String RECALL_WAIT_LIST = "recall";

    public SchedulingDataLayerMdws(MdwsConfiguration mdwsConfiguration) {
        super(mdwsConfiguration);
    }

    /**
	 * Calls the following MDWS services for the given patient<br/>
	 * SchedulingSvc.getEwlByPatient<br/>
	 * SchedulingSvc.getNearListByPatient<br/>
	 * SchedulingSvc.getRecallListByPatient<br/>
	 */
	public WaitListEntries getPatientWaitList(PatientIdentifier patientIdentifier, String facilityCode) {
        WaitListEntries waitListEntries = new WaitListEntries();
        SchedulingConnection schedulingConnection = super.getAuthenticatedConnectionWithPatientSelected(facilityCode, patientIdentifier.getUniqueId());

        TaggedEwlStatusArrays taggedEwlStatusArrays = schedulingConnection.getPort().getEwlByPatient();

        TaggedNearListByPatientArrays taggedNearListByPatientArrays = schedulingConnection.getPort().getNearListByPatient();

        TaggedRecallListByPatientArrays taggedRecallListByPatientArrays = schedulingConnection.getPort().getRecallListByPatient();

        MdwsResponseValidator.validateMdwsObject(taggedEwlStatusArrays);

        MdwsResponseValidator.validateMdwsObject(taggedNearListByPatientArrays);

        MdwsResponseValidator.validateMdwsObject(taggedRecallListByPatientArrays);

        WaitListTranslator waitListTranslator = new WaitListTranslator();
        waitListTranslator.add(waitListEntries, taggedEwlStatusArrays);
        waitListTranslator.add(waitListEntries, taggedNearListByPatientArrays);
        waitListTranslator.add(waitListEntries, taggedRecallListByPatientArrays);

        return waitListEntries;
    }

	/**
	 * Calls the MDWS service SchedulingSvc.updateNearList for the given patient
	 */
	public String updateNearEntryForPatient(PatientIdentifier patientIdentifier, String facilityCode, String status) {
        UpdateNearListTO updateNearListTO;
        String response = "";
        SchedulingConnection schedulingConnection = super.getAuthenticatedConnectionWithPatientSelected(facilityCode, patientIdentifier.getUniqueId());

        TaggedUpdateNearListArrays taggedUpdateNearListArrays = schedulingConnection.getPort().updateNearList(status);

        updateNearListTO = taggedUpdateNearListArrays.getArrays().getTaggedUpdateNearListArray().get(0).getStatuses().getUpdateNearListTO().get(0);

        MdwsResponseValidator.validateMdwsObject(taggedUpdateNearListArrays);

        if(updateNearListTO.getCode() != null && Integer.parseInt(updateNearListTO.getCode()) == 0) {
            response = "Success";
        }

        return response;
    }

	/**
	 * Returns null
	 */
	public WaitListEntryDetail getWaitListEntryDetail(String waitListId, String facilityCode) {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

	/**
	 * Calls the following MDWS services<br/>
	 * SchedulingSvc.getEwlByFacility<br/>
	 * SchedulingSvc.getNearListByFacility<br/>
	 * SchedulingSvc.getRecallListByFacility<br/>
	 */
	public WaitListEntries getWaitListForFacility(String facilityCode, String waitListType) {
        WaitListEntries waitListEntries = new WaitListEntries();
        FacilityWaitListTranslator translator = new FacilityWaitListTranslator();
        TaggedEwlByFacilityArrays taggedEwlByFacilityArrays = null;
        TaggedRecallListByFacilityArrays taggedRecallListByFacilityArrays = null;
        TaggedNearListByFacilityArrays taggedNearListByFacilityArrays = null;

        SchedulingConnection authenticatedConnection = super.getAuthenticatedConnection(facilityCode);

        if(waitListType !=null && waitListType.equalsIgnoreCase(EWL_WAIT_LIST)){
            taggedEwlByFacilityArrays = authenticatedConnection.getPort().getEwlByFacility();
        }

        if(waitListType !=null && waitListType.equalsIgnoreCase(NEAR_WAIT_LIST)){
            taggedNearListByFacilityArrays = authenticatedConnection.getPort().getNearListByFacility();
        }

        if(waitListType !=null && waitListType.equalsIgnoreCase(RECALL_WAIT_LIST)){
            taggedRecallListByFacilityArrays = authenticatedConnection.getPort().getRecallListByFacility();
        }

        if(waitListType !=null && waitListType.equalsIgnoreCase(EWL_WAIT_LIST)){
            MdwsResponseValidator.validateMdwsObject(taggedEwlByFacilityArrays);
            waitListEntries = translator.translate(taggedEwlByFacilityArrays);
        }

        if(waitListType !=null && waitListType.equalsIgnoreCase(RECALL_WAIT_LIST)){
            MdwsResponseValidator.validateMdwsObject(taggedRecallListByFacilityArrays);
            waitListEntries = translator.translate(taggedRecallListByFacilityArrays);
        }

        if(waitListType !=null && waitListType.equalsIgnoreCase(NEAR_WAIT_LIST)){
            MdwsResponseValidator.validateMdwsObject(taggedNearListByFacilityArrays);
            waitListEntries =  translator.translate(taggedNearListByFacilityArrays);
        }

        return waitListEntries;
    }

	/**
	 * Returns null
	 */
	public WaitListEntry getWaitListEntry(String waitListId, String facilityCode) {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

	/**
	 * Calls the MDWS service SchedulingSvc.makeAppointment for the given patient
	 */
	public BookAppointment bookPatientAppointment(BookAppointment bookAppointment) {
        SchedulingConnection authenticatedSite = super.getAuthenticatedConnectionWithPatientSelected(new MdwsConfigurationHelper().extractSiteCodeFromAssigningAuthority(bookAppointment.getPatientIdentifier().getAssigningAuthority()), bookAppointment.getPatientIdentifier().getUniqueId());
        String vistaDate =  DateHelper.convertDateTimeToVistaDateTimeFormat(bookAppointment.getDateTime());
        String vistaDesiredDate = removeTrailingZeros(DateHelper.convertDateTimeToVistaDateTimeFormat(bookAppointment.getDesiredDate()));
        AppointmentTO lvAppointmentTO = authenticatedSite.getPort().makeAppointment(bookAppointment.getClinicId(),
        												removeTrailingZeros(vistaDate),
                                                        bookAppointment.getPurpose(),
                                                        "",
                                                        bookAppointment.getApptLength(),
                                                        bookAppointment.getApptType(),
                                                        bookAppointment.getBookingNotes(), bookAppointment.getLab(), bookAppointment.getxRay(), bookAppointment.getEkg(), bookAppointment.getLvl(),vistaDesiredDate);
        BookAppointment bookedAppointment;
        String error = responseValidator.validateMdwsObject(lvAppointmentTO);
        if(error != null && error.length() > 0){
            bookedAppointment = new BookAppointment();
            bookedAppointment.setError(error);
            return bookedAppointment;
        }
        else{
            MdwsResponseValidator.validateMdwsObject(lvAppointmentTO);
        }
        AppointmentTimeSlotTranslator translator = new AppointmentTimeSlotTranslator();
        return translator.translate(lvAppointmentTO);
    }

	/**
	 * Calls the MDWS service SchedulingSvc.getAppointmentsBookingNotes for the given patient
	 */
	public BookedAppointments getPatientBookedAppointments(AppointmentSlotFilter appointmentSlotFilter) {
        SchedulingConnection authenticatedSite = super.getAuthenticatedConnectionWithPatientSelected(appointmentSlotFilter.getSiteCode(), appointmentSlotFilter.getPatientIdentifier().getUniqueId());
        TaggedAppointmentArray taggedAppointmentArray = authenticatedSite.getPort().getAppointmentsBookingNotes(DateHelper.convertDateTimeToVistaDateTimeFormat(appointmentSlotFilter.getStartDate()));
        MdwsResponseValidator.validateMdwsObject(taggedAppointmentArray);
        BookedAppointmentTranslator translator = new BookedAppointmentTranslator();
        return translator.translateFromTaggedAppointmentArray(taggedAppointmentArray);
    }

	/**
	 * Calls the MDWS service SchedulingSvc.cancelAppointment for the given patient
	 */
	public CancelAppointment cancelAppointmentForPatient(CancelAppointment cancelAppointmentObject) {
        SchedulingConnection authenticatedSite = super.getAuthenticatedConnectionWithPatientSelected(new MdwsConfigurationHelper().extractSiteCodeFromAssigningAuthority(cancelAppointmentObject.getPatientIdentifier().getAssigningAuthority()), cancelAppointmentObject.getPatientIdentifier().getUniqueId());
        String appointmentDate = DateHelper.convertDateTimeToVistaDateTimeFormat(cancelAppointmentObject.getAppointmentTime());
        CancelAppointmentTO cancelAppointmentTO = authenticatedSite.getPort().cancelAppointment(cancelAppointmentObject.getClinicId(),
                                                        removeTrailingZeros(appointmentDate),
                                                        cancelAppointmentObject.getCancelCode(),
                                                        cancelAppointmentObject.getCancelReason(),
                                                        cancelAppointmentObject.getRemarks());
        MdwsResponseValidator.validateMdwsObject(cancelAppointmentTO);
        CancelAppointmentTranslator translator = new CancelAppointmentTranslator();
        CancelAppointment canceledAppointment = translator.translate(cancelAppointmentTO);
        canceledAppointment.setPatientIdentifier(cancelAppointmentObject.getPatientIdentifier());
        return canceledAppointment;
    }


	/**
	 * Calls the MDWS service SchedulingSvc.removePatientFromRecallList
	 */
    /*
    public WaitListEntry removeRecallEntryForPatient(WaitListEntry waitListEntry) {
		SchedulingConnection authenticatedConnection = super.getAuthenticatedConnection(waitListEntry.getFacilityId());
        String patientRequestDate = "";
        if(NullChecker.isNotNullish(waitListEntry.getRecallDate1()))
            patientRequestDate = DateHelper.convertDateTimeToVistaDateTimeFormat(waitListEntry.getRecallDate1());
        TaggedRemoveFromRecallListArrays taggedRemoveFromRecallListArrays = authenticatedConnection.getPort().removePatientFromRecallList(waitListEntry.getPatientIdentifier().getUniqueId(), waitListEntry.getClinicId(),
                waitListEntry.getProvider(),
                removeTrailingZeros(DateHelper.convertDateTimeToVistaDateTimeFormat(waitListEntry.getRecallDate())),
                patientRequestDate);
        MdwsResponseValidator.validateMdwsObject(taggedRemoveFromRecallListArrays);
        FacilityWaitListTranslator waitListTranslator = new FacilityWaitListTranslator();
        if(waitListTranslator.isRecallEntryRemovedSuccessFully(taggedRemoveFromRecallListArrays)){
            return waitListEntry;
        }
        return null;
    }*/

	/**
	 * Calls the MDWS service SchedulingSvc.removePatientFromEwl for the given patient
	 */
	public EwlUpdateEntry updateEWLEntry(EwlUpdateEntry ewlUpdateEntry) {
        SchedulingConnection authenticatedConnection = super.getAuthenticatedConnectionWithPatientSelected(ewlUpdateEntry.getFacilityId(), ewlUpdateEntry.getPatientIdentifier().getUniqueId());
        String appointmentTime = removeTrailingZeros(DateHelper.convertDateTimeToVistaDateTimeFormat(ewlUpdateEntry.getAppointmentTime()));
        String sdwlData = appointmentTime + "^" + ewlUpdateEntry.getClinicId() + "^" + ewlUpdateEntry.getCode() + "^" +
                                ewlUpdateEntry.getFacilityId() + "^" + ewlUpdateEntry.getStopCode() + "^" + ewlUpdateEntry.getCreditCode() + "^" + ewlUpdateEntry.getFacilityId();
        TextTO textTO = authenticatedConnection.getPort().removePatientFromEwl(ewlUpdateEntry.getIen(), ewlUpdateEntry.getDispositionCode(), sdwlData);
        MdwsResponseValidator.validateMdwsObject(textTO);
        if(isSuccess(textTO)){
            return ewlUpdateEntry;
        }
        return null;
    }

	/**
	 * Calls the MDWS service SchedulingSvc.getClinicSchedulingDetailsByDateRange and SchedulingSvc.hasClinicAccess
	 */
	public AppointmentTimeSlots getClinicSchedulingDetail(AppointmentSlotFilter appointmentSlotFilter) {
        if(appointmentSlotFilter.getStartDate() == null && appointmentSlotFilter.getEndDate() == null && appointmentSlotFilter.getClinicId() == null){
            return new AppointmentTimeSlots();
        }
        SchedulingConnection authenticatedSite = super.getAuthenticatedConnection(appointmentSlotFilter.getSiteCode());
        HospitalLocationTO hospitalLocationTO = authenticatedSite.getPort().getClinicSchedulingDetailsByDateRange(appointmentSlotFilter.getClinicId(),
                DateHelper.formatDateTimeInVistaFormat(appointmentSlotFilter.getStartDate()),
                DateHelper.formatDateTimeInVistaFormat(appointmentSlotFilter.getEndDate()));
        MdwsResponseValidator.validateMdwsObject(hospitalLocationTO);
        AppointmentTimeSlotTranslator appointmentTimeSlotTranslator = new AppointmentTimeSlotTranslator();
        AppointmentTimeSlots appointmentTimeSlots = appointmentTimeSlotTranslator.translateFromHospitalLocationTO(hospitalLocationTO, appointmentSlotFilter);
        logger.debug("Verify if User has access to the clinic ID : [" + appointmentSlotFilter.getClinicId() + "]");
        BoolTO boolTO = authenticatedSite.getPort().hasClinicAccess(appointmentSlotFilter.getClinicId());
        appointmentTimeSlots.setHasUserAccessToClinic(boolTO.isTrueOrFalse());
        return appointmentTimeSlots;
    }

	/**
	 * Calls the MDWS service SchedulingSvc.getCancellationReasons
	 */
	public CancelReasons getCancelReasonList(String facilityCode) {
        logger.debug("Fetch List of Appointment Cancel Reason list for [" + facilityCode + "] facility");
        SchedulingConnection authenticatedConnection = super.getAuthenticatedConnection(facilityCode);
        TaggedCancellationReasonsArray taggedCancellationReasonArray = authenticatedConnection.getPort().getCancellationReasons();
        MdwsResponseValidator.validateMdwsObject(taggedCancellationReasonArray);
        CancelReasonTranslator translator = new CancelReasonTranslator();
        return translator.translate(taggedCancellationReasonArray);
    }

	/**
	 * Calls the MDWS service SchedulingSvc.getConsultsWithoutPatient
	 */
	public SMConsults getConsultsBySpecialties(String service, String providerId, DateFilter dateFilter, String siteCode) {
        logger.debug("Fetch Consults for [" + service+ "] specialty/service for site : " + siteCode);
        SchedulingConnection authenticatedSite = super.getAuthenticatedConnection(siteCode);
//        LVTaggedConsultStatusArray lvTaggedConsultStatusArray = authenticatedSite.getPort().getConsultStatuses();
//        MdwsResponseValidator.validateMdwsObject(lvTaggedConsultStatusArray);
        ConsultTranslator consultTranslator = new ConsultTranslator();
        String consultStatus = "5,6,8"; //consultTranslator.getCommaSeparatedStatusList(lvTaggedConsultStatusArray);
        String startDate = "";
        String endDate = "";
        if(dateFilter.getStartDate() != null)
            startDate = DateHelper.convertDateToVistaFormat(dateFilter.getStartDate());
        if(dateFilter.getEndDate() != null)
            endDate = DateHelper.convertDateToVistaFormat(dateFilter.getEndDate());
        TaggedConsultsArray taggedConsultArray = authenticatedSite.getPort().getConsultsWithoutPatient(startDate, endDate, service, consultStatus, providerId);
        MdwsResponseValidator.validateMdwsObject(taggedConsultArray);
        SMConsults smConsults = consultTranslator.translate(taggedConsultArray);
        return smConsults;
    }

	/**
	 * Calls the MDWS service SchedulingSvc.getConsultingServices
	 */
	public SMConsultServices getConsultServices(String siteCode) {
        SchedulingConnection authenticatedSite = super.getAuthenticatedConnection(siteCode);
        TaggedConsultingServicesArray taggedConsultingServiceArray = authenticatedSite.getPort().getConsultingServices();
        ConsultTranslator consultTranslator = new ConsultTranslator();
        SMConsultServices smConsultServices =  consultTranslator.translate(taggedConsultingServiceArray);
        return smConsultServices;
    }

	/**
	 * Calls the MDWS service SchedulingSvc.getConsultDetails
	 */
	public SMConsultDetail getDetailsForConsult(String consultIen, String siteCode) {
        logger.debug("Get details for Consult : ConsultIEN = [" + consultIen + "]; Facility : [" + siteCode + "]");
        SchedulingConnection authenticatedSite = super.getAuthenticatedConnection(siteCode);
        TaggedConsultDetailArray taggedConsultDetailArray = authenticatedSite.getPort().getConsultDetails(consultIen);
        MdwsResponseValidator.validateMdwsObject(taggedConsultDetailArray);
        ConsultTranslator consultTranslator = new ConsultTranslator();
        SMConsultDetail smConsultDetail = consultTranslator.translate(taggedConsultDetailArray);
        smConsultDetail.setConsultIen(consultIen);
        return smConsultDetail;
    }

	/**
	 * Calls the MDWS service SchedulingSvc.getAppointmentTypes
	 */
	public AppointmentTypes getAppointmentTypes(String siteCode) {
        SchedulingConnection authenticatedConnection = super.getAuthenticatedConnection(siteCode);
        AppointmentTypeArray appointmentTypeArray = authenticatedConnection.getPort().getAppointmentTypes(siteCode);
        MdwsResponseValidator.validateMdwsObject(appointmentTypeArray);
        AppointmentTypeTranslator appointmentTypeTranslator = new AppointmentTypeTranslator();
        return appointmentTypeTranslator.translate(appointmentTypeArray);
    }

    private static String removeTrailingZeros(String dateString){
        if(NullChecker.isNotNullish(dateString)){
            while (dateString.charAt(dateString.length()-1) == '0' || dateString.charAt(dateString.length()-1) == '.'){
                dateString = dateString.substring(0, dateString.length()-1);
            }
        }
        return dateString;
    }

    private boolean isSuccess(TextTO textTO){
        return textTO.getText().equals("success");
    }
    
    /**
	 * Calls the MDWS service SchedulingSvc.getClinicsWithSpecialties
	 */
	public SchedulingSpecialties getClinicsWithSpecialties(String siteCode) {
        logger.debug("Fetch Clinics and specialties");
        SchedulingConnection authenticatedSite = super.getAuthenticatedConnection(siteCode);
        TaggedHospitalLocationArray taggedHositalLocationArray= authenticatedSite.getPort().getClinicsWithSpecialties("");
        MdwsResponseValidator.validateMdwsObject(taggedHositalLocationArray);
        SpecialtyWithClinicTranslator specialtyWithClinicTranslator = new SpecialtyWithClinicTranslator();
        SchedulingSpecialties SchedulingSpecialties = specialtyWithClinicTranslator.translate(taggedHositalLocationArray,siteCode);
        return SchedulingSpecialties;
    }
}
