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

import gov.va.med.esr.common.model.lookup.RegistryType;
import gov.va.med.esr.common.model.lookup.ReportExceptionType;
import gov.va.med.esr.common.model.registry.Registry;
import gov.va.med.esr.service.LoadRegistryResult;
import gov.va.med.esr.service.LookupService;
import gov.va.med.esr.service.RegistryService;
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.fw.io.writer.FormattedFileWriter;
import gov.va.med.fw.service.ServiceException;

import java.util.HashMap;
import java.util.Map;

/**
 * Processes the Purple Heart, POW and SHAD registry files.
 * 
 * @author Rajiv Patnaik Created on Apr 10, 2006
 * @version 1.0
 * 
 * Copyright © 2006 VHA. All rights reserved
 */
public class LoadRegistryProcess extends
        AbstractDataFileSingleRowIncrementProcess
{
    
    /**
     * Maps the audit Id in the job configuration with the correct Registry Type.
     * Used to get the correct Registry Type if a record could not be parsed.
     */
    private static Map registryTypes = new HashMap() 
    {
        /**
		 * 
		 */
		private static final long serialVersionUID = -1190015544065810633L;

		{
            put("ProcessPOWRegistryFile", RegistryType.CODE_POW_REGISTRY.getCode());
            put("ProcessPurpleHeartRegistryFile", RegistryType.CODE_PH_REGISTRY.getCode());
            put("ProcessSHADRegistryFile", RegistryType.CODE_SHAD_REGISTRY.getCode());
        }
    };    
    
    private FormattedFileWriter exceptionFileWriter;

    private RegistryService registryService;
    
    private LookupService lookupService;
    
    

    /**
     * @return Returns the exceptionFileWriter.
     */
    public FormattedFileWriter getExceptionFileWriter()
    {
        return exceptionFileWriter;
    }

    /**
     * @param exceptionFileWriter
     *            The exceptionFileWriter to set.
     */
    public void setExceptionFileWriter(FormattedFileWriter exceptionFileWriter)
    {
        this.exceptionFileWriter = exceptionFileWriter;
    }

    /**
     * @return Returns the registryService.
     */
    public RegistryService getRegistryService()
    {
        return registryService;
    }

    /**
     * @param registryService
     *            The registryService to set.
     */
    public void setRegistryService(RegistryService registryService)
    {
        this.registryService = registryService;
    }

    /**
     * @return Returns the lookupService.
     */
    public LookupService getLookupService()
    {
        return lookupService;
    }
    /**
     * @param lookupService The lookupService to set.
     */
    public void setLookupService(LookupService lookupService)
    {
        this.lookupService = lookupService;
    }
    /*
     * (non-Javadoc)
     * 
     * @see gov.va.med.fw.batchprocess.AbstractDataFileSingleRowIncrementProcess#processDataRecord(java.lang.Object)
     */

    protected ProcessStatistics createProcessStatistics()
    {
        return new LoadRegistryProcessStatistics();
    }

    // Override to write to exception file if a record fails bean creation
    public boolean beanCreationFailure(DataFileProcessExecutionContext context,
            String nextRowRawData, Exception e)
    {
        //Even if there was a problem, treat it as a successful record for
        // statistical purposes
        //since the record will be logged in the exception file
        LoadRegistryProcessStatistics statistics = (LoadRegistryProcessStatistics) context
                .getProcessStatistics();
        context.getProcessStatistics().incrementNumberOfSuccessfulRecords();
        statistics.incrementRecordsRead();
        statistics.incrementRecordsFailedConsistencyCheck();
        
        try
        {
            statistics.setRegistryType(
                    (RegistryType)getLookupService().getByCode(RegistryType.class, (String)registryTypes.get(getAuditId())));
            statistics.addRegistryExceptionDetail(
                    (ReportExceptionType)getLookupService().getByCode(ReportExceptionType.class, ReportExceptionType.R1), 
                    context.getCurrentRowRawData());
        } catch (ServiceException ex)
        {
            //LookupException should not happen. Log the exception message
            logger.error("Could not lookup code while adding consistency check failure record" +ReportExceptionType.R1.getCode(), ex);
        } 
        
        return true;
    }


    protected boolean processDataRecord(
            DataFileProcessExecutionContext context, Object bean)
    {
    	LoadRegistryProcessStatistics statistics = 
    		(LoadRegistryProcessStatistics) context.getProcessStatistics();
    	Registry registry = null;
        try
        {
            LoadRegistryFileData fileData = (LoadRegistryFileData) bean;
            registry = fileData.getRegistry();
            
            //Execute rules
            LoadRegistryResult result = registryService.processRegistry(registry);

            //Set statistical data
            setStatisticalData(context, registry, result, statistics);

        } catch (Throwable e)
        {
        	if(logger.isErrorEnabled()) 
        		logger.error("Error processing data record: " + context.getCurrentRowRawData(), e);
            
            setSystemErrorStatisticalData(context, registry, e); 
        }

        return true;
    }


    /**
     * Set the Statistics data to be persisted
     * @param registry
     * @param result
     * @param statistics
     */
    private void setStatisticalData(DataFileProcessExecutionContext context, Registry registry,
            LoadRegistryResult result, LoadRegistryProcessStatistics statistics)
    {
        //Set statistical info
        statistics.setRegistryType(registry.getRegistryTrait()
                .getRegistryType());
        statistics.incrementRecordsRead();
        statistics.incrementRecordsPassedConsistencyCheck();

        //Parse the result from rules. 
        if (result != null)
        {
            if (!result.isExactMatch())
                statistics.incrementRecordsNotMatchedToExistingRecords();

            if (result.isAmbiguousMatch())
                statistics.incrementRecordsAmbigouslyMatched();

            if (result.isExactMatch())
                statistics.incrementRecordsMatchedToExistingRecords();

            if (result.isNewRegistry())
                statistics.incrementNewRegistryEntriesInserted();

            if(result.getExceptionType() != null)
            {
                statistics.addRegistryExceptionDetail(
                        result.getExceptionType(),context.getCurrentRowRawData());
                
            }

        }
        
    }

	/**
	 * Set the Statistics data to be persisted in case of a System Exception
	 * 
	 * @param context
	 * @param statistics
	 * @param registry
	 * @param e
	 */
	private void setSystemErrorStatisticalData(DataFileProcessExecutionContext context, 
			Registry registry, Throwable e) {
	    
		//TODO For any system exeption, append the exception message to the row record.
	    //Modify code once database changes have been made to add new exception type and a column 
	    //to store this exception message 		
    	LoadRegistryProcessStatistics statistics = 
    		(LoadRegistryProcessStatistics) context.getProcessStatistics();
		
		statistics.setRegistryType(registry.getRegistryTrait().getRegistryType());
		statistics.incrementRecordsRead();
		statistics.incrementRecordsPassedConsistencyCheck();            
		statistics.addRegistryExceptionDetail(
		        null,context.getCurrentRowRawData() + "^[Error message - " + (e.getMessage() == null ? "Unknown system exception":e.getMessage()) +"]");
	}    
}