package gov.va.med.esr.common.batchprocess;

import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Date;
import java.io.*;
import org.apache.commons.lang.Validate;
import gov.va.med.esr.common.model.CommonEntityKeyFactory;
import gov.va.med.fw.batchprocess.AbstractDataFileSingleRowIncrementProcess;
import gov.va.med.fw.batchprocess.DataFileProcessExecutionContext;
import gov.va.med.fw.batchprocess.ProcessStatistics;
import gov.va.med.esr.service.HandBookService;
import gov.va.med.esr.service.LookupService;
import gov.va.med.esr.common.model.lookup.HandBookMailStatusType;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.service.PersonService;
import gov.va.med.esr.common.model.comms.HandBookMailQueue;
import gov.va.med.fw.batchprocess.HandbookMailingResponseAddressFileProcessStatistics;
import gov.va.med.esr.common.model.person.id.PersonIdEntityKey;
/** CCR10964
 * Batch process that reads from incoming CMS address file parsing
 * successful mailings of handbooks
 * 
 * TODO: 
 * Sudha email 07212001 - Failed file  records that fail the validation checks in ICD need 
 * not be written to exception file
 * @author DNS   PICKLJ
 *
 */
public class HandbookMailingResponseAddressFileProcess extends
		AbstractDataFileSingleRowIncrementProcess implements Serializable {
	
	protected PersonService personService;
	private HandBookService handBookService;
	private LookupService lookupService;	
	private String rawData = null;
	private HandbookMailingResponseAddressFileProcessStatistics stats = null;

	/*
	 * (non-Javadoc)
	 *  TODO database changes are coming from ADR
	 *       
	 * @see gov.va.med.fw.batchprocess.AbstractDataProcess#processData(gov.va.med.fw.batchprocess.DataProcessExecutionContext,
	 *      java.util.List)
	 */
	public  void processDataRecords(
			      DataFileProcessExecutionContext context, List acquiredData) {
		if(acquiredData.isEmpty()) {
			logger.info("no records"); 
			return;
		}	
		logger.info("processing a new record"); 
		if (stats == null ) { 
	      try {		
	          stats = (HandbookMailingResponseAddressFileProcessStatistics)context.getProcessStatistics();
	      } catch (java.lang.ClassCastException cex) {
              logger.error("ClassCastException crap! : ", cex);
	      }	  
	    }	

		for (int i=0;i<acquiredData.size();i++) {
		     try {
	        	Object obj = acquiredData.get(i);
	            // if no exception continue reading file data
			    if (processDataRecord(context, obj)) {

				    if (isKeepProcessedData()) {
					  context.getProcessedData().add(obj);
					  logger.info("adding processDataRecord "+i);
				    } else {
					  logger.info("NO MORE DATA run any clean up");	
					  updateJobResultsLast(context);
				    }
				  
			    } else {
				  // some error while calling processDataRecord so stop
				  logger.info("one record sent back false - stopping processDataRecords"); 
				  updateJobResultsLast(context);
				  break;				  
			    }
			  } catch (RuntimeException e) {
					if(logger.isErrorEnabled())
					logger.error("RuntimeException processDataRecords^"+e.getMessage()+"^"+rawData);
					context.getExceptionData().add(createExceptionObject("RuntimeException processDataRecords^"+rawData+"^"+e.fillInStackTrace()));
			  }
			}

	}	
	
	
	protected boolean processDataRecord(DataFileProcessExecutionContext context, Object bean) {
		
		HandbookMailingResponseAddressFileData dataRecord = (HandbookMailingResponseAddressFileData) bean;
		boolean success = true;
        rawData = context.getCurrentRowRawData();
        SimpleDateFormat dateFormat = new SimpleDateFormat("MMddyyyy");
        
		try {
			// validate record
			// Missing Required fields
			if (dataRecord.validateData().size() > 0) {
				// collect error info
				List invalidData = dataRecord.validateData();
				String errMsg = "";
				for (int i=0;i<invalidData.size();i++) {
					errMsg = errMsg+"^"+(String)invalidData.get(i);
				}				
				logger.error("Failed - Missing Required Fields"+errMsg);
				context.getExceptionData().add(createExceptionObject("Failed - Missing Required Fields"+errMsg+"^"+rawData));
				context.getProcessStatistics().incrementNumberOfErrorRecords();
				// keep processing?
				return success;
			}
			// Invalid Product ID
			String formName = dataRecord.getProdNumText();
			// check Product ID update stats//H400H, H400B, H400F				
			if (formName.equals("H400H")) {
					stats.incrementH400HRecordsProcessed();
			} else if (formName.equals("H400B")) {
					stats.incrementH400BRecords();
			} else if (formName.equals("H400F")) {
					stats.incrementH400FRecords();				
			} else {
					logger.info("Invalid Product ID^"+rawData);
					context.getExceptionData().add(createExceptionObject("Invalid Product ID^"+rawData));
					context.getProcessStatistics().incrementNumberOfErrorRecords();
					// keep processing?
					return success;					
			}	
	
			// find mailQueue 
			HandBookMailQueue mailQueue = new HandBookMailQueue();
			//logger.info("get mailQueue for UID="+dataRecord.getUID());
			try {
				 mailQueue = handBookService.findHandBookByIdentifier(dataRecord.getUID());
			} catch (Exception ex) {
			     logger.error("Invalid Request ID^Exception - handBookService.findHandBookByIdentifier^"+ex.getMessage()+"^"+rawData);
			     context.getExceptionData().add("Invalid Request ID^Exception - handBookService.findHandBookByIdentifier^"+rawData+"^"+ex.fillInStackTrace());
			     context.getProcessStatistics().incrementNumberOfErrorRecords();
			     // keep processing?
				 return success;	
			}
            if (mailQueue == null) {
			     logger.error("Invalid Request ID^mailQueue is null^"+rawData);
				 context.getExceptionData().add("Invalid Request ID^mailQueue is null^"+rawData);
				 context.getProcessStatistics().incrementNumberOfErrorRecords();
				 // keep processing?
				 return success;            	
            }
			// VPID not matching the one sent in the request
			// there is no VPID in mailQueue but we can get VPID from create personService
			// failure to create is Invalid Veteran Id	
			//String vpidFromDB = personService.getVPIDByPersonId(mailQueue.getEntityKey().
			// move this down
			String vpidCompare = null;
			String icnCompare = null;
			try {
				String personId = String.valueOf(mailQueue.getPersonId());
				PersonIdEntityKey pkey = CommonEntityKeyFactory.createPersonIdEntityKey(personId); 
				vpidCompare = (personService.getVPIDByPersonId(pkey)).getVPID();
				icnCompare  = handBookService.getICNChecksumForVpid(vpidCompare);
				
				logger.info("does ["+dataRecord.getVPID()+"] = ["+icnCompare+"]");
			} catch (Exception ex) {
				logger.error("Exception - getVPIDByPersonId failed^"+rawData+"^"+ex.fillInStackTrace());
				context.getExceptionData().add("Exception - getVPIDByPersonId failed^"+rawData+"^"+ex.fillInStackTrace());
				context.getProcessStatistics().incrementNumberOfErrorRecords();
				// keep processing records?				
				return success; 				
			}			           
            // match icnCompare
			if (!icnCompare.equals(dataRecord.getVPID())) {
				logger.error("Invalid Veteran ID^"+rawData);
				context.getExceptionData().add("Invalid Veteran Id^"+rawData);
				context.getProcessStatistics().incrementNumberOfErrorRecords();
				// keep processing records?				
				return success; 				
			}
			/* 
			 * SUC62.3.1 If the specific letter Remail Indicator on the EDB is Resend then the system 
			 * automatically sets the Remail Indicator to Remailed (Handbooks are not remailed).
			 * 
			 * For Handbook Files, for each record received, a check is done to ensure that the corresponding 
			 * handbook and profile .pdf files exist in the VBR.  If they do, the Communication Status is set 
			 * to Mailed by CMS.
			 * */
			// check for docuemnt_receipt - requirement from email from Sudha
			boolean receiptVerified = handBookService.verifyDocumentReceipt(vpidCompare, dataRecord.getUID());		
			/*
			 * The way you can check if a handbook /  benefits profile is stored is 
			 * to check the document_receipt table matching the request_number in 
			 * address_file to receipt_string in document_receipt table .With the 
			 * document_receipt_id, you can check the document table for 
			 * document_type_id = 1 and document_type_id = 2. You should find 
			 * two entries with file_id. This ensures that the files are 
			 * stored in VBR.
			 */
			if (!receiptVerified) {
				logger.error("document verified is false vpidCompare="+vpidCompare+"^"+rawData);
				//context.getExceptionData().add("Failed - document verified is false^"+rawData);
				context.getFailedData().add(rawData);
				context.getExceptionData().add("Verify Receipt Failed^"+rawData);
				context.getProcessStatistics().incrementNumberOfErrorRecords();
				// keep processing records?				
				return success;  
			}				
			// no instructions to validate address but HANSBOOK_MAIL_QUEUE.ADDRESS_ID 
			// is nullable so make sure it is not null
			/* 08/10/2011 Sudha
			 * - you need to remove the current validation that checks the if the address_id is 
			 *   present in the handbook_mail_queue table)
			 */
			// SQA says failed data is an exception 08052011 and there is no failed data file *.FAILED
			// failed data is not a java exception
			//logger.info("the mailQueue is not null for UID="+dataRecord.getUID());			
			// update Mailed By CMS in go get a HandbookMailQueue record using uid
			// ADR.HANDBOOK_MAIL_QUEUE.HANDBOOK_MAIL_QUEUE_ID
			/*
			 * SUC62.3.2 The system captures the Date/Time File Received.
			 * SUC62.3.3 The system updates the Date Mailed with the Date Mailed received with each record.
			 * SUC62.3.4 The system sets the Date/Time Updated to the Date/Time the Communication Status was set.
			 * SUC62.3.5 The system captures and stores the following statistics that will be used to generate a report.:
                Date/Time File Received
                File Name
                Number of Records Per File
                Break out the letters communication by type and how many per type.
			 * */		
            String uid = dataRecord.getUID();
            try {
            	// update status  "Mailed By CMS"  
                HandBookMailStatusType statusType  =lookupService.getHandBookMailingStatusTypeByCode(HandBookMailStatusType.MAILED_BY_CMS.getCode());
                Date mailedDate = dateFormat.parse(dataRecord.getDatemailed());
                mailQueue.getHandBookMailStatus().setSentToUPSDate(mailedDate);
                handBookService.saveHandbookMailStatus(mailQueue, statusType);
                context.getProcessStatistics().incrementNumberOfSuccessfulRecords();
            } catch (Exception ex) {
    			logger.error("processDataRecord updateStatus update Exception uid="+uid+" : " + rawData, ex);
    			context.getExceptionData().add("Exception - updateStatus"+rawData+"^"+ex.fillInStackTrace());
    			context.getProcessStatistics().incrementNumberOfErrorRecords();
    		    return success;
            }		
			
			return success;
			
		} catch (Exception ex) {
			// no docs on exceptions yet - writing to a file
			logger.error("processDataRecord - Exception processing data record^" + rawData, ex.fillInStackTrace());
			context.getProcessStatistics().incrementNumberOfErrorRecords();
			context.getExceptionData().add(createExceptionObject("processDataRecord - Exception processing data record^"+rawData+"^"+ex.fillInStackTrace()));
		}
		
		return success;		
	}
			
	public void afterPropertiesSet() {
		super.afterPropertiesSet();
		Validate.notNull(personService, "personService is required");
	}

	// update stats last
	private void updateJobResultsLast(DataFileProcessExecutionContext context) {
		  stats.setProcessingEndDate(new Date());
		  updateJobResult(context);		
	}
	
	public PersonService getPersonService() {
		return personService;
	}

	public void setPersonService(PersonService personService) {
		this.personService = personService;
	}
	
	public HandBookService getHandBookService() {
		return handBookService;
	}

	public void setHandBookService(HandBookService handBookService) {
		this.handBookService = handBookService;
	}	

	public LookupService getLookupService() {
		return lookupService;
	}

	public void setLookupService(LookupService lookupService) {
		this.lookupService = lookupService;
	}
	protected ProcessStatistics createProcessStatistics() {
        return new HandbookMailingResponseAddressFileProcessStatistics ();
    } 
}

