/*
 * Copyright 2016 Red Hat, Inc. and/or its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.optaplanner.training.election.app;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.optaplanner.core.api.solver.SolverFactory;
import org.optaplanner.training.election.domain.Election;
import org.optaplanner.training.election.domain.FederalState;

public class ElectionApp {

    public static void main(String[] args) {
        Election election = readElection();
        SolverFactory<Election> solverFactory = SolverFactory.createFromXmlResource(
                "org/optaplanner/training/election/solver/electionSolverConfig.xml");
        election = solverFactory.buildSolver().solve(election);
        printElection(election);
    }

    private static void printElection(Election election) {
        System.out.println("Election");
        System.out.println("========");

        List<FederalState> federalStateList = election.getFederalStateList();
        int populationTotal = federalStateList.stream().mapToInt(FederalState::getPopulation).sum();
        federalStateList.stream()
                .filter((federalState) -> Election.BAD_CANDIDATE.equals(federalState.getWinningCandidate()))
                .sorted(Comparator.comparing(FederalState::getElectoralVotes)
                        .thenComparing(FederalState::getPopulation).reversed())
                .forEach((federalState) -> System.out.printf(
                        "Win %2d electoral votes in %-20s. Bribe %,10d citizens there.\n",
                        federalState.getElectoralVotes(),
                        federalState.getName(),
                        federalState.getMinimumMajorityPopulation()));

        System.out.println("");
        int bribeMinimumPopulation = federalStateList.stream()
                .filter((federalState) -> Election.BAD_CANDIDATE.equals(federalState.getWinningCandidate()))
                .mapToInt(FederalState::getMinimumMajorityPopulation).sum();
        double percentage = bribeMinimumPopulation * 100.0 / populationTotal;
        System.out.printf("Bribe %.2f%% of the US population to become president (even if all citizens votes).\n", percentage);
    }

    private static Election readElection() {
        Path inputFile = Paths.get("data/election/import/president2016.txt");
        try (Stream<String> stream = Files.lines(inputFile)) {
            List<FederalState> federalStateList = stream
                    .filter((line) -> !line.isEmpty() && !line.startsWith("#"))
                    .map((line) -> {
                        String[] tokens = line.split(",");
                        if (tokens.length != 3) {
                            throw new IllegalStateException("The line (" + line + ") does not have 3 tokens.");
                        }
                        return new FederalState(tokens[0], Integer.parseInt(tokens[1]), Integer.parseInt(tokens[2]));
                    }).collect(Collectors.toList());
            return new Election(federalStateList);
        } catch (IOException | NumberFormatException e) {
            throw new IllegalStateException("Reading inputFile (" + inputFile + ") failed.", e);
        }

    }

}

@@ -1684,109 +1684,8 @@
 ();%0A
-        int populationTotal = federalStateList.stream().mapToInt(FederalState::getPopulation).sum();%0A
     
@@ -1972,19 +1972,8 @@
 ion)
-.reversed()
 )%0A  
@@ -2061,72 +2061,104 @@
    %22
-Win %252d electoral
+%25-20s %253d EC: %25,11d of %25,11d
  vote
+r
 s 
-in %25-20s. Bribe %25,10d citizens there.%5Cn%22
+(%25.2f%25%25).%5Cn%22,%0A                        federalState.getName()
 ,%0A  
@@ -2245,36 +2245,111 @@
 federalState.get
-Name
+MinimumMajorityPopulation(),%0A                        federalState.getPopulation
 (),%0A            
@@ -2403,16 +2403,55 @@
 lation()
+ * 100.0 / federalState.getPopulation()
 ));%0A%0A   
@@ -2491,22 +2491,247 @@
     int 
-bribeM
+electoralVotes = federalStateList.stream()%0A                .filter((federalState) -%3E Election.BAD_CANDIDATE.equals(federalState.getWinningCandidate()))%0A                .mapToInt(FederalState::getElectoralVotes).sum();%0A        int m
 inimumPo
@@ -2965,62 +2965,83 @@
     
-double percentage = bribeMinimumPopulation * 100.0 / p
+int populationTotal = federalStateList.stream().mapToInt(FederalState::getP
 opul
@@ -3045,21 +3045,23 @@
 pulation
-Total
+).sum()
 ;%0A      
@@ -3084,107 +3084,260 @@
 ntf(
-%22Bribe %25.2f%25%25 of the US population to become president (even if all citizens votes).%5Cn%22, percentage
+%0A                %22%25-20s %253d EC: %25,11d of %25,11d voters (%25.2f%25%25).%5Cn%22,%0A                %22TOTAL%22,%0A                electoralVotes,%0A                minimumPopulation,%0A                populationTotal,%0A                minimumPopulation * 100.0 / populationTotal
 );%0A 

improve print method