/********************************************************************
 * Copyright © 2004 EDS. All rights reserved
 ********************************************************************/
//Package
package gov.va.med.esr.messaging.builder.message;

//Java Classes

//Framework Classes

import java.util.ArrayList;
import java.util.List;

import gov.va.med.fw.hl7.segment.OBX;
import gov.va.med.fw.hl7.builder.HL7MetaData;
import gov.va.med.fw.util.builder.BuilderException;

//ESR Classes
import gov.va.med.esr.common.infra.TriState;
import gov.va.med.esr.common.model.lookup.NTRVerificationMethod;
import gov.va.med.esr.common.model.ee.NoseThroatRadium;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.service.PersonHelperService;

/**
 * Class to build the OBX segment.
 * 
 * @author Alex Yoon
 * @version 1.0
 */
public class OBXBuilder extends AbstractSegmentBuilder {
    /**
    * An instance of serialVersionUID 
    */
   private static final long serialVersionUID = 4591791636261927308L;

   private PersonHelperService helperService;
    
    private static final String VALUE_TYPE = "CE";
    private static final String OBSERVATION_ID_NTR = "VISTA~28.11";
    private static final String OBSERVATION_ID_SENSITIVITY = "38.1~SECURITY LOG";
    
    //From table VA0053.
    private static final String TREATMENT_CODING_SYSTEM = "VA0053";
    private static final String RECEIVING_TREATMENT_YES_CODE = "1";
    private static final String RECEIVING_TREATMENT_YES_DESC = "RECEIVED NTR TRMT";
    private static final String RECEIVING_TREATMENT_NO_CODE = "5";
    private static final String RECEIVING_TREATMENT_NO_DESC = "NO NTR TRMT";
    private static final String RECEIVING_TREATMENT_UNKNOWN_CODE = "9";
    private static final String RECEIVING_TREATMENT_UNKNOWN_DESC = "NTR TRMT UNKNOWN";
    private static final String AVIATOR_YES_CODE ="2";
    private static final String AVIATOR_YES_DESC = "AVIATOR PRE 1955";
    private static final String AVIATOR_NO_CODE ="6";
    private static final String AVIATOR_NO_DESC = "NOT AVIATOR PRE 1955";
    private static final String SUB_TRAINEE_YES_CODE = "3";
    private static final String SUB_TRAINEE_YES_DESC = "SUB TRAINEE PRE 1965";
    private static final String SUB_TRAINEE_NO_CODE = "7";
    private static final String SUB_TRAINEE_NO_DESC = "NOT SUB TRAINEE PRE 1965";
    private static final String CANCER_YES_CODE = "4";
    private static final String CANCER_YES_DESC = "DX WITH HEAD NECK CANCER";
    private static final String CANCER_NO_CODE = "8";
    private static final String CANCER_NO_DESC = "NOT DX WITH HEAD NECK CANCER";
    
    private static final String OBSERVATION_RESULT_STATUS_NTR = "F";
    private static final String OBSERVATION_RESULT_STATUS_SENSITIVITY = "R";
    
    private static final String RESPONSIBLE_OBSERVER_COMPONENT = "~~~~~~~~~~~~~&";
    private static final String OBSERVATION_METHOD_CODING_SYSTEM = "VA0052";
    
    private static final String OBSERVATION_VALUE_SENSITIVITY_YES = "Y~YES~HL70136";
    private static final String REPONSIBLE_OBSERVER_SENSITIVITY = "AAC";
    
    /**
     * Default contructor.
     */
    public OBXBuilder() {
        super();
    }
    
    public PersonHelperService getHelperService()
    {
        return this.helperService;
    }

    public void setHelperService(PersonHelperService helperService)
    {
        this.helperService = helperService;
    }
    
    /**
     * Method to build the OBX segment.
     * 
     * @param metaData
     *           The parameter object used to build the a OBX segment.
     * @return The OBX segment.
     */
    public Object build(HL7MetaData metaData ) throws BuilderException {
        if((metaData == null) || 
           (metaData.getEntity() == null) ||
           !(metaData.getEntity() instanceof Person)) {
                throw new BuilderException("Invalid input parameter to build a segment");
        }
        
        List segments = new ArrayList();
        Person person = (Person)metaData.getEntity();
        
        try {
        	Boolean sensitiveRecord = person.getSensitiveRecord();
        	
        	//Create OBX only if there is data. No need to create an empty OBX since it is optional.
        	
            //If sensitivity flag is true, then build OBX with sensitivity-level.
        	if (sensitiveRecord != null && (sensitiveRecord.booleanValue()))
        	{
        	    segments.add(setSensitivity(sensitiveRecord));
        	}
            
            //If ntr is not null, then build OBX with Nose Throat Radium.
            //Get NoseThroatRadium object
            NoseThroatRadium ntr = 
                (NoseThroatRadium)this.helperService.getClinicalDetermination(NoseThroatRadium.class, person);
            if (ntr != null) {
                segments.add(setNTR(ntr));
            }
            
        }
        catch (Exception e) {
            throw new BuilderException( "Failed to build OBX Segment due to an exception ", e);
        }
        
        return segments;
    }
    
    /**
     * Method that builds and sets OBX segment for Sensitivity Level .
     * 
     * @param sensitivity
     *           The Boolean Object.
     * @return OBX segment.
     */
    private OBX setSensitivity(Boolean sensitivity) {
        OBX segment = new OBX();
        segment.setValueType(VALUE_TYPE);
        segment.setObservationID(OBSERVATION_ID_SENSITIVITY);
        segment.setObservationValue(OBSERVATION_VALUE_SENSITIVITY_YES);
        segment.setObservationResultStatus(OBSERVATION_RESULT_STATUS_SENSITIVITY);
        segment.setResponsibleObserver(REPONSIBLE_OBSERVER_SENSITIVITY);
        
        
        return segment;
    }
    
    /**
     * Method that builds and sets OBX segment for Nose Throat Radium.
     * 
     * @param ntr
     *           The NoseThroatRadium Object.
     * @return OBX segment.
     */
    private OBX setNTR(NoseThroatRadium ntr) {
        OBX segment = new OBX();
        segment.setValueType(VALUE_TYPE);
        segment.setObservationID(OBSERVATION_ID_NTR);
        segment.setObservationValue(buildObservationValue(ntr));
        segment.setObservationResultStatus(OBSERVATION_RESULT_STATUS_NTR);
        //ESR_CodeCR5659:MST and NTR did not upload on Vista due to not sending the time (just the date)
        segment.setObservationDate(DateFormatter.formatDate(ntr.getVerificationDate(),DateFormatter.DATETIME_ZONE_FORMAT));
        segment.setProducerID((ntr.getVerificationFacility() != null) ? ntr.getVerificationFacility().getStationNumber() : null);
        segment.setResponsibleObserver(buildResponsibleObserver(ntr));
        segment.setObservationMethod(buildObservationMethod(ntr));
        
        return segment;
    }
    
    /**
     * Method that builds observation value in Coded Element format.
     * Example: 1~Received NTR Trmt~VA0053|6~Not Aviator Pre 1955~VA0053|7~Not Sub Trainee pre1965~VA0053|4~Dx With Head Neck Cancer~VA0053
     * @param ntr
     *           The NoseThroatRadium Object.
     * @return observation value.
     */
    private String buildObservationValue(NoseThroatRadium ntr) {
        String observationValue = "";
        Boolean flag;
        
        //Build Receiving Treatment.
        TriState receivingTreatment = ntr.getReceivingTreatment();
        if (receivingTreatment != null) {
            if (receivingTreatment.equals(TriState.TRUE)) {
                observationValue += ElementFormatter.formatCodedElement
                	(RECEIVING_TREATMENT_YES_CODE, RECEIVING_TREATMENT_YES_DESC, TREATMENT_CODING_SYSTEM);
            }
            else if (receivingTreatment.equals(TriState.FALSE)) {
                observationValue += ElementFormatter.formatCodedElement
                	(RECEIVING_TREATMENT_NO_CODE, RECEIVING_TREATMENT_NO_DESC, TREATMENT_CODING_SYSTEM);
            }
            else {
                observationValue += ElementFormatter.formatCodedElement
            		(RECEIVING_TREATMENT_UNKNOWN_CODE, RECEIVING_TREATMENT_UNKNOWN_DESC, TREATMENT_CODING_SYSTEM);
            }
        }
        
        //Build Aviator Before 1955.
        flag = ntr.getFromAviatorServiceBefore1955();
        if (flag != null) {
            observationValue += (observationValue.length() > 0) ? "|" : "";
            
            if (flag.booleanValue()) {
                observationValue += ElementFormatter.formatCodedElement
                	(AVIATOR_YES_CODE, AVIATOR_YES_DESC, TREATMENT_CODING_SYSTEM);
            }
            else {
                observationValue += ElementFormatter.formatCodedElement
                	(AVIATOR_NO_CODE, AVIATOR_NO_DESC, TREATMENT_CODING_SYSTEM);
            }
        }
        
        //Build Submariner Before 1965.
        flag = ntr.getFromSubmarinerServiceBefore1965();
        if (flag != null) {
            observationValue += (observationValue.length() > 0) ? "|" : "";
            
            if (flag.booleanValue()) {
                observationValue += ElementFormatter.formatCodedElement
                	(SUB_TRAINEE_YES_CODE, SUB_TRAINEE_YES_DESC, TREATMENT_CODING_SYSTEM);
            }
            else {
                observationValue += ElementFormatter.formatCodedElement
                	(SUB_TRAINEE_NO_CODE, SUB_TRAINEE_NO_DESC, TREATMENT_CODING_SYSTEM);
            }
        }
        
        //Build Diagnosed With Cancer.
        flag = ntr.getDiagnosedWithCancer();
        if (flag != null) {
            observationValue += (observationValue.length() > 0) ? "|" : "";
            
            if (flag.booleanValue()) {
                observationValue += ElementFormatter.formatCodedElement
                	(CANCER_YES_CODE, CANCER_YES_DESC, TREATMENT_CODING_SYSTEM);
            }
            else {
                observationValue += ElementFormatter.formatCodedElement
                	(CANCER_NO_CODE, CANCER_NO_DESC, TREATMENT_CODING_SYSTEM);
            }
        }
        
        return observationValue;
    }
    
    /**
     * Method that builds reponsible observer.
     * Example: ~~~~~~~~~~~~~&500
     * @param ntr
     *           The NoseThroatRadium Object.
     * @return reponsible observer.
     */
    private String buildResponsibleObserver(NoseThroatRadium ntr) {
        String responsibleObserver = null;
        
        if ((ntr.getDeterminationFacility() != null) 
                && (ntr.getDeterminationFacility().getStationNumber() != null)
                && (ntr.getDeterminationFacility().getStationNumber() != "")) {
            responsibleObserver = RESPONSIBLE_OBSERVER_COMPONENT + ntr.getDeterminationFacility().getStationNumber();
        }
        
        return responsibleObserver;
    }
    
    /**
     * Method that builds observation method.
     *
     * @param ntr
     *           The NoseThroatRadium Object.
     * @return observation method.
     */
    private String buildObservationMethod(NoseThroatRadium ntr) {
        String observationMethod = null;
        
        NTRVerificationMethod method = ntr.getVerificationMethod();
        if ((method != null)) {
            observationMethod = ElementFormatter.formatCodedElement
            	(method.getCode(), method.getDescription(), OBSERVATION_METHOD_CODING_SYSTEM);
        }
        
        return observationMethod;
    }
}