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

import gov.va.med.esr.common.rule.parameter.MTTotalIncomePresentAndFinancialStmtIncomeNullException;
import gov.va.med.esr.common.util.FeedbackTask;
import gov.va.med.esr.common.util.TimerFactory;
import gov.va.med.esr.service.PersonLockedException;
import gov.va.med.fw.persistent.DAOOperations;
import gov.va.med.fw.service.ServiceException;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.List;
import java.util.Timer;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.JspWriter;

import org.apache.commons.logging.Log;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;

/**
 * 
 * Finds veterans whose most recent enrollment determination assigns the veteran
 * to priority group 8e or 8g and have an income test of type primary for income
 * year 2008,and sends them to a veteran updater process.
 * 
 */
public class ReProcessVeteransIn8eAnd8gProcessImpl implements
        ReProcessVeteransIn8eAnd8gProcess, BeanFactoryAware {
    public final String FIND_VETERANS_FOR_CONVERSION_SQL = "select p.person_id, p.vpid_value "
            + "from Person p "
            + "JOIN Enrollment_Determination ed "
            + "ON ED.PERSON_ID = P.PERSON_ID AND ED.ENROLLMENT_DETERMINATION_ID "
            + "=(SELECT MAX(ENROLLMENT_DETERMINATION_ID) "
            + "FROM Enrollment_Determination ed2 WHERE ed2.PERSON_ID = p.PERSON_ID) "
            + "JOIN STD_ENROLLMENTPRIORGRP pg "
            + "ON PG.ID=ED.PRIORITY_GROUP_TYPE_ID AND PG.CODE=8 "
            + "JOIN STD_ENROLLMENTPRIORSGRP egs "
            + "ON EGS.ID=ED.PRIORITY_SUB_GROUP_TYPE_ID AND (EGS.CODE=5 OR EGS.CODE=7) "
            + "JOIN Income_Test it "
            + "ON IT.PERSON_ID=P.PERSON_ID AND IT.INCOME_YEAR=2008 AND IT.PRIMARY_TEST_IND='1' "
            + "AND IT.DISCLOSE_FINANCIAL_INCOME_IND=1 AND IT.AGREED_TO_PAY_DEDUCTIBLE_IND=1";

    public final String PERSON_INCLUSION_SQL = "AND P.PERSON_ID IN (?)";

    private int delay = 30000;

    private String personInclusionList;

    private BeanFactory beanFactory;

    private Log logStatus;

    private HttpServletResponse httpServletResponse;

    private JspWriter jspWriter;

    private TimerFactory timerFactory;

    private VeteranUpdaterProcess veteranUpdaterProcess;

    public void setVeteranUpdaterProcess(
            VeteranUpdaterProcess veteranUpdaterProcess) {
        this.veteranUpdaterProcess = veteranUpdaterProcess;
    }

    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    public void setHttpServletResponse(HttpServletResponse httpServletResponse) {
        this.httpServletResponse = httpServletResponse;
    }

    public void setPersonInclusionList(String personInclusionList) {
        this.personInclusionList = personInclusionList;
    }

    public void setTimerFactory(TimerFactory timerFactory) {
        this.timerFactory = timerFactory;
    }

    public void setLogStatus(Log logStatus) {
        this.logStatus = logStatus;
    }

    public void setResponse(HttpServletResponse httpServletResponse) {
        this.httpServletResponse = httpServletResponse;
    }

    public void setJspWriter(JspWriter jspWriter) {
        this.jspWriter = jspWriter;
    }

    public void execute() {
        logStatus.info("Start");
        Timer timer = null;
        try {
            DAOOperations genericDAO = (DAOOperations) beanFactory
                    .getBean("genericDAO");

            // find all veterans in priority group 8e or 8g having
            // primary means test for income year 2008
            String queryString = FIND_VETERANS_FOR_CONVERSION_SQL;

            // if there are person ids to exclude, add them here
            if (personInclusionList != null) {
                queryString = queryString + PERSON_INCLUSION_SQL;
                queryString = queryString
                        .replaceAll("\\?", personInclusionList);
            }

            jspWriter.println("<br/><br/>Finding veterans");
            httpServletResponse.flushBuffer();
            FeedbackTask feedbackTask = new FeedbackTask(jspWriter,
                    httpServletResponse, ".");
            timer = timerFactory.scheduleTimerTask(feedbackTask, 0, delay);
            List results = genericDAO.executeSQLQuery(queryString);
            timer.cancel();
            String numberOfVeteransMessage = "Found " + results.size()
                    + " veteran(s).";
            jspWriter.println("<br/>" + numberOfVeteransMessage);
            logStatus.info(numberOfVeteransMessage);
            httpServletResponse.flushBuffer();

            // for each veteran found
            for (int i = 0; i < results.size(); i++) {
                BigDecimal personId = (BigDecimal) ((Object[]) results.get(i))[0];
                personId.setScale(0, BigDecimal.ROUND_HALF_UP);
                String vpid = (String) ((Object[]) results.get(i))[1];
                try {
                    // send to veteran updater process
                    veteranUpdaterProcess.updateVeteran(personId.toString(),
                            vpid,i);
                } catch (Exception e) {
                    if (e instanceof PersonLockedException) {

                        // if veteran is locked, log error and continue
                        String veteranLockedMessage = "Veteran with person id: "
                                + personId
                                + " and vpid: "
                                + vpid
                                + ".  Veteran is locked and cannot be updated.";
                        logStatus.error(veteranLockedMessage);
                        jspWriter.println("<br/>" + veteranLockedMessage);
                        httpServletResponse.flushBuffer();
                    } else if (e instanceof UnexpectedEnrollmentException) {

                        // if the vet is in a group other than 8b or d, this is
                        // an error and should be logged
                        String unexpectedEnrollmentGroupMessage = "Veteran with person id: "
                                + personId
                                + " and vpid: "
                                + vpid
                                + ".  Veteran not enrolled in 8b or 8d after conversion.";
                        logStatus.error(unexpectedEnrollmentGroupMessage);
                        jspWriter.println("<br/>"
                                + unexpectedEnrollmentGroupMessage);
                        httpServletResponse.flushBuffer();
                    } else if (e instanceof UnexpectedEnrollmentStatusException) {

                        // if the vet is other than verified, this is
                        // an error and should be logged
                        String unexpectedEnrollStatusMessage = "Veteran with person id: "
                                + personId
                                + " and vpid: "
                                + vpid
                                + " . Veteran status not verifed after conversion.";
                        logStatus.error(unexpectedEnrollStatusMessage);
                        jspWriter.println("<br/>"
                                + unexpectedEnrollStatusMessage);
                        httpServletResponse.flushBuffer();
                    } else {

                        // if veteran's mt income is present and financial stmt
                        // income is null, log error
                        Throwable t = e.getCause();
                        while (t != null && t.getCause() != null) {
                            t = t.getCause();
                        }
                        if (t instanceof MTTotalIncomePresentAndFinancialStmtIncomeNullException) {
                            StringBuffer veteranFinStmtIncomeNullMsg = new StringBuffer(
                                    "Veteran with person id: " + personId
                                            + " and vpid: " + vpid + ".  "
                                            + t.getMessage());

                            logStatus.error(veteranFinStmtIncomeNullMsg);
                            jspWriter.println("<br/>"
                                    + veteranFinStmtIncomeNullMsg);
                            httpServletResponse.flushBuffer();
                        } else {
                            StringBuffer unexpectedErrorMsg = new StringBuffer(
                                    "Veteran with person id: "
                                            + personId
                                            + " and vpid: "
                                            + vpid
                                            + ". Unexpected error during veteran conversion: "
                                            + e.getMessage());
                            logStatus.error(unexpectedErrorMsg, e);
                            jspWriter.println("<br/>" + unexpectedErrorMsg);
                            httpServletResponse.flushBuffer();
                        }
                    }
                }
            }
        } catch (Exception e) {
            logStatus.error("", e);
        } finally {
            try {
                jspWriter.println("<br/>Complete");
                httpServletResponse.flushBuffer();
            } catch (IOException e) {
            }
            if (timer != null) {
                timer.cancel();
            }
            logStatus.info("Complete");
        }
    }

    public void setDelay(int delay) {
        this.delay = delay;
    }
}
