package org.opengroupware.jope.appserver.elements;

import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.opengroupware.jope.appserver.WOAssociation;
import org.opengroupware.jope.appserver.WOContext;
import org.opengroupware.jope.appserver.WOElement;
import org.opengroupware.jope.appserver.WOResponse;
import org.opengroupware.jope.foundation.UString;

/*
 * WOString
 * 
 * Just a plain, dynamic string.
 * 
 * Sample:
 *   ComponentName: WOString {
 *     value = name;
 *   }
 * 
 * Renders:
 *   The element renders the given value, possibly after applying conversions.
 *   
 * Bindings:
 *   value          [in] - object
 *   valueWhenEmpty [in] - object
 *   escapeHTML     [in] - boolean (set to false to avoid HTML escaping)
 *   insertBR       [in] - boolean (replace newlines with <br/> tags)
 */
public class WOString extends WOHTMLDynamicElement {
  protected Log log = LogFactory.getLog("WOString");
  
  protected WOAssociation value;
  protected WOAssociation valueWhenEmpty;
  protected WOAssociation escapeHTML;
  protected WOAssociation insertBR;
  protected WOFormatter   formatter;

  public WOString(String _name, Map<String, WOAssociation> _assocs,
                  WOElement _template)
  {
    super(_name, _assocs, _template);
    
    this.value          = grabAssociation(_assocs, "value");
    this.escapeHTML     = grabAssociation(_assocs, "escapeHTML");
    this.valueWhenEmpty = grabAssociation(_assocs, "valueWhenEmpty");
    this.insertBR       = grabAssociation(_assocs, "insertBR");
    
    this.formatter = WOFormatter.formatterForAssociations(_assocs);
  }
  
  public WOString(WOAssociation _value, boolean _escapeHTML) {
    super(null /* name */, null /* assocs */, null /* template */);
    
    this.value      = _value;
    this.escapeHTML =
      WOAssociation.associationWithValue(new Boolean(_escapeHTML)); 
  }
  
  /* some convenience accessors for from-code creation */
  
  public WOString(Object _value) {
    this(WOAssociation.associationWithValue(_value), true /* escapeHTML */);
  }
  
  /* generate response */

  public void appendToResponse(WOResponse _r, WOContext _ctx) {
    if (_ctx.isRenderingDisabled())
      return;
    
    boolean isDebugOn = this.log.isDebugEnabled();
    Object  cursor = _ctx.cursor();
    Object  v;
    String  s;
    boolean doEscape = true;
    
    if (isDebugOn) this.log.debug("append, cursor: " + cursor);
    
    if (this.value == null) {
      if (isDebugOn) this.log.debug("  no value binding: " + cursor);
      return;
    }
    
    if ((v = this.value.valueInComponent(cursor)) == null) {
      if (isDebugOn)
        this.log.debug("  value binding return no object: " + this.value);
    }
    
    /* valueWhenEmpty */
    
    if (v != null) {
      if (v instanceof String) {
        if (((String)v).length() == 0)
          v = null;
      }
    }
    if (this.valueWhenEmpty != null) {
      if (v == null)
        v = this.valueWhenEmpty.valueInComponent(cursor);
    }
    
    /* format value */
    
    if (this.formatter != null)
      s = this.formatter.stringForObjectValue(v, _ctx);
    else if (v != null)
      s = v.toString();
    else
      s = null;

    /* escaping */
    
    if (this.escapeHTML != null) {
      if (!this.escapeHTML.booleanValueInComponent(cursor))
        doEscape = false;
    }

    if (isDebugOn) this.log.debug("  escape: " + doEscape);
    
    /* insertBR processing */
    
    if (this.insertBR != null && s != null) {
      if (this.insertBR.booleanValueInComponent(cursor)) {
        /* Note: we can't use replace() because we need to escape the individual
         *       parts.
         */
        StringBuffer sb = new StringBuffer(256);
        String[] lines = s.split("[\\n]");
        boolean isFirst = true;
        
        for (String line: lines) {
          if (isFirst)
            isFirst = false;
          else
            sb.append("<br />");
          if (doEscape)
            line = UString.stringByEscapingHTMLString(line);
          sb.append(line);
        }
        doEscape = false;
        s = sb.toString();
      }
    }
    
    /* append */
    
    if (s != null) {
      if (doEscape)
        _r.appendContentHTMLString(s);
      else
        _r.appendContentString(s);
    }
    else if (isDebugOn)
      this.log.debug("  no content to render.");
  }
  
  /* description */
  
  public void appendAttributesToDescription(StringBuffer _d) {
    super.appendAttributesToDescription(_d);
    
    this.appendAssocToDescription(_d, "value", this.value);
  }
}
