package de.torisan.util.thirdParty.coremediaSaxFilters;

import java.util.Enumeration;
import java.util.Hashtable;

import hox.corem.servlets.Context;
import hox.corem.servlets.ResourceFactory;
import hox.log.Log;
import hox.text.sax.SaxFilter;

import org.xml.sax.AttributeList;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributeListImpl;

/** A SaxFilter based implementation of a filter to be used with Coremedia DomUnparsers. The filter 
 * converts HOX.IMAGE or it's configured replacement in SGML input with HTML- or any desired target-ML's replacement.
 * There are lots of configuration methods for the properties of an instance. Yet, I believe the defaults that are 
 * set will be sufficient in most cases. 
 * Most cases herewith being: "conversion of inline images in Sgml-Textfields into a proper HTML representation"  
 * NOTE: This implementation uses a lot of deprecated API. This could not be circumvented, because the use of the 
 * deprecated API is forced upon this implementation by interfaces it has to stick to.
 * @author Toralf Richter (t.richter@triplesense.de)
 */
public class InlineImageFilterForSgmlTexts extends SaxFilter implements Cloneable {

 /** The element (or element name) returned here, indicates what output element will be produced. 
  * The default is this case and for this purpose is *IMG*. It should rarely need to be changed. 
  * @return String
  */
 public String getElement() {
  return element;
 }

 /** Will return the *main* attribute which is needed by this filter to work properly.
  * This aatribute corresponds to #getInlineImageMainAttribute(). 
  * Default attribute names are #getMainAttribute() = *SRC*, #getInlineImageMainAttribute() = *ID*.
  * The name of this attribute may be changed easily with the corresponding setter - but kkep in mind 
  * this is a last resort before changing the implemented code of this class and having to redeploy - 
  * usually the provided defaults are sensible and will suffice. 
  * @return String
  */
 public String getMainAttribute() {
  return mainAttribute;
 }

 /** Will return the mapping of 1. attribute names in the output produced => 2. attribute names as met in 
  * the Coremedia SGML input. All the attribute names listed here will in filtering / conversion be cycled through,
  * an every input name will be converted to the out name, and every input value will be assigned the the appropriate 
  * output name without further change.
  * Default settings are:
  * 1. ALIGN => HALIGN
  * 2. VALIGN => VALIGN 
  * For usual purposes the provided defaults are sensible and will suffice.
  * @return Hashtable
  */
 public Hashtable getOtherAttributes() {
  return otherAttributes;
 }

 /** Returns the name of the document property containing the image blob to be
  * used in image display
  * @return String
  */
 public String getImgProperty() {
  return imgProperty;
 }

 /** Return the templateId which is going to be used in constructing URIs 
  * to the image blob property that is to be rendered
  * @return String
  */
 public String getTemplateId() {
  return templateId;
 }

 /** Return the key - value list of additonal attributes which are going to be
  * added to the output struct produced by this filter. In case of an image here, 
  * this could be for instance "BORDER" => "0" ... for HTML output 
  * @return Hashtable
  */
 public Hashtable getAttributesToAddToOutput() {
  return attributesToAddToOutput;
 }

 /** Sets the name of the output element transformed here. Any defaults etc. are documented with #getElement().
  * @see #getElement()
  * @param element void
  */
 public void setElement(String element) {
  this.element = element;
 }

 /** Will set the *main* attribute which is needed by this filter to work properly. Any defaults etc. are 
  * documented with #getMainAttribute().
  * @see #getMainAttribute()
  * @param attribute void
  */
 public void setMainAttribute(String attribute) {
  this.mainAttribute = attribute;
 }

 /** Will set the mapping of 1. attribute names in the output produced => 2. attribute names as met in 
  * the Coremedia SGML input... Any defaults etc. are 
  * documented with #getOtherAttributes().
  * @see #getOtherAttributes()
  * @param hashtable void
  */
 public void setOtherAttributes(Hashtable hashtable) {
  otherAttributes = hashtable;
 }

 /** Sets the name of the document blob property containing the image blob to be
  * used in image display
  * @param string void
  */
 public void setImgProperty(String string) {
  imgProperty = string;
 }

 /** Sets the templateId which is going to be used in constructing URIs 
  * to the image blob property that is to be rendered
  * @param string void
  */
 public void setTemplateId(String string) {
  templateId = string;
 }

 /** Sets the key - value list of additonal attributes which are going to be
  * added to the output struct produced by this filter.
  * @param hashtable void
  */
 public void setAttributesToAddToOutput(Hashtable hashtable) {
  attributesToAddToOutput = hashtable;
 }

 /** Access to a ResourceFactory for internal processing.
  * @return ResourceFactory
  */
 protected ResourceFactory getResourceFactory() {
  if (resourceFactory == null)
   resourceFactory = Context.getCurrentContext().getGenerator().getResourceFactory();
  return resourceFactory;
 }

 /** Access to a Log Facility.
  * @return Log
  */
 protected Log getLog() {
  return Context.getCurrentContext().getGenerator().getLog();
 }

 /** Method to create the start of the element. Textually spoken it creates 
  * the start tag of the element and fills it with the needed and/or desired attributes.
  * This is the method which is called upon by the saxparser/domunparser APIs and that does 
  * the actual filtering.
  * @param name - name of the element processed
  * @param attributes - list of the attributes attached to the element
  */
 public void startElement(String name, AttributeList attributes) throws SAXException {
  if (name.equals(this.inlineImageElement)) {
   String idString = attributes.getValue(this.inlineImageMainAttribute);
   if (idString == null) {
    super.startElement(name, attributes);
   }
   AttributeListImpl list = new AttributeListImpl();
   try {
    int id = Integer.parseInt(idString);
    String src = "";
    //    String align = "";
    //    String valign = "";
    hox.corem.servlets.Document imgDoc = hox.corem.servlets.Context.getCurrentContext().getGenerator().getResourceFactory().createDocument(id);

    if (imgDoc.getBlobProperty(this.getImgProperty()) != null) {
     if (this.getTemplateId().length() == 0) {
      src = imgDoc.getPropertyUri(this.getImgProperty()).toString();
     } else {
      src = imgDoc.getPropertyUri(this.getImgProperty(), this.getTemplateId()).toString();
     }
     list.addAttribute(this.getMainAttribute(), "CDATA", src);

     /* Conversion of all configured other attributes */
     for (Enumeration e = this.otherAttributes.keys(); e.hasMoreElements();) {
      String key = (String)e.nextElement();
      String value = (String)this.otherAttributes.get(key);
      if (attributes.getValue(value) != null) {
       list.addAttribute(key, "CDATA", attributes.getValue(value));
      }
     }
     /* concatenation of addtional attributes to be set in the output */
     for (Enumeration e = this.attributesToAddToOutput.keys(); e.hasMoreElements();) {
      String key = (String)e.nextElement();
      String value = (String)this.attributesToAddToOutput.get(key);
      if (value != null) {
       list.addAttribute(key, "CDATA", value);
      }
     }
    } else {
     this.doNotDisPLayAnyImages = true;
    }
   } catch (Exception e) {
    getLog().write(3, "InlineImageFilterForSgmlTexts: exception while filtering sax events", e);
    throw new SAXException(e.getMessage());
   }
   if (this.doNotDisPLayAnyImages) {
    return;
   }
   super.startElement(this.getElement(), list);
  } else {
   super.startElement(name, attributes);
  }
 }

 /** Special implementation of method closing the element of concern. The element that is
  * closed here is the processed image element. 
  * @param name - naem of the element processed
  */
 public void endElement(String name) throws SAXException {
  if (name.equals(this.inlineImageElement)) {
   name = this.getElement();
   if (this.doNotDisPLayAnyImages) {
    return;
   }
  }
  super.endElement(name);
 }

 /** Constructor. Initialises the filter with the following default seetings:
  * output element *IMG* - input element *HOX.IMAGE*,
  * output main attribute *SRC* - input main attribute *ID*
  * mapping for other attributes (output => input) : "ALIGN" => "HALIGN", "VALIGN" => "VALIGN",
  * internal flag doNotDisPlayAnyImages = false, which means images will be displayed 
  * additonal attributes:  "BORDER" => "0"
  * @throws Exception
  */
 public InlineImageFilterForSgmlTexts() throws Exception {
  this(false);
 }

 /** Constructor. Allow to explicitly set doNotDisPLayAnyImages flag.
  * Everything else is equal to the no-arg constructor
  * @param doNotDisPLayAnyImages - a value of false sets the filter to display images, a value of true sets the filter not to display images
  * @throws Exception
  */
 public InlineImageFilterForSgmlTexts(boolean doNotDisPLayAnyImages) throws Exception {
  this.element = "IMG";
  this.mainAttribute = "SRC";
  this.inlineImageElement = "HOX.IMAGE";
  this.inlineImageMainAttribute = "ID";
  this.doNotDisPLayAnyImages = doNotDisPLayAnyImages;
  this.otherAttributes.put("ALIGN", "HALIGN");
  this.otherAttributes.put("VALIGN", "VALIGN");
  this.attributesToAddToOutput.put( "BORDER", "0" );
 }

 private String element;
 private String mainAttribute;
 private Hashtable otherAttributes = new Hashtable();
 private Hashtable attributesToAddToOutput = new Hashtable();
 private ResourceFactory resourceFactory;
 private String inlineImageElement;
 private String inlineImageMainAttribute;
 private boolean doNotDisPLayAnyImages = false;
 private String imgProperty = "BildKlein";
 private String templateId = "";

}
