package gov.nih.nci.cabig.caaers.web.ae;

import gov.nih.nci.cabig.caaers.domain.ExpeditedAdverseEventReport;
import gov.nih.nci.cabig.caaers.domain.report.Report;
import gov.nih.nci.cabig.caaers.domain.report.ReportDefinition;
import gov.nih.nci.cabig.caaers.service.EvaluationService;
import gov.nih.nci.cabig.caaers.service.ReportService;
import gov.nih.nci.cabig.caaers.web.fields.DefaultInputFieldGroup;
import gov.nih.nci.cabig.caaers.web.fields.InputFieldGroup;
import gov.nih.nci.cabig.caaers.web.fields.InputFieldFactory;
import org.springframework.beans.BeanWrapper;
import org.springframework.validation.Errors;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.servlet.http.HttpServletRequest;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * @author Rhett Sutphin
 */
public class CheckpointTab extends AeTab {
    private static final Log log = LogFactory.getLog(CheckpointTab.class);

    private EvaluationService evaluationService;
    private ReportService reportService;

    public CheckpointTab() {
        super("Is expedited reporting necessary?", "SAE?", "ae/checkpoint");
    }

    @Override
    public Map<String, InputFieldGroup> createFieldGroups(ExpeditedAdverseEventInputCommand command) {
        InputFieldGroup optional = new DefaultInputFieldGroup("optionalReports");
        for (ReportDefinition reportDefinition : command.getOptionalReportDefinitionsMap().keySet()) {
            optional.getFields().add(InputFieldFactory.createCheckboxField(
                "optionalReportDefinitionsMap[" + reportDefinition.getId() + ']',
                reportDefinition.getName()
            ));
        }

        return Collections.singletonMap(optional.getName(), optional);
    }

    @Override
    public void onDisplay(HttpServletRequest request, ExpeditedAdverseEventInputCommand command) {
        evaluationService.addRequiredReports(command.getAeReport());
        command.setOptionalReportDefinitions(createOptionalReportDefinitionsList(command));
    }

    private List<ReportDefinition> createOptionalReportDefinitionsList(ExpeditedAdverseEventInputCommand command) {
        List<ReportDefinition> all = evaluationService.applicableReportDefinitions(command.getAssignment());
        if (log.isDebugEnabled()) {
            log.debug("Applicable report defs: " + all);
        }
        for (Report report : command.getAeReport().getReports()) {
            if (report.isRequired()) {
                boolean removed = all.remove(report.getReportDefinition());
                if (log.isDebugEnabled()) {
                    if (removed) {
                        log.debug("  Removed " + report.getReportDefinition() + " from optional list because it is required");
                    } else {
                        log.debug("  Report def " + report.getReportDefinition()
                            + " is in the EAER, but is not applicable according to "
                            + evaluationService.getClass().getName());
                    }
                }
            }
        }
        if (log.isDebugEnabled()) {
            log.debug("Optional report defs: " + all);
        }
        return all;
    }

    @Override
    protected void validate(
        ExpeditedAdverseEventInputCommand command, BeanWrapper commandBean,
        Map<String, InputFieldGroup> fieldGroups, Errors errors
    ) {
        boolean anyReports = command.getAeReport().getReports().size() > 0;
        for (ReportDefinition def : command.getOptionalReportDefinitionsMap().keySet()) {
            anyReports |= optionalReportSelected(command, def);
        }
        if (!anyReports) {
            errors.reject("AT_LEAST_ONE_REPORT", "At least one expedited report must be selected to proceed");
        }
    }

    @Override
    public void postProcess(HttpServletRequest request, ExpeditedAdverseEventInputCommand command, Errors errors) {
        for (ReportDefinition def : command.getOptionalReportDefinitionsMap().keySet()) {
            if (optionalReportSelected(command, def)) {
                addOptionalReport(command.getAeReport(), def);
            } else {
                removeOptionalReport(command.getAeReport(), def);
            }
        }
        if (command.getAeReport().getReports().size() > 0) {
            command.save();
        }
    }

    private boolean optionalReportSelected(ExpeditedAdverseEventInputCommand command, ReportDefinition def) {
        Boolean val = command.getOptionalReportDefinitionsMap().get(def);
        return val == null ? false : val;
    }

    private void addOptionalReport(ExpeditedAdverseEventReport aeReport, ReportDefinition def) {
        if (findReportWithDefinition(aeReport, def) == null) {
            reportService.createReport(def, aeReport);
        }
    }

    private void removeOptionalReport(ExpeditedAdverseEventReport aeReport, ReportDefinition def) {
        // TODO: we're going to need a service method for this, too
        Report existing = findReportWithDefinition(aeReport, def);
        if (existing != null && !existing.isRequired()) {
            aeReport.getReports().remove(existing);
        }
    }

    private Report findReportWithDefinition(ExpeditedAdverseEventReport aeReport, ReportDefinition def) {
        for (Report report : aeReport.getReports()) {
            if (report.getReportDefinition().equals(def)) return report;
        }
        return null;
    }

    ////// CONFIGURATION

    public void setEvaluationService(EvaluationService evaluationService) {
        this.evaluationService = evaluationService;
    }

    public void setReportService(ReportService reportService) {
        this.reportService = reportService;
    }
}

@@ -747,16 +747,45 @@
 Request;
+%0A%0Aimport java.util.ArrayList;
 %0Aimport 
@@ -3984,24 +3984,155 @@
 s errors) %7B%0A
+%0A    %09//the list of report definitions to instantiate%0A    %09List%3CReportDefinition%3E reportDefs = new ArrayList%3CReportDefinition%3E();%0A%0A
         for 
@@ -4261,34 +4261,125 @@
 nd, def)
-) %7B%0A              
+ && (findReportWithDefinition(command.getAeReport(), def) == null)) %7B%0A                reportDefs.add(def); //
   addOpt
@@ -4382,32 +4382,41 @@
 dOptionalReport(
+command, 
 command.getAeRep
@@ -4531,32 +4531,159 @@
     %7D%0A        %7D%0A
+        if(reportDefs.size() %3E 0)%7B%0A        %09evaluationService.addOptionalReports(command.getAeReport(), reportDefs);%0A        %7D%0A
         if (comm
@@ -4997,32 +4997,66 @@
 e : val;%0A    %7D%0A%0A
+//%09 TODO: Review these changes.%0A//
     private void
@@ -5128,32 +5128,34 @@
 finition def) %7B%0A
+//
         if (find
@@ -5197,24 +5197,29 @@
  == null) %7B%0A
+//%0A//
             
@@ -5261,16 +5261,18 @@
 eport);%0A
+//
         
@@ -5265,32 +5265,34 @@
 t);%0A//        %7D%0A
+//
     %7D%0A%0A    priva
@@ -5627,16 +5627,117 @@
 sting);%0A
+            reportService.deleteReport(existing); //remove the existing report from ReportDefinition%0A
         

Update the logic of calling ReportService , for optional reports selected from UI