
package de.ivu.elect.business.image.entity;

import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;

import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.util.Base64;
import java.util.Optional;

import javax.faces.context.FacesContext;
import javax.faces.event.PhaseId;
import javax.imageio.ImageIO;
import javax.persistence.Transient;

import org.primefaces.model.DefaultStreamedContent;

import de.ivu.elect.util.FileUtil;

public abstract class AbstractBild implements BildBase {

  private static final long serialVersionUID = 1L;

  @Transient
  private transient BufferedImage bufferedImage;

  @Transient
  private transient String grupppeNameFuerDateiname;

  protected AbstractBild() {
    super();
  }

  public String getGrupppeNameFuerDateiname() {
    return grupppeNameFuerDateiname;
  }

  public void setGrupppeNameFuerDateiname(String grupppeNameFuerDateiname) {
    this.grupppeNameFuerDateiname = grupppeNameFuerDateiname;
  }

  /**
   * http://stackoverflow.com/questions/10073905/display-database-blob-images-in-pgraphicimage-inside-uirepeat
   */
  public DefaultStreamedContent getStreamedContent() {
    FacesContext context = FacesContext.getCurrentInstance();

    if (isBlank(getContentBase64()) || PhaseId.RENDER_RESPONSE.equals(context.getCurrentPhaseId())) {
      return new DefaultStreamedContent();
    }

    return DefaultStreamedContent.builder().stream(() -> new ByteArrayInputStream(getContent())).contentType(getMimeType()).name(getDateiName()).build();
  }

  private String getDateiName() {
    return FileUtil.normalizeFileNamePreserveCase("Logo-" + getGrupppeNameFuerDateiname()) + "." + extractFileExtensionFromMimeType();
  }

  private String extractFileExtensionFromMimeType() {
    String mimeType = getMimeType();
    String separator = "/";

    if (isNotBlank(mimeType) && mimeType.contains(separator)) {
      return mimeType.split(separator)[1];
    }

    return mimeType;
  }

  public void setContent(byte[] content) {
    setContentBase64(Base64.getEncoder().encodeToString(content));
  }

  public byte[] getContent() {
    return Base64.getDecoder().decode(getContentBase64());
  }

  /**
   * @return Seitenverhältnis Breite/Höhe, falls bestimmbar. Enthält NIEMALS 0.0!!!
   */
  public Optional<Double> getAspectRatio() {
    Optional<Integer> widthInPx = getWidthInPx();

    if (widthInPx.isPresent()) {
      Optional<Integer> heightInPx = getHeightInPx();

      if (heightInPx.isPresent()) {
        try {
          double value = (double) widthInPx.get() / (double) heightInPx.get();

          if (value != 0.0D) {
            return Optional.of(value);
          }
        } catch (Exception ignored) { // Division durch 0, etc.
        }
      }
    }

    return Optional.empty();
  }

  public Optional<Integer> getWidthInPx() {
    return getBufferedImage().map(BufferedImage::getWidth);
  }

  public Optional<Integer> getHeightInPx() {
    return getBufferedImage().map(BufferedImage::getHeight);
  }

  private Optional<BufferedImage> getBufferedImage() {
    if (bufferedImage == null) {
      try {
        bufferedImage = ImageIO.read(new ByteArrayInputStream(getContent()));
      } catch (Exception ignored) {
      }
    }

    return Optional.ofNullable(bufferedImage);
  }
}
