package no.valg.valgnatt.backend.mandatberegning.prognose;

import java.math.BigDecimal;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import no.valg.valgnatt.backend.mandatberegning.domene.Kvotient;
import no.valg.valgnatt.database.Konstanter;
import no.valg.valgnatt.database.geografi.Kommune;
import no.valg.valgnatt.database.geografi.Land;
import no.valg.valgnatt.database.geografi.Område;

/**
 * Created by msi on 21-Dec-16.
 * Vekt-klassen håndterer å beregne vekting av forskjellige prognoser og slå sammen prognoser basert på vekten
 */
class Vekt {

	private Vekt() {
	}

	/**
	 * MSI jun 2016:
	 * Skal finne vekten som skal gis til område 1 basert på antall frammøtte i områdene.
	 */
	public static BigDecimal beregnFrammøteVekt(Område område, Set<String> kommnrOmråde1, Set<String> kommnrOmråde2) {
		BigDecimal vekt1 = finnVekt(kommnrOmråde1, område);
		BigDecimal vekt2 = finnVekt(kommnrOmråde2, område);
		return vekt1.divide(vekt1.add(vekt2), Konstanter.MAKS_PRESISJON, BigDecimal.ROUND_HALF_UP);
	}

	private static BigDecimal finnVekt(Set<String> kommnrIOmråde, Område område) {
		BigDecimal antallFremmøte = BigDecimal.ZERO;
		for (String kommnr : kommnrIOmråde) {
			Land land = område.getClass() == Land.class ? (Land) område : område.getLand();
			Kommune kommune = land.getKommune(kommnr);
			Float fremmøte = kommune.beregnFrammoteProsentIaar();
			if (fremmøte == null) {
				fremmøte = område.beregnFrammoteProsentIaar();
			}
			if (fremmøte == null) {
				fremmøte = Konstanter.DEFAULT_FRAMMØTE_PROSENT;
			}
			antallFremmøte = antallFremmøte.add(new BigDecimal(fremmøte).multiply(new BigDecimal(kommune.getAntallStemmeberettigede())));
		}
		return antallFremmøte;
	}

	/**
	 * MSI jun 2016:
	 * Metoden slår sammen prognose1 og prognose2 basert på prognose1Vekt. Dersom det finnes partier som bare finnes i prognose1 eller
	 * prognose2, så brukes disse andelen direkte (uten vekting).
	 */
	static Map<String, Kvotient> slåSammenPrognoser(Map<String, Kvotient> prognose1, Map<String, Kvotient> prognose2, BigDecimal prognose1Vekt) {

		Map<String, Kvotient> prognose = new TreeMap<>();
		BigDecimal prognose2Vekt = BigDecimal.ONE.subtract(prognose1Vekt);
		for (String partikode : prognose1.keySet()) {
			if (prognose2.get(partikode) == null) {
				prognose.put(partikode, new Kvotient(prognose1.get(partikode).getKvotient().multiply(prognose1Vekt)));
			} else {

				prognose.put(partikode, prognose1.get(partikode).multiply(prognose1Vekt).add(prognose2.get(partikode).multiply(prognose2Vekt)));
			}
		}
		for (String partikode : prognose2.keySet()) {
			prognose.computeIfAbsent(partikode, k -> new Kvotient(prognose2.get(partikode).getKvotient().multiply(prognose2Vekt)));
		}
		return Diverse.fordelAndelerPåHundreProsent(prognose);
	}
}
