<commit_before>package es.fhir.rest.core.resources;

import java.time.LocalDate;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.Appointment;
import org.hl7.fhir.r4.model.Schedule;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;

import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.rest.annotation.IncludeParam;
import ca.uhn.fhir.rest.annotation.OptionalParam;
import ca.uhn.fhir.rest.annotation.RequiredParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.ReferenceOrListParam;
import ca.uhn.fhir.rest.param.ReferenceParam;
import ca.uhn.fhir.rest.param.TokenParam;
import ch.elexis.core.findings.codes.CodingSystem;
import ch.elexis.core.findings.util.TerminUtil;
import ch.elexis.core.findings.util.fhir.IFhirTransformer;
import ch.elexis.core.findings.util.fhir.IFhirTransformerRegistry;
import ch.elexis.core.model.IAppointment;
import ch.elexis.core.model.ModelPackage;
import ch.elexis.core.services.IAppointmentService;
import ch.elexis.core.services.IModelService;
import ch.elexis.core.services.IQuery;
import ch.elexis.core.services.IQuery.COMPARATOR;
import ch.elexis.core.time.DateConverter;
import es.fhir.rest.core.resources.util.QueryUtil;

@Component(service = IFhirResourceProvider.class)
public class AppointmentResourceProvider
		extends AbstractFhirCrudResourceProvider<Appointment, IAppointment> {
	
	@Reference(target = "(" + IModelService.SERVICEMODELNAME + "=ch.elexis.core.model)")
	private IModelService coreModelService;
	
	@Reference
	private IAppointmentService appointmentService;
	
	@Reference
	private IFhirTransformerRegistry transformerRegistry;
	
	public AppointmentResourceProvider(){
		super(IAppointment.class);
	}
	
	@Override
	public Class<? extends IBaseResource> getResourceType(){
		return Appointment.class;
	}
	
	@Activate
	public void activate(){
		super.setCoreModelService(coreModelService);
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public IFhirTransformer<Appointment, IAppointment> getTransformer(){
		return (IFhirTransformer<Appointment, IAppointment>) transformerRegistry
			.getTransformerFor(Appointment.class, IAppointment.class);
	}
	
	@Search
	public List<Appointment> search(
		@OptionalParam(name = Appointment.SP_DATE) DateRangeParam dateParam,
		@OptionalParam(name = Appointment.SP_SERVICE_CATEGORY) TokenParam serviceCategoryParam){
		
		// TODO default limit, offset, paging
		
		IQuery<IAppointment> query = coreModelService.getQuery(IAppointment.class);
		// TODO configurable
		query.and(ModelPackage.Literals.IAPPOINTMENT__TYPE, COMPARATOR.NOT_EQUALS, "gesperrt");
		
		if (serviceCategoryParam != null && StringUtils.equalsIgnoreCase(
			CodingSystem.ELEXIS_AGENDA_AREA_ID.getSystem(), serviceCategoryParam.getSystem())) {
			query.and(ModelPackage.Literals.IAPPOINTMENT__SCHEDULE, COMPARATOR.EQUALS, serviceCategoryParam.getValue());
		}
		
		if(dateParam != null) {
			DateConverter dateConverter = new DateConverter();
			if (dateParam.getLowerBound() != null) {
				LocalDate dayParam =
					dateConverter.convertToLocalDate(dateParam.getLowerBound().getValue());
				COMPARATOR compare =
					QueryUtil.prefixParamToToQueryParam(dateParam.getLowerBound().getPrefix());
				query.and("tag", compare, dayParam);
			}
			if (dateParam.getUpperBound() != null) {
				LocalDate dayParam2 =
					dateConverter.convertToLocalDate(dateParam.getUpperBound().getValue());
				COMPARATOR compare2 =
					QueryUtil.prefixParamToToQueryParam(dateParam.getUpperBound().getPrefix());
				query.and("tag", compare2, dayParam2);
			}
		}
	
		return super.handleExecute(query);
	}
	
//	/**
//	 * Find all appointments within a certain date range; optionally allocate them to a set of areas
//	 * 
//	 * @param dateParam
//	 * @param actors
//	 * @return
//	 */
//	@Search
//	public List<Appointment> findAppointmentsByDateAndOptionallyArea(
//		@RequiredParam(name = Appointment.SP_DATE) DateRangeParam dateParam,
//		@Description(shortDefinition = "Only supports Schedule/identifier")
//		@OptionalParam(name = Appointment.SP_ACTOR) ReferenceOrListParam actors,
//		@IncludeParam(allow = {
//			"Appointment:patient"<commit_msg>[23530] AppointmentProvider @Search add SP_PATIENT<commit_after>package es.fhir.rest.core.resources;

import java.time.LocalDate;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.Appointment;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;

import ca.uhn.fhir.rest.annotation.OptionalParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.param.TokenParam;
import ch.elexis.core.findings.codes.CodingSystem;
import ch.elexis.core.findings.util.fhir.IFhirTransformer;
import ch.elexis.core.findings.util.fhir.IFhirTransformerRegistry;
import ch.elexis.core.model.IAppointment;
import ch.elexis.core.model.ModelPackage;
import ch.elexis.core.services.IAppointmentService;
import ch.elexis.core.services.IModelService;
import ch.elexis.core.services.IQuery;
import ch.elexis.core.services.IQuery.COMPARATOR;
import ch.elexis.core.time.DateConverter;
import es.fhir.rest.core.resources.util.QueryUtil;

@Component(service = IFhirResourceProvider.class)
public class AppointmentResourceProvider
		extends AbstractFhirCrudResourceProvider<Appointment, IAppointment> {
	
	@Reference(target = "(" + IModelService.SERVICEMODELNAME + "=ch.elexis.core.model)")
	private IModelService coreModelService;
	
	@Reference
	private IAppointmentService appointmentService;
	
	@Reference
	private IFhirTransformerRegistry transformerRegistry;
	
	public AppointmentResourceProvider(){
		super(IAppointment.class);
	}
	
	@Override
	public Class<? extends IBaseResource> getResourceType(){
		return Appointment.class;
	}
	
	@Activate
	public void activate(){
		super.setCoreModelService(coreModelService);
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public IFhirTransformer<Appointment, IAppointment> getTransformer(){
		return (IFhirTransformer<Appointment, IAppointment>) transformerRegistry
			.getTransformerFor(Appointment.class, IAppointment.class);
	}
	
	@Search
	public List<Appointment> search(
		@OptionalParam(name = Appointment.SP_DATE) DateRangeParam dateParam,
		@OptionalParam(name = Appointment.SP_SERVICE_CATEGORY) TokenParam serviceCategoryParam,
		@OptionalParam(name = Appointment.SP_PATIENT) StringParam patientParam){
		
		// TODO default limit, offset, paging
		
		IQuery<IAppointment> query = coreModelService.getQuery(IAppointment.class);
		// TODO configurable
		query.and(ModelPackage.Literals.IAPPOINTMENT__TYPE, COMPARATOR.NOT_EQUALS, "gesperrt");
		
		if (serviceCategoryParam != null && StringUtils.equalsIgnoreCase(
			CodingSystem.ELEXIS_AGENDA_AREA_ID.getSystem(), serviceCategoryParam.getSystem())) {
			query.and(ModelPackage.Literals.IAPPOINTMENT__SCHEDULE, COMPARATOR.EQUALS,
				serviceCategoryParam.getValue());
		}
		
		if (dateParam != null) {
			DateConverter dateConverter = new DateConverter();
			if (dateParam.getLowerBound() != null) {
				LocalDate dayParam =
					dateConverter.convertToLocalDate(dateParam.getLowerBound().getValue());
				COMPARATOR compare =
					QueryUtil.prefixParamToToQueryParam(dateParam.getLowerBound().getPrefix());
				query.and("tag", compare, dayParam);
			}
			if (dateParam.getUpperBound() != null) {
				LocalDate dayParam2 =
					dateConverter.convertToLocalDate(dateParam.getUpperBound().getValue());
				COMPARATOR compare2 =
					QueryUtil.prefixParamToToQueryParam(dateParam.getUpperBound().getPrefix());
				query.and("tag", compare2, dayParam2);
			}
		}
		
		if (patientParam != null) {
			String patientId = patientParam.getValue();
			query.and(ModelPackage.Literals.IAPPOINTMENT__SUBJECT_OR_PATIENT, COMPARATOR.EQUALS,
				patientId);
		}
		
		return super.handleExecute(query);
	}
	
//	/**
//	 * Find all appointments within a certain date range; optionally allocate them to a set of areas
//	 * 
//	 * @param dateParam
//	 * @param actors
//	 * @return
//	 */
//	@Search
//	public List<Appointment> findAppointmentsByDateAndOptionallyArea(
//		@RequiredParam(name = Appointment.SP_DATE) DateRangeParam dateParam,
//		@Description(shortDefinition = "Only supports Schedule/identifier")
//		@OptionalParam(name = Appointment.SP_ACTOR) ReferenceOrListParam actors,
//		@IncludeParam(allow = {
//			"Appointment:patient"
{'fraction_non_alphanumeric': 0.1127836192584394, 'fraction_numerical': 0.002545655783065855, 'mean_word_length': 5.500719424460431, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7396220', 'n_tokens_mistral': 3094, 'n_tokens_neox': 2899, 'n_words': 451}