/*
  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.elements;

import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.opengroupware.jope.appserver.core.WOAssociation;
import org.opengroupware.jope.appserver.core.WOContext;
import org.opengroupware.jope.appserver.core.WODynamicElement;
import org.opengroupware.jope.appserver.core.WOElement;
import org.opengroupware.jope.appserver.core.WOElementWalker;
import org.opengroupware.jope.appserver.core.WORequest;
import org.opengroupware.jope.appserver.core.WOResponse;

/*
 * WOConditional
 * 
 * Render a subsection or not depending on some component state.
 * 
 * Sample:
 *   ShowIfRed: WOConditional {
 *     condition = currentColor;
 *     value     = "red";
 *   }
 *   
 * Renders:
 *   This element doesn't render anything.
 *   
 * Bindings:
 *   condition [in] - boolean or object if used with value binding
 *   negate    [in] - boolean
 *   value     [in] - object
 * 
 * TODO: would be nice to have NPS style operations, like
 *         operation="isNotEmpty" condition="item.lastname"
 *       since in Java we can't add such to objects using categories.
 */
public class WOConditional extends WODynamicElement {
  protected static Log log = LogFactory.getLog("WOConditional");

  protected WOAssociation condition;
  protected WOAssociation negate;
  protected WOAssociation value;
  protected WOElement     template;

  public WOConditional(String _name, Map<String, WOAssociation> _assocs,
                       WOElement _template)
  {
    super(_name, _assocs, _template);

    if ((this.condition = grabAssociation(_assocs, "condition")) == null)
      log.error("missing 'condition' binding!");

    this.negate   = grabAssociation(_assocs, "negate");
    this.value    = grabAssociation(_assocs, "value");    
    this.template = _template;
  }

  /* evaluate */
  
  protected boolean doShowInContext(WOContext _ctx) {
    boolean doShow, doNegate = false;
    Object  cursor = _ctx.cursor();
    
    if (this.negate != null)
      doNegate = this.negate.booleanValueInComponent(cursor);
    
    if (this.value != null) {
      Object v = this.value.valueInComponent(cursor);
      Object o = this.condition.valueInComponent(cursor);
      
      if (v == o)
        doShow = true;
      else if (o == null || v == null)
        doShow = false;
      else
        doShow = o.equals(v);
    }
    else
      doShow = this.condition.booleanValueInComponent(cursor);
    
    return doNegate ? !doShow : doShow;
  }
  
  /* responder */

  @Override
  public void takeValuesFromRequest(WORequest _rq, WOContext _ctx) {
    if (!this.doShowInContext(_ctx) || this.template == null)
      return;
    
    _ctx.appendElementIDComponent("1");
    this.template.takeValuesFromRequest(_rq, _ctx);
    _ctx.deleteLastElementIDComponent();
  }
  
  @Override
  public Object invokeAction(WORequest _rq, WOContext _ctx) {
    // TODO: implement me for WOComponentActions
    log.error("WOConditional not implemented for component actions ...");
    return null;
  }
  
  @Override
  public void appendToResponse(WOResponse _r, WOContext _ctx) {
    if (!this.doShowInContext(_ctx) || this.template == null) {
      log.debug("not showing a conditional ...");
      return;
    }
    
    _ctx.appendElementIDComponent("1");
    this.template.appendToResponse(_r, _ctx);
    _ctx.deleteLastElementIDComponent();
  }
  
  @Override
  public void walkTemplate(WOElementWalker _walker, WOContext _ctx) {
    if (!this.doShowInContext(_ctx) || this.template == null) {
      log.debug("not showing a conditional ...");
      return;
    }
    
    _ctx.appendElementIDComponent("1");
    _walker.processTemplate(this, this.template, _ctx);
    _ctx.deleteLastElementIDComponent();
  }
}
