
package de.ivu.elect.presentation.menu;

import javax.annotation.Nonnull;
import javax.inject.Inject;

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

import de.ivu.elect.business.mandant.entity.EntityMitMandant;
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.jee.entity.Entity;
import de.ivu.elect.jee.presentation.action.AbstractBaseActionEntry;
import de.ivu.elect.presentation.security.AbstractGebietSecurity;
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 static de.ivu.elect.jee.entity.EntityUtil.castTo;

public abstract class AbstractActionEntry<E extends Entity<?, ?>> extends AbstractBaseActionEntry<E> {

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

  private static final long serialVersionUID = 1L;

  protected static final AbstractGebietSecurity KEINE_GEBIET_SECURITY = AbstractGebietSecurity.KEINE_GEBIET_SECURITY;

  @Inject
  protected transient ElectCommonPrincipal principal;

  @Inject
  protected transient GebietSecurity gebietSecurity;

  @Inject
  protected transient SperrmerkmalSecurity sperrmerkmalSecurity;

  public AbstractActionEntry() {
    super();
  }

  @Override
  public boolean hasPrincipalRequiredPermission() {
    return principal.hasUseCasePermission(getRequiredPermission());
  }

  @Override
  // NICHT ÜBERSCHREIBEN! (final wegen WELD nicht möglich)
  public boolean isDisabled(E proxy) {
    if (proxy == null) {
      return true;
    }
    try {

      // NOTE, dass ggf. ein (Hibernate-) Proxy in dieser Methode landet, der zunächst zu einer Entität gecastet werden muss!
      E entity = attach(tryCastToEntity(proxy)); // ELECTKOM-23

      // Entity kann schon gelöscht sein
      if (entity == null) {
        return true;
      }

      if (!isRechtAufGebietVorhanden(entity)) {
        return true;
      }

      if (isSperrmerkmalSperreVorhandenUndNichtBearbeitbar(entity)) {
        return true;
      }

      return isDisabledInternal(entity);
    } catch (Exception e) {
      LOG.warn("Exception in " + getClass() + ", " + e.getMessage());
      throw e;
    }
  }

  protected E tryCastToEntity(E proxy) {
    // NOTE, dass Value-Objekte (bspw. für Tabellenzeilen) existieren, die das Entity-Interface implementieren, sich aber nicht auf eine Entität casten lassen!
    if (proxy.isInstanceOf(Object.class)) {
      return (E) castTo(proxy, Object.class);
    }

    return proxy;
  }

  protected boolean isSperrmerkmalSperreVorhandenUndNichtBearbeitbar(E entity) {
    return sperrmerkmalSecurity.isSperreVorhandenUndNichtBearbeitbar(entity);
  }

  protected boolean isRechtAufGebietVorhanden(E entity) {
    return getGebietSecurity().isRechtVorhanden(entity);
  }

  // Überschreiben, wenn die Gebietsprüfung eine lazy-loading Exception ergibt und eine Analyse des Problems nicht weiterhilft...
  protected E attach(E entity) {
    return entity;
  }

  protected abstract boolean isDisabledInternal(@Nonnull E entity);

  protected abstract UseCasePermission getRequiredPermission();

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

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

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

  protected Mandant getMandant(EntityMitMandant entityMitMandant) {
    if (entityMitMandant != null) {
      Mandant mandant = entityMitMandant.getMandant();
      if (mandant != null) {
        return mandant;
      }
    }
    return principal.getMandant();
  }

}
