/*
 * File    : ActiveBoxContent.java
 * Created : 02-may-2001 15:29
 * By      : fbusquets
 *
 * JClic - Authoring and playing system for educational activities
 *
 * Copyright (C) 2000 - 2018 Francesc Busquets & Departament
 * d'Educacio de la Generalitat de Catalunya
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details (see the LICENSE file).
 */

package edu.xtec.jclic.boxes;

import edu.xtec.jclic.Constants;
import edu.xtec.jclic.PlayStation;
import edu.xtec.jclic.bags.MediaBag;
import edu.xtec.jclic.bags.MediaBagElement;
import edu.xtec.jclic.fileSystem.FileSystem;
import edu.xtec.jclic.media.ActiveMediaPlayer;
import edu.xtec.jclic.media.MediaContent;
import edu.xtec.util.Domable;
import edu.xtec.util.JDomUtility;
import edu.xtec.util.ResourceManager;
import edu.xtec.util.StrUtils;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Shape;
import java.util.Map;

/**
 * This class defines a content that can be displayed by
 * {@link edu.xtec.jclic.boxes.ActiveBox} objects. This content can be a text,
 * an image, a fragment of an image or a combination of text and images. The
 * style (colours, font and size, etc.) can be specified in a
 * {@link edu.xtec.jclic.boxes.BoxBase} object. It stores also information about
 * the optimal size and location of the <CODE>ActiveBox</CODE>.
 *
 * @author Francesc Busquets (fbusquets@xtec.cat)
 * @version 13.09.09
 */
public class ActiveBoxContent extends Object implements Cloneable, Domable {

  public BoxBase bb = null;
  public Dimension dimension = null;
  public Boolean border = null;
  public String text = null;
  public String imgName = null;
  public Shape imgClip = null;
  public MediaContent mediaContent = null;
  public int[] imgAlign = new int[] { JDomUtility.ALIGN_MIDDLE, JDomUtility.ALIGN_MIDDLE };
  public int[] txtAlign = new int[] { JDomUtility.ALIGN_MIDDLE, JDomUtility.ALIGN_MIDDLE };
  public boolean avoidOverlapping = false;
  public int id = -1;
  public int item = -1;

  public Image img = null;

  // static fields
  protected static ActiveBoxContent EMPTY_CONTENT;

  // transient properties
  public Object userData = null;
  public String rawText = null;
  public String htmlText = null;
  public String innerHtmlText = null;
  public boolean animated = false;
  public ActiveMediaPlayer amp = null;

  protected void copyRawDataFrom(ActiveBoxContent src) {
    bb = src.bb;
    dimension = src.dimension;
    border = src.border;
    text = src.text;
    imgName = src.imgName;
    imgClip = src.imgClip;
    mediaContent = src.mediaContent;
    imgAlign = src.imgAlign;
    txtAlign = src.txtAlign;
    avoidOverlapping = src.avoidOverlapping;
    id = src.id;
    item = src.item;
    img = src.img;
    userData = src.userData;
    rawText = src.rawText;
    htmlText = src.htmlText;
    innerHtmlText = src.innerHtmlText;
    animated = src.animated;
    amp = src.amp;
  }

  /** Creates new ActiveBoxContent */
  public ActiveBoxContent() {
  }

  public static ActiveBoxContent getEmptyContent() {
    if (EMPTY_CONTENT == null)
      EMPTY_CONTENT = new ActiveBoxContent();
    return EMPTY_CONTENT;
  }

  public static final String ELEMENT_NAME = "cell";
  protected static final String ID = "id", ITEM = "item", WIDTH = "width", HEIGHT = "height", BORDER = "border",
      IMAGE = "image", TXTALIGN = "txtAlign", IMGALIGN = "imgAlign", AVOID_OVERLAPPING = "avoidOverlapping";

  public org.jdom.Element getJDomElement() {
    org.jdom.Element e = new org.jdom.Element(ELEMENT_NAME);

    if (id != -1)
      e.setAttribute(ID, Integer.toString(id));

    if (item != -1)
      e.setAttribute(ITEM, Integer.toString(item));

    JDomUtility.setAlignProp(e, TXTALIGN, txtAlign, true);
    JDomUtility.setAlignProp(e, IMGALIGN, imgAlign, true);
    if (avoidOverlapping)
      e.setAttribute(AVOID_OVERLAPPING, JDomUtility.boolString(avoidOverlapping));

    if (dimension != null) {
      e.setAttribute(WIDTH, Integer.toString(dimension.width));
      e.setAttribute(HEIGHT, Integer.toString(dimension.height));
    }
    if (border != null)
      e.setAttribute(BORDER, JDomUtility.boolString(border.booleanValue()));

    if (imgName != null)
      e.setAttribute(IMAGE, imgName);

    if (bb != null)
      e.addContent(bb.getJDomElement());

    if (mediaContent != null)
      e.addContent(mediaContent.getJDomElement());

    if (text != null)
      JDomUtility.setParagraphs(e, text);

    return e;
  }

  public static final int EMPTY_CELL = 0, ONLY_ID = 1, HAS_CONTENT = 2;

  public int testCellContents() {
    if (JDomUtility.isDefaultAlign(txtAlign) && JDomUtility.isDefaultAlign(imgAlign) && !avoidOverlapping
        && dimension == null && border == null && imgName == null && bb == null && mediaContent == null
        && (text == null || text.length() == 0)) {
      return ((id == -1 && item == -1) ? EMPTY_CELL : ONLY_ID);
    }
    return HAS_CONTENT;
  }

  public static ActiveBoxContent getActiveBoxContent(org.jdom.Element e, MediaBag mediaBag) throws Exception {

    ActiveBoxContent abc = new ActiveBoxContent();
    abc.setProperties(e, mediaBag);
    return abc;
  }

  public void setProperties(org.jdom.Element e, Object aux) throws Exception {

    JDomUtility.checkName(e, ELEMENT_NAME);
    MediaBag mediaBag = (MediaBag) aux;

    org.jdom.Element child;

    id = JDomUtility.getIntAttr(e, ID, id);
    item = JDomUtility.getIntAttr(e, ITEM, item);
    if (e.getAttribute(JDomUtility.HALIGN) != null || e.getAttribute(JDomUtility.VALIGN) != null) {
      // old version!!!
      txtAlign[0] = JDomUtility.getHAlign(e, txtAlign[0]);
      txtAlign[1] = JDomUtility.getVAlign(e, txtAlign[1]);
      imgAlign[0] = txtAlign[0];
      imgAlign[1] = txtAlign[1];
    } else {
      txtAlign = JDomUtility.getAlignProp(e, TXTALIGN, txtAlign);
      imgAlign = JDomUtility.getAlignProp(e, IMGALIGN, imgAlign);
    }
    avoidOverlapping = JDomUtility.getBoolAttr(e, AVOID_OVERLAPPING, avoidOverlapping);

    dimension = JDomUtility.getDimensionAttr(e, WIDTH, HEIGHT, dimension);
    border = JDomUtility.getBooleanAttr(e, BORDER, border);
    imgName = FileSystem.stdFn(e.getAttributeValue(IMAGE));
    if ((child = e.getChild(BoxBase.ELEMENT_NAME)) != null)
      setBoxBase(BoxBase.getBoxBase(child));
    if ((child = e.getChild(MediaContent.ELEMENT_NAME)) != null)
      mediaContent = MediaContent.getMediaContent(child);
    setTextContent(JDomUtility.getParagraphs(e));

    if (mediaBag != null)
      realizeContent(mediaBag);
  }

  public static void listReferences(org.jdom.Element e, Map<String, String> map) {
    if (e != null) {
      String s = e.getAttributeValue(IMAGE);
      if (s != null && s.length() > 0)
        map.put(s, Constants.MEDIA_OBJECT);
      org.jdom.Element child = e.getChild(MediaContent.ELEMENT_NAME);
      if (child != null)
        MediaContent.listReferences(child, map);
    }
  }

  @Override
  public Object clone() {
    ActiveBoxContent abc = null;
    try {
      abc = (ActiveBoxContent) super.clone();
      abc.txtAlign = new int[] { txtAlign[0], txtAlign[1] };
      abc.imgAlign = new int[] { imgAlign[0], imgAlign[1] };
    } catch (Exception ex) {
      System.err.println("Unexpected error cloning ActiveBoxContent!");
    }
    return abc;
  }

  public void realizeContent(MediaBag mediaBag) throws Exception {
    // todo: check global img and imgclip
    if (imgName != null) {
      MediaBagElement mbe = mediaBag.getImageElement(imgName);
      if (mbe != null) {
        img = mbe.getImage();
        animated = mbe.animated;
      }
    }
    if (mediaContent != null) {
      mediaContent.registerContentTo(mediaBag);
      if (img == null && (text == null || text.length() == 0)) {
        String s = mediaContent.getIconName();
        img = ResourceManager.getImageIcon("icons/" + s).getImage();
      }
    }
    checkHtmlText(mediaBag);
  }

  public boolean isEmpty() {
    return (text == null && img == null);
  }

  public boolean isEquivalent(ActiveBoxContent abc, boolean checkCase) {
    if (abc == this)
      return true;
    boolean result = false;
    if (abc != null) {
      if (isEmpty() && abc.isEmpty())
        result = (id == abc.id);
      else
        result = (text == null ? abc.text == null
            : (checkCase ? text.equals(abc.text) : text.equalsIgnoreCase(abc.text)))
            && (mediaContent == null ? abc.mediaContent == null : mediaContent.isEquivalent(abc.mediaContent))
            && (img == abc.img) && (imgClip == null ? abc.imgClip == null : imgClip.equals(abc.imgClip));
    }
    return result;
  }

  @Override
  public boolean equals(Object o) {
    boolean result = (o == this);
    if (!result && o != null && o instanceof ActiveBoxContent) {
      ActiveBoxContent abc = (ActiveBoxContent) o;
      result = isEquivalent(abc, true) && ((bb == null && abc.bb == null) || (bb != null && bb.equals(abc.bb)))
          && txtAlign[0] == abc.txtAlign[0] && txtAlign[1] == abc.txtAlign[1] && imgAlign[0] == abc.imgAlign[0]
          && imgAlign[1] == abc.imgAlign[1] && avoidOverlapping == abc.avoidOverlapping;
    }
    return result;
  }

  public void setTextContent(String tx) {
    // only plain text!
    if (tx != null) {
      rawText = tx;
      text = tx;
      checkHtmlText(null);
    } else {
      rawText = null;
      text = null;
      htmlText = null;
      innerHtmlText = null;
    }
  }

  protected void checkHtmlText(MediaBag mediaBag) {
    htmlText = null;
    innerHtmlText = null;

    if (text != null && text.substring(0).toLowerCase().startsWith("<html>")) {
      htmlText = text;
      if (mediaBag != null) {
        FileSystem fs = mediaBag.getProject().getFileSystem();
        String path = fs.root;
        if (!fs.isUrlBased())
          path = "file:" + FileSystem.sysFn(path);
        htmlText = StrUtils.replace(htmlText, "SRC=\"", "SRC=\"" + path);
        htmlText = StrUtils.replace(htmlText, "src=\"", "src=\"" + path);
      }
      String s = htmlText.substring(0).toLowerCase();
      if (s.indexOf("<body") == -1) {
        int s2 = s.indexOf("</html>");
        if (s2 >= 0) {
          innerHtmlText = htmlText.substring(6, s2);
        }
      }
    }
  }

  public void setImgContent(Image setImg, Shape setImgClip) {
    img = setImg;
    imgName = null;
    imgClip = setImgClip;
  }

  public void setImgAlign(int[] align) {
    imgAlign[0] = align[0];
    imgAlign[1] = align[1];
  }

  public void setImgAlign(int h, int v) {
    imgAlign[0] = h;
    imgAlign[1] = v;
  }

  public void setTxtAlign(int[] align) {
    txtAlign[0] = align[0];
    txtAlign[1] = align[1];
  }

  public void setTxtAlign(int h, int v) {
    txtAlign[0] = h;
    txtAlign[1] = v;
  }

  public void prepareMedia(PlayStation ps) {
    if (mediaContent != null)
      amp = ps.getActiveMediaPlayer(mediaContent);
    else
      amp = null;
  }

  public void setBoxBase(BoxBase boxBase) {
    bb = boxBase;
  }

  public void setDimension(Dimension d) {
    dimension = d;
  }

  public Dimension getDimension() {
    return dimension;
  }

  public void setBorder(boolean b) {
    border = b;
  }

  public void copyStyleTo(ActiveBoxContent abc) {
    if (abc != null) {
      abc.setBoxBase(bb);
      if (border != null)
        abc.setBorder(border.booleanValue());
    }
  }

  public String getDescription() {
    StringBuilder result = new StringBuilder();
    if (text != null && text.length() > 0)
      result.append(text);
    else if (imgName != null)
      result.append("IMG:").append(imgName);
    else if (imgClip != null) {
      Rectangle r = imgClip.getBounds();
      result.append("[").append(r.x).append(",").append(r.y).append(",");
      result.append(r.width).append(",").append(r.height).append("]");
    }

    if (mediaContent != null) {
      if (result.length() > 0)
        result.append(' ');
      result.append(mediaContent.getDescription());
    }
    return result.substring(0);
  }
}
