/*
 * Created on Dec 20, 2005
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
package gov.va.med.esr.common.persistent.comms.hibernate;


//Java
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;

import gov.va.med.fw.persistent.DAOException;
import gov.va.med.fw.service.AbstractComponent;

import gov.va.med.esr.common.model.comms.CommsImportStatistics;
import gov.va.med.esr.common.model.comms.ErrorFileEntry;
import gov.va.med.esr.common.model.comms.MailedFileEntry;
import gov.va.med.esr.common.model.comms.RejectFileEntry;
import gov.va.med.esr.common.model.comms.CmsErrorFileEntry;
import gov.va.med.esr.common.model.comms.CmsMailedFileEntry;
import gov.va.med.esr.common.model.comms.CmsRejectFileEntry;
import gov.va.med.esr.common.model.comms.CmsReturnedByUSPSFileEntry;
import gov.va.med.esr.common.persistent.comms.ImportFileDAO;


/**
 * @author DNS   TSAIG
 *
 * To process 3 response files (WYYDDD01.ERR, WYYDDD01.rej, WYYDDD01.adr) after AAC process a letter file
 * 
 * According James Strike from AAC
 * - There will always be 3, even if there was no rejects or errors (empty file is returned today)
 * - When processing is complete we would move the files to a 'processed' folder.   
 *   I have created the 'processed' folder in FromEDB/Welcome/processed and  ToEDB/Welcome/processed.  
 */
public class ImportFileDAOImpl extends AbstractComponent implements ImportFileDAO{

	
	private static String FILE_TYPE = null;
	private static String ARCHIVED_FILE_EXTENSION = "~";
	
	private String filePath = null;
	private String cmsFilePath = null;	
	
	private boolean archiveFileAfterProcessing = true;

	
    /**
     * @return Returns the filePath where the AAC response files are.
     * This is configured and injected from a spring config file (comms/daos.xml)
     */
    public String getAacFilePath() {
        return filePath;
    }
    /**
     * @param filePath The filePath to set.
     */
    public void setAacFilePath(String filePath) {
        this.filePath = filePath;
    }
	
    //This file is a response to the letter file that is sent to AAC.  
    //It contains the records that failed the Validation Checks. 
    //The codes received populate the Error File Reason. A record can have one or more errors.
    //Record Example for a letter that has multiple error codes:
    //    F600C ^123456789^725092286^B05^388609723212334254345
    //    F600C ^123456789^725092286^H03^388609723212334254345
    //    F600C ^123456789^725092286^H04^388609723212334254345
	public ArrayList readErrorFile(CommsImportStatistics stat) throws DAOException
	{
	    File file = getFileByExtension(ERROR_FILE_EXTENSION);
	    
	    if (file == null)
	        return null;
	    
	    stat.setErrorFileReceivedDate(new Date(file.lastModified()));
	    stat.setErrorFileName(file.getName());
		
		ArrayList errEntryLst = new ArrayList();
	    
		String aLine = null;
		String [] fields = null;
		BufferedReader in = null;
		try {
			in = new BufferedReader(new FileReader(file));
	
			while((aLine = in.readLine()) != null)
			{		
				fields = aLine.split(FIELD_SEPERATOR);
				//Form#, Case#, SSN, Failed data element, Barcode
				if (fields.length ==5) //protect index out of bound error
					errEntryLst.add(new ErrorFileEntry(
                        fields[0].trim(),fields[1].trim(), fields[2].trim(), fields[3].trim(), fields[4].trim()));
			}
		} catch (java.io.FileNotFoundException fnfex)
		{
		    throw new DAOException("#### Error reading AAC Error file: File Not Found", fnfex);
		} catch (IOException ioex)
		{
		    throw new DAOException("#### Error reading AAC Error file: IO Exception", ioex);
		}  finally {
			if(in != null) {
				try {
					in.close();
					archiveProcessedFile(file);
				} catch(IOException e) {
					logger.error("Unable to close input file", e);
				}				
			}			
		}

		return errEntryLst;
	}


	//This file is a response to the letter file that is sent to AAC. 
	//It contains the records that failed the address validation (CASS Certified) checks.
	//The codes received populate the Code 1 Reject Field. Only one code per letter request will be received.
	//Record Example: H600C ^123456789^725092286^S^388609723212334254345
	public ArrayList readRejectFile(CommsImportStatistics stat) throws DAOException
	{
	    File file = getFileByExtension(REJECT_FILE_EXTENSION);
	    
	    if (file == null)
	        return null;
	    
	    stat.setRejectFileReceivedDate(new Date(file.lastModified()));
	    stat.setRejectFileName(file.getName());
		
		ArrayList rejEntryLst = new ArrayList();
	    
		String aLine = null;
		String [] fields = null;
		BufferedReader in = null;
		try{
			in = new BufferedReader(new FileReader(file));
	
		    while((aLine = in.readLine()) != null)
			{		
		        fields = aLine.split(FIELD_SEPERATOR);
			    //Form#, Case#, SSN, Code 1 reject error code, Barcode
			    if (fields.length ==5) //protect index out of bound error
			        rejEntryLst.add(new RejectFileEntry(
                            fields[0].trim(),fields[1].trim(), fields[2].trim(), fields[3].trim(), fields[4].trim()));
			}
		} catch (java.io.FileNotFoundException fnfex)
		{
		    throw new DAOException("#### Error reading AAC Reject file: File Not Found", fnfex);
		} catch (IOException ioex)
		{
		    throw new DAOException("#### Error reading AAC Reject file: IO Exception", ioex);
		} finally {
			if(in != null) {
				try {
					in.close();
					archiveProcessedFile(file);
				} catch(IOException e) {
					logger.error("Unable to close input file", e);
				}				
			}			
		}
		
		return rejEntryLst;
	}
	

	//This file contains the records that were mailed with a standardized address (CASS Certified). 
	//These represent those records where a letter was actually mailed by the mail center.
	//Record Example: 600C^123456789^725092286^MR JACK R LEGGETT^2704 N 8TH ST^ MCALLEN^ TX^78501-2068^05052005^ 388609723212334254345
	public ArrayList readMailedFile(CommsImportStatistics stat) throws DAOException
	{
	    File file = getFileByExtension(MAILED_FILE_EXTENSION);
	    
	    if (file == null)
	        return null;
	    
	    stat.setMailedFileReceivedDate(new Date(file.lastModified()));
	    stat.setMailedFileName(file.getName());
		
	    ArrayList addrEntryLst = new ArrayList();
	    
		String aLine = null;
		String [] fields = null;
		BufferedReader in = null;
	    try {
			in = new BufferedReader(new FileReader(file));
	
		    while((aLine = in.readLine()) != null)
			{		
		        fields = aLine.split(FIELD_SEPERATOR);
				//Form#, Case#, SSN, Name, Line1, Line2, City, State, Zip, Date Mailed, Barcode
				if (fields.length == 11) //protect index out of bound error
				    addrEntryLst.add(new MailedFileEntry(
                        fields[0].trim(),fields[1].trim(),fields[2].trim(),fields[3].trim(),
                        fields[4].trim(),fields[5].trim(),fields[6].trim(),fields[7].trim(),fields[8].trim(),
                        fields[9].trim(),fields[10].trim()));
			}		    
		} catch (java.io.FileNotFoundException fnfex)
		{
		    throw new DAOException("#### Error reading AAC Mailed file: File Not Found", fnfex);
		} catch (IOException ioex)
		{
		    throw new DAOException("#### Error reading AAC Mailed file: IO Exception", ioex);
		} finally {
			if(in != null) {
				try {
					in.close();
					archiveProcessedFile(file);
				} catch(IOException e) {
					logger.error("Unable to close input file", e);
				}				
			}			
		}
		
		return addrEntryLst;

	}
	
	
	public String getCmsFilePath() {
		return cmsFilePath;
	}

	public ArrayList readCmsErrorFile(CommsImportStatistics stat)
			throws DAOException {
	    File file = getCmsFileByExtension(ERROR_FILE_EXTENSION);
	    
	    if (file == null)
	        return null;
	    
	    stat.setErrorFileReceivedDate(new Date(file.lastModified()));
	    stat.setErrorFileName(file.getName());
		
		ArrayList errEntryLst = new ArrayList();
	    
		String aLine = null;
		String [] fields = null;
		BufferedReader in = null;
		try {
			in = new BufferedReader(new FileReader(file));
	
			while((aLine = in.readLine()) != null)
			{		
				fields = aLine.split(FIELD_SEPERATOR);
				if (fields.length ==6) //protect index out of bound error
					errEntryLst.add(new CmsErrorFileEntry(fields[0].trim(),fields[1].trim(),fields[2].trim(),
				    		fields[3].trim(),fields[4].trim(),fields[5].trim()));
			}
		} catch (java.io.FileNotFoundException fnfex)
		{
		    throw new DAOException("#### Error reading CMS Error file: File Not Found", fnfex);
		} catch (IOException ioex)
		{
		    throw new DAOException("#### Error reading CMS Error file: IO Exception", ioex);
		}  finally {
			if(in != null) {
				try {
					in.close();
					archiveProcessedFile(file);
				} catch(IOException e) {
					logger.error("Unable to close input file", e);
				}				
			}			
		}

		return errEntryLst;
	}

	public ArrayList readCmsMailedFile(CommsImportStatistics stat)
			throws DAOException {
	    File file = getCmsFileByExtension(MAILED_FILE_EXTENSION);
	    
	    if (file == null)
	        return null;
	    
	    stat.setMailedFileReceivedDate(new Date(file.lastModified()));
	    stat.setMailedFileName(file.getName());
		
	    ArrayList addrEntryLst = new ArrayList();
	    
		String aLine = null;
		String [] fields = null;
		BufferedReader in = null;
	    try {
			in = new BufferedReader(new FileReader(file));
	
		    while((aLine = in.readLine()) != null) {		
		        fields = aLine.split(FIELD_SEPERATOR);
				if (fields.length == 6) //protect index out of bound error
				    addrEntryLst.add(new CmsMailedFileEntry(fields[0].trim(),fields[1].trim(),fields[2].trim(),
				    		fields[3].trim(),fields[4].trim(),fields[5].trim()));
			}		    
		} catch (java.io.FileNotFoundException fnfex)
		{
		    throw new DAOException("#### Error reading CMS Mailed file: File Not Found", fnfex);
		} catch (IOException ioex) {
		    throw new DAOException("#### Error reading CMS Mailed file: IO Exception", ioex);
		} finally {
			if(in != null) {
				try {
					in.close();
					archiveProcessedFile(file);
				} catch(IOException e) {
					logger.error("Unable to close input file", e);
				}				
			}			
		}
		
		return addrEntryLst;
	}

	public ArrayList readCmsRejectFile(CommsImportStatistics stat)
			throws DAOException {
	    File file = getCmsFileByExtension(REJECT_FILE_EXTENSION);
	    
	    if (file == null)
	        return null;
	    
	    stat.setRejectFileReceivedDate(new Date(file.lastModified()));
	    stat.setRejectFileName(file.getName());
		
		ArrayList rejEntryLst = new ArrayList();
	    
		String aLine = null;
		String [] fields = null;
		BufferedReader in = null;
		try{
			in = new BufferedReader(new FileReader(file));
	
		    while((aLine = in.readLine()) != null)
			{		
		        fields = aLine.split(FIELD_SEPERATOR);
			    if (fields.length ==6) //protect index out of bound error
			        rejEntryLst.add(new CmsRejectFileEntry(fields[0].trim(),fields[1].trim(),fields[2].trim(),
				    		fields[3].trim(),fields[4].trim(),fields[5].trim()));
			}
		} catch (java.io.FileNotFoundException fnfex)
		{
		    throw new DAOException("#### Error reading CMS Reject file: File Not Found", fnfex);
		} catch (IOException ioex)
		{
		    throw new DAOException("#### Error reading CMS Reject file: IO Exception", ioex);
		} finally {
			if(in != null) {
				try {
					in.close();
					archiveProcessedFile(file);
				} catch(IOException e) {
					logger.error("Unable to close input file", e);
				}				
			}			
		}
		
		return rejEntryLst;
	}

	public ArrayList readCmsReturnedMailFile(CommsImportStatistics stat)
			throws DAOException {
	    File file = getCmsFileByExtension(RETURNED_FILE_EXTENSION);
	    
	    if (file == null)
	        return null;
	    
	    stat.setRejectFileReceivedDate(new Date(file.lastModified()));
	    stat.setRejectFileName(file.getName());
		
		ArrayList rejEntryLst = new ArrayList();
	    
		String aLine = null;
		String [] fields = null;
		BufferedReader in = null;
		try{
			in = new BufferedReader(new FileReader(file));
	
		    while((aLine = in.readLine()) != null)
			{		
		        fields = aLine.split(FIELD_SEPERATOR);
			    if (fields.length ==6) //protect index out of bound error
			        rejEntryLst.add(new CmsReturnedByUSPSFileEntry(fields[0].trim(),fields[1].trim(),fields[2].trim(),
				    		fields[3].trim(),fields[4].trim(),fields[5].trim()));
			}
		} catch (java.io.FileNotFoundException fnfex)
		{
		    throw new DAOException("#### Error reading CMS Returned Mail file: File Not Found", fnfex);
		} catch (IOException ioex)
		{
		    throw new DAOException("#### Error reading CMS Returned Mail file: IO Exception", ioex);
		} finally {
			if(in != null) {
				try {
					in.close();
					archiveProcessedFile(file);
				} catch(IOException e) {
					logger.error("Unable to close input file", e);
				}				
			}			
		}
		
		return rejEntryLst;
	}
	
	public void setCmsFilePath(String cmsFilePath) {
		this.cmsFilePath = cmsFilePath;
	}
	
	private void archiveProcessedFile(File inputFile) {
		if(!archiveFileAfterProcessing)
			return;
		
		File archivedFile = new File(inputFile.getAbsolutePath() + ARCHIVED_FILE_EXTENSION); 
		boolean result = inputFile.renameTo(archivedFile);
		if(!result) {
			logger.error("Unable to rename input file: " + inputFile);
		}
	}


	private File getFileByExtension(String fileType)
	{
	    FILE_TYPE = fileType;
	    
	    File[] files = new File(getAacFilePath()).listFiles(new FilenameFilter() {
	        public boolean accept(File d, String name) {
	            return name.endsWith(FILE_TYPE);
	        }
	    });
	    
		if (files == null || files.length == 0)
			return null;
		
		//should just have one file
		return files[0];
	}
	private File getCmsFileByExtension(String fileType)
	{
	    FILE_TYPE = fileType;
	    
	    File[] files = new File(getCmsFilePath()).listFiles(new FilenameFilter() {
	        public boolean accept(File d, String name) {
	            return name.endsWith(FILE_TYPE);
	        }
	    });
	    
		if (files == null || files.length == 0)
			return null;
		
		//should just have one file
		return files[0];
	}	
	/**
	 * @return Returns the archiveFileAfterProcessing.
	 */
	public boolean isArchiveFileAfterProcessing() {
		return archiveFileAfterProcessing;
	}
	/**
	 * @param archiveFileAfterProcessing The archiveFileAfterProcessing to set.
	 */
	public void setArchiveFileAfterProcessing(boolean archiveFileAfterProcessing) {
		this.archiveFileAfterProcessing = archiveFileAfterProcessing;
	}

}
