/*
 * CandidatesCounter
 *
 * Created on 19.12.2008 Copyright (c) 2008 Kiesraad
 */

package de.ivu.wahl.result.determination;

import de.ivu.wahl.result.Candidate;
import de.ivu.wahl.result.CandidateList;
import de.ivu.wahl.result.ElectionAndCandidates;
import de.ivu.wahl.result.Util;
import de.ivu.wahl.result.i18n.MessageKeys;
import de.ivu.wahl.result.i18n.Messages;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * The CandidatesCounter keeps track of the number of candidates of a list, that may receive a seat. "List" stand for
 * either of candidate list, P3-list or P42-list.
 *
 * @author , IVU Traffic Technologies AG
 */
class CandidatesCounter {

  private final Map<CandidateList, Long> _candidatesPerList;
  private final Map<P2List, Long> _candidatesPerP2List;
  private final Map<P3List, Long> _candidatesPerP3List;

  /**
   * Constructor for a CandidatesCounter for the normal seat distribution
   */
  public CandidatesCounter(ElectionAndCandidates electionAndCandidates, Collection<P3List> p3Lists) {
    Map<CandidateList, Long> candidatesPerList = new HashMap<>();
    Map<P2List, Long> candidatesPerP2List = new HashMap<>();
    Map<P3List, Long> candidatesPerP3List = new HashMap<>();

    for (P3List p3List : p3Lists) {
      Set<Candidate> p3Candidates = new HashSet<>();
      for (P2List p2List : p3List.getP2Lists()) {
        Set<Candidate> p2Candidates = new HashSet<>();
        for (CandidateList candidateList : p2List.getCandidateLists()) {
          Set<Candidate> candidates = new HashSet<>(candidateList.getCandidates());
          candidates.removeAll(electionAndCandidates.getDeceasedCandidates());

          p2Candidates.addAll(candidates);
          p3Candidates.addAll(candidates);
          candidatesPerList.put(candidateList, Long.valueOf(candidates.size()));
        }
        candidatesPerP2List.put(p2List, Long.valueOf(p2Candidates.size()));
      }
      candidatesPerP3List.put(p3List, Long.valueOf(p3Candidates.size()));
    }

    this._candidatesPerList = Util.createUnmodifiableCopy(candidatesPerList);
    this._candidatesPerP2List = Util.createUnmodifiableCopy(candidatesPerP2List);
    this._candidatesPerP3List = Util.createUnmodifiableCopy(candidatesPerP3List);
  }

  public long getNumberOfListedCandidates(CandidateList candidateList) {
    Long result = _candidatesPerList.get(candidateList);
    assert result != null : Messages.bind(MessageKeys.Builder_Assert_NoNumberOfCandidatesStoredFoCandidateList_0,
            candidateList);
    return result;
  }

  /**
   * @return an unmodifiable Map of P2 lists (key) and their respective number of candidates (value)
   */
  public Map<P2List, Long> getCandidatesPerP2List() {
    return _candidatesPerP2List;
  }

  /**
   * @return an unmodifiable Map of P3 lists (key) and their respective number of candidates (value)
   */
  public Map<P3List, Long> getCandidatesPerP3List() {
    return _candidatesPerP3List;
  }

}
