package gov.va.med.esr.common.builder.comms;

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

import org.apache.commons.lang.StringUtils;

import gov.va.med.esr.common.model.person.Association;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.model.party.Address;
import gov.va.med.esr.common.model.person.Name;
import gov.va.med.esr.common.util.LetterFormatHelper;
import gov.va.med.esr.common.model.comms.CommsTemplate;
import gov.va.med.esr.common.model.comms.CommsLogEntry;
import gov.va.med.esr.common.model.lookup.ComLetterTemplateType;

/**
 * The CmsRemoteFormatter formats letters targeted for CMS. It overrides
 * the format method and only includes Form Data Elements pertinent to CMS letters.  
 * 
 * @author DNS   ruizc
 *
 */
public class CmsRemoteFormatter extends AbstractLetterFormatter {

	private static IFormatter instance = new CmsRemoteFormatter();	
	
	public static IFormatter getInstance() {
		return instance;
	}
	
	private CmsRemoteFormatter() {
		
	}
	
	@Override
	public List format(Person person, GenerateValues inputValues) {
		List data = new ArrayList();

		// add vet data
		data.add(buildFormDataElementsForCms(person, inputValues.getOrigTemplate(),
				(GeneralTransmission) inputValues.getTransmission(),
				inputValues, null));
		// IVM Final Letters had no POA requirement
		return data;
	}	
	
	protected String buildFormDataElementsForCms(Person person, CommsTemplate template,
			GeneralTransmission transmission, GenerateValues inputValues, Association poa) {
		StringBuffer dataElements = new StringBuffer();
		// Common Data Elements specific to handling elements for CMS
		buildHeader(dataElements, template, inputValues, poa);
		buildDataElementsA(dataElements, transmission, inputValues);
		buildDataElementsBForIvm(dataElements, transmission, inputValues, poa);
		buildDataElementsC(dataElements, transmission, inputValues);
		buildDataElementsD(dataElements, transmission, inputValues);
		return dataElements.toString();
	}
	
	private void buildHeader(StringBuffer dataElements,
			CommsTemplate template, GenerateValues inputValues, Association poa) {
		String formNumber = template.getCommsTemplateFormNumber();
		String formName = template.getCommsTemplateName();		
		// Letter Number	Beginning – of –New – Letter	10 (F)	Required	LETTER=742-400
		// Letter Name	Letter Name		Required	NAME=Copay Exempt(Priority Group 5)
		// Version	Version	10 (V)	Required	VER=00001
 
		dataElements.append("*LETTER=").append(LetterFormatHelper.toAACFormNumber(formNumber)).
		append(FIELD_DELIMITER).append("*NAME=").append(formName).
		append(FIELD_DELIMITER).append(VERSION_HEADER).
		append(LetterFormatHelper.toAACVerNumber(VERSION)).append(FIELD_DELIMITER);
		
		// COMPASSION
		// Barcode ID	Barcode ID	21 (F)	Required	BID=388609723212334254345
		if (this.isCompassionLetter(formNumber)) {
			dataElements.append("*BID=").append(getBarcode(inputValues)).
			append(FIELD_DELIMITER);
		}
	}	

	
	@Override
	protected void buildDataElementsA(StringBuffer dataElements,
			GeneralTransmission transmission, GenerateValues inputValues) {

		String form = transmission.getFormNumber();		
		if (form != null) {
			CommsLogEntry entry = inputValues.getCommsLog();
			String ivmCaseClosureDate = LetterFormatHelper.toAACDate(entry.getIvmCaseClosureDate());
			String ivmCaseNumber = LetterFormatHelper.getString(entry.getIvmCaseNumber());
			if (this.isIVMFinalLetter(form)) {
				// A01	IVM Case Number	14	Required	2010IVM0000001
				// A02	IVM Case Closure Date	8	Required	06301999
				dataElements.append("* A01=").append(ivmCaseNumber)
				.append(FIELD_DELIMITER).append("* A02=").append(ivmCaseClosureDate).append(FIELD_DELIMITER);					
			}
			else if (this.isCompassionLetter(form)) {
				// Compassion
				// A01	Veteran Person Identifier (VPID)	17	Required	1234567890V123456
				// A02	IVM Case Closure Date	8	Optional	06301999
				dataElements.append("* A01=").append(transmission.getVeteranPersonIdentifier())
				.append(FIELD_DELIMITER).append("* A02=").append(ivmCaseClosureDate).append(FIELD_DELIMITER);					
			}
		}
	}

	protected void buildDataElementsBForIvm(StringBuffer dataElements,
			GeneralTransmission transmission, GenerateValues inputValues, Association poa) {
		String form = transmission.getFormNumber();		
		if (form != null) {
			if (this.isIVMFinalLetter(form) || this.isCompassionLetter(form)) {
				CommsLogEntry entry = inputValues.getCommsLog();
				String date = LetterFormatHelper.toAACDate(new Date());
				String commId = entry.getCommsLogIdString();
				// B01	File Creation Date 	8	Required	06301999
				// B02	Communication Id	20 (V)	Required	COM_MAILING_ID
				dataElements.append("* B01=").append(date).append(FIELD_DELIMITER).
				append("* B02=").append(LetterFormatHelper.getString(commId)).append(FIELD_DELIMITER);					
			}
		}
	}
	
	/** limits to capped size */
	private String truncateCountryName(String countryName) {
		if(countryName == null)
			return EMPTY_STRING;
		
		if(countryName.length() > 50)
			countryName = countryName.substring(0, 50);
		return countryName;
	}

	@Override
	protected void buildDataElementsC(StringBuffer dataElements,
			GeneralTransmission transmission, GenerateValues inputValues) {
		String form = transmission.getFormNumber();		
		if (form != null) {
			if (this.isIVMFinalLetter(form)) {
				// C01	Client -Prefix	10 (V)	Required	Mr
				// C02	Client - First Name	30 (V)	Required	JAMES
				// C03	Client Middle Name or Initial	30 (V)	Optional	LEE
				// C04	Client - Last Name	30 (V)	Optional	BEASLEY			
				// C05	Client - Suffix	30 (V)	Optional	JR
				Name legalName = transmission.getVeteran().getLegalName();
				String middleName = legalName != null ? legalName.getMiddleName() : null;
				dataElements.append("* C01=").append(transmission.getVeteranTitle()).
				append(FIELD_DELIMITER).append("* C02=").append(transmission.getVeteranFirstName()).
				append(FIELD_DELIMITER).append("* C03=").append(LetterFormatHelper.getString(middleName)).
				append(FIELD_DELIMITER).append("* C04=").append(transmission.getVeteranLastName()).
				append(FIELD_DELIMITER).append("* C05=").append(transmission.getVeteranSuffix()).				
				append(FIELD_DELIMITER);						
			}
			else if (this.isCompassionLetter(form)) {
				// C01	Primary Next of Kin Name - Prefix	10 (V)	Required	Mr
				// C02	Primary Next of Kin - First Name	30 (V)	Optional	JAMES
				// C03	Primary Next of Kin - Middle Name or Initial	30 (V)	Required	LEE
				// C04	Primary Next of Kin Last Name	30 (V)	Optional	BEASLEY
				// C05	Primary Next of Kin Suffix	30 (V)	Optional	JR
				Name nokName = transmission.getPrimaryNextOfKinName();
				String nokPrefix = (nokName != null) ? nokName.getPrefix() : null;
				String nokFirstName = (nokName != null) ? nokName.getGivenName() : null;
				String nokMiddleName = (nokName != null) ? nokName.getMiddleName() : null;
				String nokLastName = (nokName != null) ? nokName.getFamilyName() : null;
				String nokSuffix = (nokName != null) ? nokName.getSuffix() : null;				
				
				dataElements.append("* C01=").append(LetterFormatHelper.getString(nokPrefix)).
				append(FIELD_DELIMITER).append("* C02=").append(LetterFormatHelper.getString(nokFirstName)).
				append(FIELD_DELIMITER).append("* C03=").append(LetterFormatHelper.getString(nokMiddleName)).
				append(FIELD_DELIMITER).append("* C04=").append(LetterFormatHelper.getString(nokLastName)).
				append(FIELD_DELIMITER).append("* C05=").append(LetterFormatHelper.getString(nokSuffix)).				
				append(FIELD_DELIMITER);				 
			}
		}
	}

	@Override
	protected void buildDataElementsD(StringBuffer dataElements,
			GeneralTransmission transmission, GenerateValues inputValues) {
			
		Address address = transmission.getMailingAdress();
		String addressLine1 = transmission.getVeteranAddressLine1();
		String combinedAddressLine2 = this.getMailingAddressLine2(address);
		String combinedAddressLine3 = this.getMailingAddressLine3(address);		
		String city = transmission.getVeteranCity();
		String state = transmission.getVeteranState();
		String zip = this.getMailingAddressZip(address);
		String postal = this.getMailingAddressPostal(address);		
		String province = this.getMailingAddressProvince(address);
		String county = this.getMailingAddressCounty(address);
		String country = transmission.getVeteranCountryName();
		// D01	Client Address Line 1	35 (V)	Required	3602 SNOWBIBRD LN
		// D02	Client -Address Line 2	35 (V)	Optional	PO BOX 23
		// D03	Client -Address Line 3	35 (V)	Optional	
		// D04	Client-City	15 (V)	Required	CLIFTON PARK
		// D05	Client –State for domestic address	2 (F)	Required, if USA	NY
		// D06	Client –Zip Code for domestic address 10 (V)	Required, if USA	12065-1234
		// D07	Postal Code for Foreign Address		Required, if outside of USA	8E423X
		// D08	Province for Foreign Address		Required, if outside of USA	Quebec
		// D09	Client –County	30 (V)	Optional	SARATOGA
		// D10	Client- Country	50(V)	Required, if outside of USA	United States 		
		dataElements.append("* D01=").append(LetterFormatHelper.getString(addressLine1).toUpperCase()).append(FIELD_DELIMITER).
		append("* D02=").append(LetterFormatHelper.getString(combinedAddressLine2).toUpperCase()).append(FIELD_DELIMITER).
		append("* D03=").append(LetterFormatHelper.getString(combinedAddressLine3).toUpperCase()).append(FIELD_DELIMITER).		
		append("* D04=").append(LetterFormatHelper.getString(city).toUpperCase()).append(FIELD_DELIMITER).
		append("* D05=").append(LetterFormatHelper.getString(state).toUpperCase()).append(FIELD_DELIMITER).
		append("* D06=").append(LetterFormatHelper.getString(zip).toUpperCase()).append(FIELD_DELIMITER).
		append("* D07=").append(LetterFormatHelper.getString(postal).toUpperCase()).append(FIELD_DELIMITER).
		append("* D08=").append(LetterFormatHelper.getString(province).toUpperCase()).append(FIELD_DELIMITER).		
		append("* D09=").append(LetterFormatHelper.getString(county).toUpperCase()).append(FIELD_DELIMITER).
		append("* D10=").append(truncateCountryName(LetterFormatHelper.getString(country).toUpperCase())).append(FIELD_DELIMITER);		
	}

	private String getMailingAddressZip(Address address) {
		String val = null;

		if(address.isUSAddress()) {
			if(StringUtils.isNotBlank(address.getZipCode())) {
				if(StringUtils.isNotBlank(address.getZipPlus4()))
					val = address.getZipCode() + "-" + address.getZipPlus4();
				else
					val = address.getZipCode();
			}
		} 

		return val;
	}
	private String getMailingAddressPostal(Address address) {
		return !address.isUSAddress() ? address.getPostalCode() : null;
	}		
	
	/*
	 * CMS wants separate address lines
	 */
	private String getMailingAddressLine2(Address address) {
		return getString(address.getLine2());		
	}
	
	/*
	 * CMS wants separate address lines
	 */	
	private String getMailingAddressLine3(Address address) {
		return getString(address.getLine3());	
	}	
	private String getMailingAddressCounty(Address address) {
		return address.isUSAddress() ? address.getCounty() : null;
	}
	private String getMailingAddressProvince(Address address) {
		return !address.isUSAddress() ? address.getProvince() : null;
	}		
	
	protected String getBarcode(GenerateValues inputValues) {
		return LetterFormatHelper.formatBarcode(inputValues.getCommsLog().getBarcode());
	}
	
	@Override
	protected void buildDataElementsH(StringBuffer dataElements,
			GeneralTransmission transmission, GenerateValues inputValues) {
	
	}

	@Override
	protected void buildDataElementsH20(StringBuffer dataElements,
			GeneralTransmission transmission, GenerateValues inputValues,
			Person person) {

	}
	
	private boolean isIVMFinalLetter(String form) {
		if (form.equalsIgnoreCase(ComLetterTemplateType.FORM_NUMBER_400.getCode()) ||
				form.equalsIgnoreCase(ComLetterTemplateType.FORM_NUMBER_450.getCode()) ||
				form.equalsIgnoreCase(ComLetterTemplateType.FORM_NUMBER_451.getCode()) ||
				form.equalsIgnoreCase(ComLetterTemplateType.FORM_NUMBER_452.getCode()) ||
				form.equalsIgnoreCase(ComLetterTemplateType.FORM_NUMBER_453.getCode()) ||
				form.equalsIgnoreCase(ComLetterTemplateType.FORM_NUMBER_454.getCode()) ||
				form.equalsIgnoreCase(ComLetterTemplateType.FORM_NUMBER_455.getCode())) {
			return true;
		}
		return false;
	}
	private boolean isCompassionLetter(String form) {
		if (form.equalsIgnoreCase(ComLetterTemplateType.FORM_NUMBER_683A.getCode())) {
			return true;
		}
		return false;
	}
}
