/*
  Copyright (C) 2006 Helge Hess

  This file is part of JOPE.

  JOPE is free software; you can redistribute it and/or modify it under
  the terms of the GNU Lesser General Public License as published by the
  Free Software Foundation; either version 2, or (at your option) any
  later version.

  JOPE 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 Lesser General Public
  License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with JOPE; see the file COPYING.  If not, write to the
  Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
  02111-1307, USA.
*/

package org.opengroupware.jope.appserver.core;

import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.opengroupware.jope.foundation.NSKeyValueStringFormatter;

/*
 * WODynamicElement
 * 
 * This is the abstract superclass for _stateless_ and reentrant parts of a
 * template. Subclasses MUST NOT store any processing state in instance
 * variables because they can be accessed concurrently by multiple threads and
 * even by one thread.
 * 
 * TODO:
 * - explain extra attribute patterns (%onclick="abc")
 * - pregenerate HTML for constant extra attributes
 */

public abstract class WODynamicElement extends WOElement {
  protected static final Log delog = LogFactory.getLog("WODynamicElement");
  
  protected WOAssociation   otherTagString;
  protected String[]        extraKeys;
  protected WOAssociation[] extraValues;

  public WODynamicElement
    (String _name, Map<String,WOAssociation> _assocs, WOElement _template)
  {
  }
  
  /* helpers */
  
  public static WOAssociation grabAssociation
    (Map<String,WOAssociation> _assocs, String _name)
  {
    if (_assocs == null)
      return null;
    
    WOAssociation assoc = _assocs.get(_name);
    if (assoc == null)
      return null;
    
    _assocs.remove(_name);
    return assoc;
  }
  
  /* accessors */
  
  public Log log() {
    return delog;
  }
  
  public void setExtraAttributes(Map<String, WOAssociation> _attrs) {
    if (delog.isDebugEnabled())
      delog.debug("setting extra attributes: " + _attrs);
    
    this.extraKeys   = null;
    this.extraValues = null;
    
    this.otherTagString = grabAssociation(_attrs, "otherTagString");
    
    int extraCount;
    if (_attrs != null && (extraCount = _attrs.size()) > 0) {
      this.extraKeys   = new String[extraCount];
      this.extraValues = new WOAssociation[extraCount];
      
      int i = 0;
      for (String key: _attrs.keySet()) {
        this.extraKeys[i]   = key;
        if ((this.extraValues[i] = _attrs.get(key)) == null)
          delog.warn("missing association for extra binding: " + key);
        i++;
      }
    }
  }
  
  /* response */
  
  public void appendExtraAttributesToResponse
    (WOResponse _r, WOContext _c)
  {
    if (this.extraKeys == null)
      return;
    
    this.appendExtraAttributesToResponse(_r, _c, _c.cursor());
  }
  
  public void appendExtraAttributesToResponse
    (WOResponse _r, WOContext _c, Object _patObject)
  {
    if (this.extraKeys == null)
      return;
    
    /* we could probably improve the speed of the pattern processor ... */
    Object cursor = _c.cursor();
    for (int i = 0; i < this.extraKeys.length; i++) {
      String v = this.extraValues[i].stringValueInComponent(cursor);
      if (v == null)
        continue;
      
      if (this.extraKeys[i].charAt(0) == '%') {
        v = NSKeyValueStringFormatter.format(v, _patObject);
        _r.appendAttribute(this.extraKeys[i].substring(1), v);
      }
      else
        _r.appendAttribute(this.extraKeys[i], v);
    }
  }
  
  /* description */
  
  public void appendAssocToDescription
    (StringBuffer _d, String _name, WOAssociation _a)
  {
    if (_a == null)
      return;
    
    _d.append(' ');
    _d.append(_name);
    _d.append('=');

    // TODO: make output even smarter ;-)
    if (!_a.isValueConstant()) {
      _d.append(_a);
      return;
    }
    
    /* constant assocs */
    
    Object v = _a.valueInComponent(null);
    
    if (v != null) {
      _d.append('"');
      if (v instanceof String) {
        if (((String)v).length() > 79)
          v = ((String)v).substring(0, 77) + "...";
      }
      _d.append(v);
      _d.append('"');
    }
    else
      _d.append(" null");
  } 
}
