package org.drools.planner.examples.nurserostering.persistence;

import java.io.File;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;

import org.apache.commons.io.IOUtils;
import org.drools.planner.examples.common.business.SolutionBusiness;
import org.drools.planner.examples.nurserostering.app.NurseRosteringApp;

/**
 * @author Geoffrey De Smet
 */
public class NurseRosteringEvaluatorHelper {

    private static final String INPUT_FILE_PREFIX = "long_late04";
    private static final String OUTPUT_FILE_SUFFIX = "_feasibleInitialized";
    private static final String DEFAULT_LINE_CONTAINS_FILTER = null;

    public static void main(String[] args) {
        String lineContainsFilter;
        if (args.length > 0) {
            lineContainsFilter = args[0];
        } else {
            lineContainsFilter = DEFAULT_LINE_CONTAINS_FILTER;
        }
        NurseRosteringApp nurseRosteringApp = new NurseRosteringApp();
        SolutionBusiness solutionBusiness = nurseRosteringApp.createSolutionBusiness();
        Process process = null;
        try {
            File inputFile = new File(solutionBusiness.getImportDataDir(),
                    INPUT_FILE_PREFIX + ".xml").getCanonicalFile();
            File outputFile = new File(solutionBusiness.getExportDataDir(),
                    INPUT_FILE_PREFIX + OUTPUT_FILE_SUFFIX + ".xml").getCanonicalFile();
            File evaluatorDir = new File("local/competition/nurserostering/");
            String command = "java -jar evaluator.jar " + inputFile.getAbsolutePath()
                    + " " + outputFile.getAbsolutePath();
            process = Runtime.getRuntime().exec(command, null, evaluatorDir);
            EvaluatorSummaryFilterOutputStream out = new EvaluatorSummaryFilterOutputStream(outputFile.getName(), lineContainsFilter);
            IOUtils.copy(process.getInputStream(), out);
            IOUtils.copy(process.getErrorStream(), System.err);
            out.writeResults();
        } catch (IOException e) {
            throw new IllegalStateException(e);
        } finally {
            if (process != null) {
                process.destroy();
            }
        }
    }

    private static class EvaluatorSummaryFilterOutputStream extends OutputStream {

        private String name;
        private String lineContainsFilter;

        private StringBuilder lineBuffer = new StringBuilder(120);
        private Map<String, int[]> excessMap = new TreeMap<String, int[]>();
        private String lastEmployeeCode = null;

        private EvaluatorSummaryFilterOutputStream(String name, String lineContainsFilter) {
            super();
            this.name = name;
            this.lineContainsFilter = lineContainsFilter;
        }

        public void write(int c) throws IOException {
            if (c == '\n') {
                String line = lineBuffer.toString();
                lineBuffer.delete(0, lineBuffer.length());
                processLine(line);
            } else {
                lineBuffer.append((char) c);
            }
        }

        private void processLine(String line) {
            int employeeIndex = line.indexOf("Employee: ");
            if (employeeIndex >= 0) {
                lastEmployeeCode = line.substring(employeeIndex).replaceAll("Employee: (.+)", "$1");
            } else if (line.contains("Penalty:")) {
                lastEmployeeCode = null;
            }
            if (lineContainsFilter == null || line.contains(lineContainsFilter)) {
                int excessIndex = line.indexOf("excess = ");
                if (excessIndex >= 0) {
                    String key = line.substring(0, excessIndex);
                    int value = Integer.parseInt(line.substring(excessIndex).replaceAll("excess = (\\d+) .*", "$1"));
                    int[] excess = excessMap.get(key);
                    if (excess == null) {
                        excess = new int[]{1, value};
                        excessMap.put(key, excess);
                    } else {
                        excess[0]++;
                        excess[1] += value;
                    }
                }
                if (lastEmployeeCode != null) {
                    System.out.print("E(" + lastEmployeeCode + ")  ");
                }
                System.out.println(line);
            }
        }

        public void writeResults() {
            System.out.println("EvaluatorHelper results for " + name);
            if (lineContainsFilter != null) {
                System.out.println("with lineContainsFilter (" + lineContainsFilter + ")");
            }
            for (Map.Entry<String, int[]> entry : excessMap.entrySet()) {
                int[] excess = entry.getValue();
                System.out.println(entry.getKey() + " count = " + excess[0] + " total = " + excess[1]);
            }
        }
    }

}

@@ -83,43 +83,8 @@
 le;%0A
-import java.io.FilterOutputStream;%0A
 impo
@@ -140,40 +140,8 @@
 am;%0A
-import java.util.LinkedHashMap;%0A
 impo
@@ -2469,22 +2469,20 @@
  int%5B%5D%3E 
-excess
+cost
 Map = ne
@@ -3695,16 +3695,77 @@
 Index);%0A
+                    int costIndex = line.indexOf(%22cost = %22);%0A
         
@@ -3805,16 +3805,17 @@
 arseInt(
+(
 line.sub
@@ -3821,27 +3821,32 @@
 bstring(
-excessIndex
+costIndex) + %22 %22
 ).replac
@@ -3851,22 +3851,20 @@
 aceAll(%22
-excess
+cost
  = (%5C%5Cd+
@@ -3908,23 +3908,19 @@
 t%5B%5D 
-excess = excess
+cost = cost
 Map.
@@ -3953,22 +3953,20 @@
     if (
-excess
+cost
  == null
@@ -3993,22 +3993,20 @@
         
-excess
+cost
  = new i
@@ -4045,22 +4045,20 @@
         
-excess
+cost
 Map.put(
@@ -4062,22 +4062,20 @@
 ut(key, 
-excess
+cost
 );%0A     
@@ -4122,22 +4122,20 @@
         
-excess
+cost
 %5B0%5D++;%0A 
@@ -4157,22 +4157,20 @@
         
-excess
+cost
 %5B1%5D += v
@@ -4523,24 +4523,56 @@
  %22 + name);%0A
+            int grandTotal = 0;%0A
             
@@ -4761,22 +4761,20 @@
 entry : 
-excess
+cost
 Map.entr
@@ -4805,22 +4805,20 @@
   int%5B%5D 
-excess
+cost
  = entry
@@ -4826,24 +4826,63 @@
 getValue();%0A
+                grandTotal += cost%5B1%5D;%0A
             
@@ -4935,22 +4935,20 @@
 t = %22 + 
-excess
+cost
 %5B0%5D + %22 
@@ -4959,22 +4959,20 @@
 l = %22 + 
-excess
+cost
 %5B1%5D);%0A  
@@ -4975,32 +4975,94 @@
 ;%0A            %7D%0A
+            System.out.println(%22Grand total: %22 + grandTotal);%0A
         %7D%0A    %7D%0A

update to new evaluator