
package de.ivu.elect.presentation;

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

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.ivu.elect.business.benutzerverwaltung.control.PrincipalBenutzerParameterLoader;
import de.ivu.elect.business.benutzerverwaltung.entity.Benutzer;
import de.ivu.elect.business.benutzerverwaltung.entity.BenutzerEditorButtonEinstellung;
import de.ivu.elect.business.benutzerverwaltung.entity.BenutzerEinsatzort;
import de.ivu.elect.business.benutzerverwaltung.entity.BenutzerParameterWerte;
import de.ivu.elect.business.gebietsbaum.boundary.GebietSessionSelect;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.mandant.entity.Mandant;
import de.ivu.elect.business.security.UseCasePermission;
import de.ivu.elect.business.security.control.ElectCommonPrincipal;
import de.ivu.elect.business.wahl.boundary.WahlSessionSelector;
import de.ivu.elect.business.wahl.boundary.WahlterminSessionSelect;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.business.wahl.entity.Wahltermin;
import de.ivu.elect.jee.entity.Entity;
import de.ivu.elect.jee.presentation.dynamicform.AdvancedDynaFormModel;
import de.ivu.elect.jee.presentation.dynamicform.DynamicFormEditOrCreateView;
import de.ivu.elect.jee.presentation.dynamicform.FormBuilder;
import de.ivu.elect.jee.presentation.redirect.Redirect;
import de.ivu.elect.jee.presentation.security.StartViewResolver;
import de.ivu.elect.jee.presentation.view.AbstractView;
import de.ivu.elect.presentation.gebietsbaum.GebietNummerFormatter;
import de.ivu.elect.presentation.mandant.MandantSessionSelect;
import de.ivu.elect.presentation.security.BearbeitenGebietSecurity;
import de.ivu.elect.presentation.security.EinsehenGebietSecurity;
import de.ivu.elect.presentation.security.GebietSecurity;
import de.ivu.elect.presentation.security.SperrmerkmalSecurity;
import de.ivu.elect.presentation.table.AbstractColumnEntry;


import static java.util.Objects.isNull;
import static org.apache.commons.lang3.StringUtils.defaultString;

// ELECT-3505 - Wahl(art)- und gebietsabhängiges Rechtekonzept umsetzen
public abstract class AbstractElectEditView<T extends Entity<?, ?>> extends AbstractView implements DynamicFormEditOrCreateView {

  private static final String STYLE_CLASS_BUTTONS_FIXIEREN = "buttons-fixieren";

  private static final long serialVersionUID = 1L;

  private static final Logger LOG = LoggerFactory.getLogger(AbstractElectEditView.class);

  @Inject
  protected transient ElectCommonPrincipal principal;

  @Inject
  protected transient GebietSecurity gebietSecurity;

  @Inject
  protected transient SperrmerkmalSecurity sperrmerkmalSecurity;

  @Inject
  protected transient StartViewResolver startViewResolver;

  @Inject
  protected transient WahlterminSessionSelect wahlterminSessionSelect;

  @Inject
  protected transient WahlSessionSelector wahlSessionSelector;

  @Inject
  protected transient GebietSessionSelect gebietSessionSelect;

  @Inject
  protected transient GebietNummerFormatter gebietNummerFormatter;

  @Inject
  protected transient MandantSessionSelect mandantSessionSelect;

  @Inject
  protected transient PrincipalBenutzerParameterLoader benutzerParameterLoader;

  private AdvancedDynaFormModel model;

  private String sperrmerkmalStyleClass;

  protected AbstractElectEditView() {
    super();
  }

  @Nullable
  protected Benutzer getSelectedBenutzer() {
    return getPrincipal().getLogin();
  }

  protected String getSelectedBenutzerKennung() {
    return getPrincipal().getBenutzerKennung();
  }

  @Nullable
  protected BenutzerEinsatzort getSelectedBenutzerEinsatzort() {
    return getPrincipal().getBenutzerEinsatzort();
  }

  protected String getSelectedBenutzerNameFormatted() {
    return getPrincipal().getFormattedName();
  }

  protected boolean hasPermission(UseCasePermission permission) {
    return getPrincipal().hasUseCasePermission(permission);
  }

  protected ElectCommonPrincipal getPrincipal() {
    return principal;
  }

  protected BearbeitenGebietSecurity getBearbeitenGebietSecurity() {
    return gebietSecurity.getBearbeitenGebietSecurity();
  }

  protected EinsehenGebietSecurity getEinsehenGebietSecurity() {
    return gebietSecurity.getEinsehenGebietSecurity();
  }

  protected String getStartViewId() {
    return startViewResolver.getStartViewId();
  }

  protected boolean isWahlterminSelected() {
    return wahlterminSessionSelect.isSelected();
  }

  protected Wahltermin getSelectedWahltermin() {
    return wahlterminSessionSelect.getEntity();
  }

  protected boolean isWahlSelected() {
    return wahlSessionSelector.isSelected();
  }

  protected Wahl getSelectedWahl() {
    return wahlSessionSelector.getEntity();
  }

  protected boolean isGebietSelected() {
    return gebietSessionSelect.isSelected();
  }

  protected Gebiet getSelectedGebiet() {
    return gebietSessionSelect.getEntity();
  }

  protected String getSelectedGebietNameFormatted() {
    return formatGebietName(getSelectedGebiet());
  }

  protected String formatGebietName(Gebiet gebiet) {
    return gebietNummerFormatter.getDarstellung(gebiet);
  }

  protected abstract T getEntity();

  protected void resetModel() {
    model = null;
  }

  @Override
  public AdvancedDynaFormModel getModel() {
    if (isNull(model)) {
      FormBuilder formBuilder = createFormBuilder();

      T entity = getEntity();

      if (isNull(entity)) {
        warnNoEntitySet();
      } else {
        addProperties(formBuilder, entity);

        if (isGebietBearbeitenRechtPruefen()) {
          checkGebietBearbeitenRecht(formBuilder, entity);
        }
      }

      model = formBuilder.createModel();
    }

    return model;
  }

  protected void warnNoEntitySet() {
    LOG.info("Entity ist null " + toString());
  }

  protected abstract void addProperties(FormBuilder formBuilder, T entity);

  protected void checkGebietBearbeitenRecht(FormBuilder formBuilder, T entity) {
    if (!isRechtZumBearbeitenAufGebietVorhanden(entity)) {
      formBuilder.globalReadonly();
    }
  }

  protected boolean isRechtZumBearbeitenAufGebietVorhanden(T entity) {
    return getBearbeitenGebietSecurity().isRechtVorhanden(entity);
  }

  @Redirect
  public abstract String delete();

  @Nullable
  @Override
  @Redirect
  public String reset() {
    resetModel();

    return null;
  }

  /**
   * ELECT-3505 - Wahl(art)- und gebietsabhängiges Rechtekonzept umsetzen
   */
  protected abstract boolean isGebietBearbeitenRechtPruefen();

  @Override
  public boolean isBtnResetRendered() {
    return isGebietBearbeitenErlaubt();
  }

  protected boolean isGebietBearbeitenErlaubt() {
    return !isGebietBearbeitenRechtPruefen() || isRechtZumBearbeitenAufGebietVorhanden(getEntity());
  }

  @Override
  public String getBtnSaveLabel() {
    return getMessage("entity.edit.action.save");
  }

  @Override
  public boolean isBtnSaveRendered() {
    return isSavePermissionVorhanden() && isGebietBearbeitenErlaubt();
  }

  protected abstract boolean isSavePermissionVorhanden();

  @Override
  public String getStyleClass() {
    String result = super.getStyleClass();

    if (sperrmerkmalSecurity.isSperreVorhandenUndHervorzuheben(getEntity())) {
      result += " " + getSperrmerkmalStyleClass();
    }

    if (isButtonsPositionFixieren()) {
      result += " " + STYLE_CLASS_BUTTONS_FIXIEREN;
    }

    return result;
  }

  private String getSperrmerkmalStyleClass() {
    if (sperrmerkmalStyleClass == null) {
      sperrmerkmalStyleClass = defaultString(getMessage(AbstractColumnEntry.MSG_KEY_SPERRMERKMAL_STYLE_CLASS), "");
    }

    return sperrmerkmalStyleClass;
  }

  @Override
  public boolean isBtnShowAllFormFieldsRendered() {
    return super.isBtnShowAllFormFieldsRendered() || getModel().isAnyPropertyHiddenOnPageLoad();
  }

  protected Mandant getMandant() {
    return mandantSessionSelect.getMandant();
  }

  /**
   * Fixiert die Formular-Buttons unten immer sichtbar. Default-Wert: <code>false</code>
   */
  protected boolean isButtonsPositionFixieren() {
    BenutzerEditorButtonEinstellung benutzerEditorButtonEinstellung = benutzerParameterLoader.resolveEnumValue(
        BenutzerParameterWerte.EDITOR_BUTTON_SICHTBARKEIT, BenutzerEditorButtonEinstellung.class);
    return benutzerEditorButtonEinstellung != null && benutzerEditorButtonEinstellung.isFixiert();
  }
}
