

package gov.va.med.repositories.fpds.webservice;


import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import gov.va.med.repositories.fpds.validator.ValidationError;
import gov.va.med.repositories.fpds.validator.ValidationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriInfo;

import gov.va.med.cds.client.ClinicalDataServiceInterface;
import gov.va.med.cds.client.webservice.ClinicalDataServiceSynchronousInterface;
import gov.va.med.cds.saml.SamlAssertionThreadLocal;


public class FederatingPatientRecordRestService
    extends
        BaseParentFederatedPatientRestService
{
    private Log logger = LogFactory.getLog( FederatingPatientRecordRestService.class );

    public static final String GETUPDATES_COMMAND = "getPtUpdates";
    public static final String SUBSCRIBE_COMMAND = "putPtSubscription";
    public static final String CANCEl_COMMAND = "cancelPtSubscription";
    public static final String RESET_COMMAND = "resetPtSubscriptions";
    public static final String COMMAND = "command";
    public static final String CONVERT_TO_JSON = "toJson";
    public static final String MAX = "max";
    public static final int MAX_VALUE = 10000;

    @Resource( name = "linkDomainToResponseTypeOfRPC" )
    Map<String, String> linkDomainToResponseTypeOfRPC;

	public void setLinkDomainToResponseTypeOfRPC( Map<String, String> linkDomainToResponseTypeOfRPC )
    {
        this.linkDomainToResponseTypeOfRPC = linkDomainToResponseTypeOfRPC;
    }


    @GET
    @Path( "{domain}" )
    @Produces( { "application/json", "application/xml" } )
    public String readData( @PathParam( "domain" )
    String domain, @Context
    UriInfo uriInfo )
    {
        String result = null;
        String requestId = null;
        MultivaluedMap<String, String> queryParameters = null;
        String filterId = null;
        String templateId = null;
        String max = null;

        try
        {
            queryParameters = uriInfo.getQueryParameters();

            chkQueryParams( queryParameters );

            String responseType = queryParameters.getFirst( TYPE );

            String mandatoryResponseTypeForThisDomain = linkDomainToResponseTypeOfRPC.get( domain.toUpperCase() );

            if ( mandatoryResponseTypeForThisDomain != null )
            {

                queryParameters.add( COMMAND, mandatoryResponseTypeForThisDomain );

                if ( responseType.equals( DEFAULT_RESPONSE_TYPE ) )
                {
                    queryParameters.add( CONVERT_TO_JSON, "true" );
                }
                else
                {
                    queryParameters.add( CONVERT_TO_JSON, "false" );
                }
            }
            else
            {
                queryParameters.add( COMMAND, DEFAULT_RESPONSE_TYPE );
            }

            if ( !StringUtils.hasText( responseType ) )
            {
                responseType = DEFAULT_RESPONSE_TYPE;
            }

            requestId = trimTrailingWhitespace( queryParameters.getFirst( BaseParentFederatedPatientRestService.REQUEST_ID ) );

            filterId = getFilterId( queryParameters, BaseParentFederatedPatientRestService.DEFAULT_FILTER_ID );
            templateId = getTemplateId( queryParameters, BaseParentFederatedPatientRestService.DEFAUlT_TEMPLATE_ID );

            List<ValidationError> validationErrors = requestValidator.validateRequestParameters( filterId, queryParameters );

            if ( validationErrors != null && validationErrors.size() > 0 )
            {
                throw new ValidationException( Status.BAD_REQUEST, validationErrors ); // indicates that the request being made was bad
            }

            String filterRequest = this.filterBuilder.createFilter( filterId, null, domain.toLowerCase(), queryParameters );
            //result = clinicalDataService.readClinicalData( templateId, filterRequest, filterId, requestId );
            result = clinicalDataServiceWS.readClinicalData( templateId, filterRequest, filterId, requestId );

        }
        catch ( Exception e )
        {
            String patientId = getPatientId( queryParameters );
            result = handleException( e, requestId, domain, templateId, patientId, queryParameters );
        }
        return result;
    }


    private void chkQueryParams( MultivaluedMap<String, String> queryParameters )
    {
        String max;
        max = queryParameters.getFirst( MAX );
        Integer maxInt = null;
        if ( StringUtils.hasText( max ) )
        {
            maxInt = new Integer( max );
            if ( maxInt > MAX_VALUE )
            {
                maxInt = MAX_VALUE;
                queryParameters.putSingle( MAX, maxInt.toString() );
            }
        }
    }


    @POST
    @Path( "subscribe" )
    @Produces( { "application/json", "application/xml" } )
    public String subscribePatient( @Context
    UriInfo uriInfo )
    {
        String result = null;
        String requestId = null;
        String templateId = null;
        MultivaluedMap<String, String> queryParameters = null;

        try
        {
            queryParameters = uriInfo.getQueryParameters();
            queryParameters.add( "command", SUBSCRIBE_COMMAND );

            requestId = trimTrailingWhitespace( queryParameters.getFirst( BaseParentFederatedPatientRestService.REQUEST_ID ) );
            templateId = getTemplateId( queryParameters, BaseParentFederatedPatientRestService.DEFAUlT_TEMPLATE_ID );

            result = processPubSub( SUBSCRIBE_COMMAND, templateId, requestId, null, queryParameters );

        }
        catch ( Exception e )
        {
            String patientId = getPatientId( queryParameters );
            result = handleException( e, requestId, "GenericObservation", templateId, patientId, queryParameters );
        }

        return result;
    }


    @GET
    @Path( "patientdata/{siteId}" )
    @Produces( { "application/json", "application/xml" } )
    public String getUpdates( @PathParam( "siteId" )
    String siteId, @Context
    UriInfo uriInfo )
    {
        String result = null;
        String requestId = null;
        String templateId = null;

        String patientId = "-999-" + siteId + "-USVHA";
        MultivaluedMap<String, String> queryParameters = null;

        try
        {
            queryParameters = uriInfo.getQueryParameters();
            queryParameters.add( "command", GETUPDATES_COMMAND );
            queryParameters.add( "resolvedIdentifier", patientId );

            requestId = trimTrailingWhitespace( queryParameters.getFirst( REQUEST_ID ) );

            templateId = getTemplateId( queryParameters, BaseParentFederatedPatientRestService.DEFAUlT_TEMPLATE_ID );

            result = processPubSub( GETUPDATES_COMMAND, templateId, requestId, null, queryParameters );

        }
        catch ( Exception e )
        {
            result = handleException( e, requestId, "GenericObservation", templateId, patientId, queryParameters );
        }

        return result;
    }


    @GET
    @Path( "reset/{siteId}" )
    @Produces( { "application/json", "application/xml" } )
    public String resetSubscriptions( @PathParam( "siteId" )
    String siteId, @Context
    UriInfo uriInfo )
    {
        String result = null;
        String requestId = null;
        String templateId = null;

        String patientId = "-999-" + siteId + "-USVHA";
        MultivaluedMap<String, String> queryParameters = null;

        try
        {
            queryParameters = uriInfo.getQueryParameters();
            queryParameters.add( "command", RESET_COMMAND );
            queryParameters.add( "resolvedIdentifier", patientId );

            requestId = trimTrailingWhitespace( queryParameters.getFirst( REQUEST_ID ) );

            templateId = getTemplateId( queryParameters, BaseParentFederatedPatientRestService.DEFAUlT_TEMPLATE_ID );

            result = processPubSub( RESET_COMMAND, templateId, requestId, null, queryParameters );

        }
        catch ( Exception e )
        {
            result = handleException( e, requestId, "GenericObservation", templateId, patientId, queryParameters );
        }

        return result;
    }


    @POST
    @Path( "cancel" )
    @Produces( { "application/json", "application/xml" } )
    public String cancelSubscription( @Context
    UriInfo uriInfo )
    {
        String result = null;
        String requestId = null;
        String templateId = null;
        MultivaluedMap<String, String> queryParameters = null;

        try
        {
            queryParameters = uriInfo.getQueryParameters();
            queryParameters.add( "command", CANCEl_COMMAND );

            requestId = trimTrailingWhitespace( queryParameters.getFirst( BaseParentFederatedPatientRestService.REQUEST_ID ) );
            templateId = getTemplateId( queryParameters, BaseParentFederatedPatientRestService.DEFAUlT_TEMPLATE_ID );

            result = processPubSub( CANCEl_COMMAND, templateId, requestId, null, queryParameters );

        }
        catch ( Exception e )
        {

            String patientId = getPatientId( queryParameters );

            result = handleException( e, requestId, "GenericObservation", templateId, patientId, queryParameters );
        }

        return result;
    }


    private String processPubSub( String command, String templateId, String requestId, String patientId,
                    MultivaluedMap<String, String> queryParameters )
    {
        String result = null;

        try
        {

            List<ValidationError> validationErrors = requestValidator.validateRequestParameters( command, queryParameters );

            if ( validationErrors != null && validationErrors.size() > 0 )
            {
                throw new ValidationException( Status.BAD_REQUEST, validationErrors ); // indicates that the request being made was bad
            }

            String filterId = getFilterId( queryParameters, BaseParentFederatedPatientRestService.DEFAULT_FILTER_ID );

            String filterRequest = this.filterBuilder.createFilter( filterId, patientId, "GenericObservation", queryParameters );
            result = clinicalDataServiceWS.readClinicalData( templateId, filterRequest, filterId, requestId );

        }
        catch ( Exception e )
        {
            result = handleException( e, requestId, "GenericObservation", templateId, patientId, queryParameters );
        }

        return result;
    }
 
}
