package gov.va.med.fw.batchprocess;

import gov.va.med.fw.io.writer.FormattedFileWriter;
import gov.va.med.fw.service.AbstractComponent;

import java.io.File;
import java.util.Date;
import java.util.List;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;

public class FailedRecordWriterProcessCompletedHandler extends
		AbstractComponent implements DataProcessCompletedHandler {

	private FormattedFileWriter failedFileWriter;
	private FormattedFileWriter exceptionFileWriter;
	private boolean deleteInputFile = false;
	private String fileExention = ".txt";
	
	private String renameInputFileExtension = ".DONE";
	
	private static String DATE_FORMAT = "yyyyMMddHHmmss";
	
	/* (non-Javadoc)
	 * @see gov.va.med.fw.batchprocess.DataProcessCompletedHandler#dataProcessingComplete(gov.va.med.fw.batchprocess.DataProcessExecutionContext)
	 */
	public void dataProcessingComplete(DataProcessExecutionContext context) {
		// write exception data
		writeExceptionData(context);
		writeFailedData(context);
		//Fix for CR_7600 If the batchProcess is interrupted do not delete the files.
		if(!context.isInterrupted()){
		    // delete input file (if any)
		    if(context instanceof DataFileProcessExecutionContext) {
			    File inputFile = ((DataFileProcessExecutionContext) context).getCurrentFile();
			    if (deleteInputFile && !inputFile.delete()){
				    throw new IllegalStateException("Unable to delete input file: "+ inputFile.getName());			
		    	} else if (renameInputFileExtension != null  ) {
		    		renameFile(inputFile);
		    	}
		    }
		}
	}
	
	public final void writeExceptionData(DataProcessExecutionContext context) {
		List exceptionData = getInterestedExceptionData(context);
		if(exceptionData != null && !exceptionData.isEmpty() && exceptionFileWriter != null)
			exceptionFileWriter.appendData(exceptionData, getExceptionFileNameSuffixData(context));
		
		//clear the exception data after writing to the file
        synchronized(exceptionData) {
            exceptionData.clear();
        }
	}
	
	
	public final void writeFailedData(DataProcessExecutionContext context) {
		List failedRecords = ((DataFileProcessExecutionContext) context).getFailedData();
		if(failedRecords != null && !failedRecords.isEmpty() ) {
			//failedFileWriter.setFileLocation();
			failedFileWriter.appendData(failedRecords, getFailedFileName(context));
	        synchronized(failedRecords) {
	        	failedRecords.clear();
	        }
		}
	}
	// subclasses can override for subset of exception data to write to file
	protected List getInterestedExceptionData(DataProcessExecutionContext context) {
		return context.getExceptionData();
	}

	// subclasses can override
	protected Object getExceptionFileNameSuffixData(DataProcessExecutionContext context) {
		File inputFile = ((DataFileProcessExecutionContext) context).getCurrentFile();		
		String inputFileName = inputFile.getName();

		return inputFileName;
	}
	
	protected String getFailedFileName(DataProcessExecutionContext context) {
		String currentFileName = ((DataFileProcessExecutionContext) context).getCurrentFile().getName();

		//get the last 3 chars before the ext
		int currNumber = 0;
		String firstPart = currentFileName.substring(0, currentFileName
				.lastIndexOf('.'));
//		Pattern pattern = Pattern.compile("^(\\S+)_(\\d{1,2})\\.(\\S+)$");
//		Matcher matcher = pattern.matcher(currentFileName);
		if (Pattern.matches("^(\\S+)_(\\d{1,2})\\.(\\S+)$", currentFileName)  ) {
			String digits = currentFileName.substring(currentFileName
					.lastIndexOf('_') + 1);
			
			digits = digits.substring(0, digits.lastIndexOf('.'));

			//firstPart = currentFileName.substring(0, currentFileName
			//		.lastIndexOf('.'));
			try {
				currNumber = Integer.parseInt(digits);
			} catch (NumberFormatException e) {
			}
		} 

		if ( currNumber > 0 && currNumber < 10) {
			//remove the number part
			firstPart = currentFileName.substring(0, currentFileName
					.lastIndexOf('_'));
		}
		currNumber++;

		String lastPart = fileExention;

		
		if (currNumber <= 10) {
			lastPart = "_" + currNumber + fileExention;
		} else { //(currNumber > 10) 
			lastPart = ".failed";
		} 

		String fileName = firstPart + lastPart;
		
		return fileName;
	}
	protected boolean renameFile(File inputFile) {
		String inputFilePath = inputFile.getParent();
		StringBuffer inputFileNameRoot = new StringBuffer("");
		StringTokenizer st = new StringTokenizer(inputFile.getName(), ".");
		int tokenCount = st.countTokens();
		for (int i = 1; i < tokenCount; i++) {
			inputFileNameRoot.append(st.nextToken());
			if (i != (tokenCount - 1))
				inputFileNameRoot.append(".");
		}
		if (tokenCount == 1)
			inputFileNameRoot.append(inputFile.getName());

		String newFileName = inputFileNameRoot.toString()
					+ renameInputFileExtension;
		File newFile = new File(inputFilePath + File.separator + newFileName);
		int i = 1;
		while (newFile.exists()) {
			if (logger.isWarnEnabled())
				logger
						.warn("Can not rename file to "
								+ newFile.getName()
								+ " since it exists already.  Trying one up number extension");

			newFile = new File(inputFilePath + File.separator + newFileName
					+ (i++));
		}
		boolean result = inputFile.renameTo(newFile);
		inputFile.setLastModified(new Date().getTime());
		return result;
	}	

	
	public void afterPropertiesSet() {
		Validate.notNull(failedFileWriter);
	}

	/**
	 * @return Returns the deleteInputFile.
	 */
	public boolean isDeleteInputFile() {
		return deleteInputFile;
	}

	/**
	 * @param deleteInputFile The deleteInputFile to set.
	 */
	public void setDeleteInputFile(boolean deleteInputFile) {
		this.deleteInputFile = deleteInputFile;
	}

	public FormattedFileWriter getExceptionFileWriter() {
		return exceptionFileWriter;
	}

	public void setExceptionFileWriter(FormattedFileWriter exceptionFileWriter) {
		this.exceptionFileWriter = exceptionFileWriter;
	}

	public FormattedFileWriter getFailedFileWriter() {
		return failedFileWriter;
	}

	public void setFailedFileWriter(FormattedFileWriter failedFileWriter) {
		this.failedFileWriter = failedFileWriter;
	}

	public String getFileExention() {
		return fileExention;
	}

	public void setFileExention(String fileExention) {
		this.fileExention = fileExention;
	}

	public String getRenameInputFileExtension() {
		return renameInputFileExtension;
	}

	public void setRenameInputFileExtension(String renameInputFileExtension) {
		this.renameInputFileExtension = renameInputFileExtension;
	}

}
