
package de.ivu.elect.wus.exchange.gebietsbaum;

import static java.util.Objects.nonNull;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.Nullable;
import javax.inject.Inject;

import org.apache.commons.lang3.StringUtils;

import de.ivu.elect.business.datei.entity.FileType;
import de.ivu.elect.business.exchange.control.FileFormat;
import de.ivu.elect.business.exchange.control.FileKonfiguration;
import de.ivu.elect.business.gebietsbaum.boundary.GebietFactory;
import de.ivu.elect.business.gebietsbaum.boundary.GebietsartTemplate;
import de.ivu.elect.business.gebietsbaum.control.Gebietsbaum;
import de.ivu.elect.business.gebietsbaum.control.StimmbezirkGebietsarten;
import de.ivu.elect.business.gebietsbaum.control.StimmbezirkGebietsbaumExchangeContext;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.wahl.boundary.WahlFactory;
import de.ivu.elect.exchange.CsvImportMapper;
import de.ivu.elect.exchange.csv.CsvMarshaller;
import de.ivu.elect.exchange.gebietsbaum.GebietDTO;
import de.ivu.elect.exchange.gebietsbaum.csv.DefaultGebietsbaumCsvImportMapper;
import de.ivu.elect.jee.exchange.Violations;
import de.ivu.elect.jee.faces.Messages;

public abstract class AbstractCoreGebietsbaumStimmbezirkeCsvImportMapper<T extends GebietDTO>
    implements
      GebietsbaumStimmbezirkImportMapper,
      CsvImportMapper<Gebietsbaum, StimmbezirkGebietsbaumExchangeContext> {

  public static final String FILE_FORMAT_NAME = "file.format.gebietsbaum.stimmbezirke.wus";

  public static final FileFormat FILE_FORMAT = new FileFormat(FILE_FORMAT_NAME, FileType.CSV);

  @Inject
  protected transient WahlFactory wahlFactory;

  @Inject
  protected transient GebietFactory gebietFactory;

  @Inject
  protected transient CsvMarshaller csvMarshaller;

  @Inject
  protected transient Messages messages;

  @Inject
  protected transient StimmbezirkGebietsarten stimmbezirkGebietsarten;

  @Inject
  protected transient DefaultGebietsbaumCsvImportMapper defaultGebietsbaumCsvImportMapper;

  public AbstractCoreGebietsbaumStimmbezirkeCsvImportMapper() {
    super();
  }

  @Override
  public boolean isAcceptContext(StimmbezirkGebietsbaumExchangeContext context) {
    return true;
  }

  @Override
  public FileFormat getFileFormat() {
    return FILE_FORMAT;
  }

  @Override
  public Gebietsbaum deserialize(InputStream is, StimmbezirkGebietsbaumExchangeContext context, FileKonfiguration fileKonfiguration) {
    return new Gebietsbaum(wahlFactory.create(), mappeGebieteToElect(getCsvMarshaller().deserialize(getDtoClass(), is, fileKonfiguration), context));
  }

  @Override
  public List<String> getCsvColumnHeaders(StimmbezirkGebietsbaumExchangeContext context) {
    return getCsvMarshaller().extractHeader(getDtoClass());
  }

  private List<Gebiet> mappeGebieteToElect(List<T> deserialize, StimmbezirkGebietsbaumExchangeContext context) {
    List<Gebiet> result = new ArrayList<>();

    long position = 1L;

    Gebiet wurzelgebiet = findeWurzelgebiet(context, deserialize);

    for (T gebietCsv : deserialize) {
      if (isStimmbezirkGebiet(context, gebietCsv)) {
        Gebiet gebiet = defaultGebietsbaumCsvImportMapper.createGebiet(context, gebietCsv);

        gebiet.setPosition(position);

        setzeUebergeordnetesGebiet(context, gebiet, gebietCsv, wurzelgebiet);

        result.add(gebiet);
        position = position + 1L;
      }
    }

    return result;
  }

  @Nullable
  protected Gebiet findeWurzelgebiet(StimmbezirkGebietsbaumExchangeContext context, List<T> deserialize) {
    for (T t : deserialize) {
      if (StringUtils.isEmpty(t.getUebergeordnetesGebietGebietsartName()) && StringUtils.isEmpty(t.getUebergeordnetesGebietNummer())) {
        return defaultGebietsbaumCsvImportMapper.createGebiet(context, t);
      }
    }

    return null;
  }

  protected abstract void setzeUebergeordnetesGebiet(StimmbezirkGebietsbaumExchangeContext context, Gebiet gebiet, T gebietCsv, @Nullable Gebiet wurzelgebiet);

  protected boolean isStimmbezirkGebiet(StimmbezirkGebietsbaumExchangeContext context, T gebietCsv) {
    if (context.isNurStimmbezirke()) {
      String gebietsartName = gebietCsv.getGebietsartName();

      GebietsartTemplate gebietsartTemplateForStimmbezirke = stimmbezirkGebietsarten.getGebietsartTemplateForStimmbezirke(context.getMandant());
      GebietsartTemplate gebietsartTemplateForBriefwahlbezirke = stimmbezirkGebietsarten.getGebietsartTemplateForBriefwahlbezirke(context.getMandant());

      return nonNull(gebietsartTemplateForStimmbezirke) && gebietsartTemplateForStimmbezirke.equalsGebietsart(gebietsartName)
          || nonNull(gebietsartTemplateForBriefwahlbezirke) && gebietsartTemplateForBriefwahlbezirke.equalsGebietsart(gebietsartName);
    }

    return true;
  }

  @Override
  public Violations validateInputFormat(InputStream is, StimmbezirkGebietsbaumExchangeContext context, FileKonfiguration fileKonfiguration) {
    return new Violations();
  }

  protected CsvMarshaller getCsvMarshaller() {
    return csvMarshaller;
  }

  protected abstract Class<T> getDtoClass();

  protected Gebiet createGebiet() {
    return gebietFactory.create();
  }
}
