package no.valg.valgnatt.backend.eksport;

import java.io.IOException;

import no.valg.valgnatt.backend.rapport.JsonObjectWrapper;
import no.valg.valgnatt.database.GrunnlagsdataCache;
import no.valg.valgnatt.database.Konstanter;
import no.valg.valgnatt.database.domene.SkjemaType;
import no.valg.valgnatt.database.domene.ValgType;
import no.valg.valgnatt.database.geografi.Fylke;
import no.valg.valgnatt.database.geografi.Kommune;
import no.valg.valgnatt.database.geografi.Land;
import no.valg.valgnatt.database.geografi.LandInndeling;
import no.valg.valgnatt.database.geografi.PartiMandater;
import no.valg.valgnatt.database.hibernate.Kandidat;
import no.valg.valgnatt.database.hibernate.Stemmekrets;
import no.valg.valgnatt.database.hibernate.Valgdistrikt;

import com.google.gson.JsonArray;

/**
 * MSI jan 2016:
 * Denne klassen (og pakken) brukes for å kunne eksportere grunnlagsdata *på samme måte* som EVA Admin.
 * Av dette så kan følgende avledes:
 * 1. Klassen/pakken har ingen betydning for runtime-kjøring av Valgnatt!
 * 2. Valgnatt får i prinsippet alle sine eksporter fra EVA Admin, så dette som gjøres her er noe som
 * gjøres når EVA Admin av en eller annen grunn ikke kan levere slike eksporter.
 * 3. Man kan ikke eksportere grunnlagsdata før man har fått importert det, så hva skal da være vitsen
 * med å lage en slik funksjon?
 * <p/>
 * Svaret på 2 og 3 er at EVA Admin ikke kan levere eksporter for gamle valg. For Valgnatt er det viktig
 * å kunne kjøre gamle valg (av flere grunner: testing, retting av resultater (grunnet bugs) i gamle valg).
 * Når så EVA Admin endret sitt eksportgrensesnitt (våren 2016) så var det nødvendig å oppgradere de
 * gamle eksportfilene for gamle valg. Det gjøres enklest på denne måten. På den måten vil alle valg
 * fremstå like i hvordan de opprettes, og man kan også kjøre ForberedValg (se valg_utils) for et gammelt
 * valg og dermed sjekke at denne koden også fungerer for flere typer valg.
 */
public class Eksport {

	public static void eksportValgdistrikterPartierOgKandidater(GrunnlagsdataCache grunnlagsdataCache) throws IOException {
		for (ValgType valgType : grunnlagsdataCache.getValgTyper()) {
			EksportSkjema skjema = new EksportSkjema(SkjemaType.GRUNNLAG_VALGDISTRIKTER_PARTIER_KANDIDATER.kode, valgType, grunnlagsdataCache.getValgAar());
			JsonObjectWrapper skjemaInnhold = skjema.getSkjemaInnhold();
			Land land = grunnlagsdataCache.getLand(valgType);
			if (valgType == ValgType.FY || valgType == ValgType.ST) {
				skjemaInnhold.leggTilTall("antall_utjevningsmandater", land.getFylker().size() * Konstanter.UTJEVNINGSMANDATER_PR_FYLKE);
			} else {
				skjemaInnhold.leggTilTall("antall_utjevningsmandater", 0);
			}
			JsonArray valgdistrikter = skjemaInnhold.leggTilTabell("valgdistrikter");

			for (LandInndeling fylke : valgType == ValgType.SA ? land.getSamevalgdistrikter().values() : land.getFylker().values()) {
				if (valgType == ValgType.FY && fylke.getNr().equals(Konstanter.OSLO_FNR)) {
					continue; // For at eksporten skal bli lik den som kommer fra EVA Admin, så tar vi ikke med Oslo i FY-valg
				}
				for (Valgdistrikt valgdistrikt : fylke.getValgdistrikter().values()) {
					JsonObjectWrapper valgdistriktJOW = new JsonObjectWrapper();
					valgdistrikter.add(valgdistriktJOW.getJsonObject());
					valgdistriktJOW.leggTilString("valgdistrikt", valgdistrikt.getId().getNr());
					valgdistriktJOW.leggTilString("navn", valgdistrikt.getNavn());
					valgdistriktJOW.leggTilTall("antall_mandater", valgdistrikt.getAntallmandater());
					leggTilPartier(grunnlagsdataCache, valgType, valgdistrikt, valgdistriktJOW);
				}
			}
			skjema.skrivTilFil();
		}
	}

	private static void leggTilPartier(GrunnlagsdataCache grunnlagsdataCache, ValgType valgType, Valgdistrikt valgdistrikt, JsonObjectWrapper valgdistriktJOW) {
		JsonArray partier = valgdistriktJOW.leggTilTabell("partier");
		for (PartiMandater pm : valgdistrikt.getPartiMandater()) {
			if (!pm.isStillerliste()) {
				continue;
			}
			JsonObjectWrapper partiJOW = new JsonObjectWrapper();
			partier.add(partiJOW.getJsonObject());
			partiJOW.leggTilString("partikode", pm.getPartikode());
			partiJOW.leggTilString("partinavn", pm.getPartinavn());
			if (pm.getPartikode().equals(Konstanter.BLANKE)) {
				partiJOW.leggTilString("partikategori", ""); // Partiet har egentlig ikke en partikategori sett fra Admin
			} else {
				partiJOW.leggTilString("partikategori", "" + grunnlagsdataCache.getPartiliste(valgType, pm.getPartikode()).getPartikategori());
			}
			if (!pm.getKandidater().isEmpty()) {
				leggTilKandidater(pm, partiJOW);
			}
		}
	}

	private static void leggTilKandidater(PartiMandater pm, JsonObjectWrapper partiJOW) {
		JsonArray kandidater = partiJOW.leggTilTabell("kandidater");
		for (Kandidat kandidat : pm.getKandidater()) {
			JsonObjectWrapper kandidatJOW = new JsonObjectWrapper();
			kandidater.add(kandidatJOW.getJsonObject());
			kandidatJOW.leggTilTall("plassnummer", kandidat.getId().getPlassnr());
			kandidatJOW.leggTilString("navn", kandidat.getNavn());
			kandidatJOW.leggTilString("fødselsdato", kandidat.getFodselsdato());
			kandidatJOW.leggTilString("bosted", kandidat.getBosted() == null ? "" : kandidat.getBosted());
			kandidatJOW.leggTilString("kjønn", kandidat.getKjonn().name());
		}
	}

	public static void eksporterStemmekretser(GrunnlagsdataCache grunnlagsdataCache) throws IOException {
		for (ValgType valgType : grunnlagsdataCache.getValgTyper()) {
			Fylke osloFylke = null;
			if (valgType == ValgType.FY) {
				// For at eksporten skal bli lik den som kommer fra EVA Admin, så tar vi ikke med Oslo i FY-valg,
				// det blir derfor noe spesialbehandling i eksporten her for å fjerne Oslo på korrekt måte
				osloFylke = grunnlagsdataCache.getFylke(valgType, Konstanter.OSLO_FNR);
			}
			EksportSkjema skjema = new EksportSkjema(SkjemaType.GRUNNLAG_STEMMEKRETSER.kode, valgType, grunnlagsdataCache.getValgAar());
			JsonObjectWrapper skjemaInnhold = skjema.getSkjemaInnhold();
			Land land = grunnlagsdataCache.getLand(valgType);
			skjemaInnhold.leggTilTall("stemmeberettigede", valgType == ValgType.FY ? land.getAntallStemmeberettigede(null) - osloFylke.getAntallStemmeberettigede() :
					land.getAntallStemmeberettigede());
			JsonArray fylker = skjemaInnhold.leggTilTabell("fylker");
			for (LandInndeling fylke : valgType == ValgType.SA ? land.getSamevalgdistrikter().values() : land.getFylker().values()) {
				if (valgType == ValgType.FY && fylke.getNr().equals(Konstanter.OSLO_FNR)) {
					continue;
				}
				JsonObjectWrapper fylkeJOW = new JsonObjectWrapper();
				fylker.add(fylkeJOW.getJsonObject());
				fylkeJOW.leggTilString("fylkesnummer", fylke.getNr());
				fylkeJOW.leggTilString("fylke", fylke.getNavn());
				fylkeJOW.leggTilTall("stemmeberettigede", fylke.getAntallStemmeberettigede());
				JsonArray kommuner = fylkeJOW.leggTilTabell("kommuner");
				for (Kommune kommune : fylke.getKommuner().values()) {
					leggTilKommune(kommuner, kommune);
				}
			}
			skjema.skrivTilFil();
		}
	}

	private static void leggTilKommune(JsonArray kommuner, Kommune kommune) {
		JsonObjectWrapper kommuneJOW = new JsonObjectWrapper();
		kommuner.add(kommuneJOW.getJsonObject());
		kommuneJOW.leggTilString("kommunenummer", kommune.getNr());
		kommuneJOW.leggTilString("kommune", kommune.getNavn());
		kommuneJOW.leggTilTall("stemmeberettigede", kommune.getAntallStemmeberettigede());
		kommuneJOW.leggTilString("valgdistrikt", kommune.getValgdistrikt().getId().getNr());
		JsonArray stemmekretser = kommuneJOW.leggTilTabell("kretser");
		for (Stemmekrets stemmekrets : kommune.getStemmekretser().values()) {
			leggTilStemmekrets(kommune, stemmekretser, stemmekrets);
		}
	}

	private static void leggTilStemmekrets(Kommune kommune, JsonArray stemmekretser, Stemmekrets stemmekrets) {
		JsonObjectWrapper stemmekretsJOW = new JsonObjectWrapper();
		stemmekretser.add(stemmekretsJOW.getJsonObject());
		stemmekretsJOW.leggTilString("kretsnummer", stemmekrets.getId().getKretsnr());
		String kretsnavn = stemmekrets.getId().getKretsnr().equals(Konstanter.DEFAULT_KRETS) ? "Hele kommunen" : stemmekrets.getKretsnavn();
		stemmekretsJOW.leggTilString("kretsnavn", kretsnavn);
		stemmekretsJOW.leggTilTall("stemmeberettigede", stemmekrets.getStemmeberettigede());
		if (stemmekrets.getBydelnr() == null || "0".equals(stemmekrets.getBydelnr())) {
			stemmekretsJOW.leggTilString("bydelsnummer", kommune.getNr() + "00");
			stemmekretsJOW.leggTilString("bydelsnavn", "Hele kommunen");
		} else { // ordentlige bydeler (finnes bare i Oslo):
			String bydelnr = stemmekrets.getBydelnr();
			stemmekretsJOW.leggTilString("bydelsnummer", kommune.getNr() + (bydelnr.length() < 2 ? "0" + bydelnr : bydelnr));
			stemmekretsJOW.leggTilString("bydelsnavn", stemmekrets.getKommune().getBydel(bydelnr).getNavn());
		}
	}
}
