/*
  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.opengroupware.jope.appserver.core.WOAssociation;
import org.opengroupware.jope.appserver.core.WOComponent;
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.WORequest;
import org.opengroupware.jope.appserver.core.WOResponse;
import org.opengroupware.jope.foundation.NSKeyValueCodingAdditions;

/*
 * WOComponentContent
 * 
 * This element renders/processes a section of the parent component inside the
 * subcomponent. The element is useful for pagewide frames and such. The child
 * would render the frame HTML and the actual content can stay in the page.
 *
 * Parent Sample (HTML):
 *   <#Child>renders this text</#Child>
 *   
 * Child Sample (HTML):
 *   <b>Content: <#Content/></b>
 *   
 * Child Sample (WOD):
 *   Content: WOComponentContent {}
 * 
 * Renders:
 *   This element does not render anything.
 * 
 * 
 * Copy bindings:
 *   
 *   <div id="leftmenu">
 *     <#WOComponentContent section="menu" />
 *   </div>
 *   <div id="content">
 *     <#WOComponentContent section="content" />
 *   </div>
 *   
 * This will set the 'section' key in the parent component to 'a' prior entering
 * the template. You can then check in the parent template:
 *   
 *   <#WOConditional var:condition="section" value="menu">a b c</#>
 *   
 * 
 * Fragments
 * 
 *   <#WOComponentContent fragmentID="menu" />
 *   <#WOComponentContent fragmentID="content" />
 * 
 * And in the parent template:
 * 
 *   <#WOFragment name="menu"> ... </#>
 *   
 * But be careful, this can interact with AJAX fragment processing.
 * 
 * 
 * Bindings:
 *   - fragmentID [in] - string   disable rendering and set fragment-id
 *   <extra>      [in] - object   copied into the parent component
 */
public class WOComponentContent extends WODynamicElement {
  
  protected WOAssociation fragmentID;

  public WOComponentContent
    (String _name, Map<String, WOAssociation> _assocs, WOElement _template)
  {
    super(_name, _assocs, _template);
    
    this.fragmentID = grabAssociation(_assocs, "fragmentID");
  }

  /* responder */
  
  @Override
  public void takeValuesFromRequest(WORequest _rq, WOContext _ctx) {
    WOElement content;
    
    if ((content = _ctx.componentContent()) == null)
      return;
    
    WOComponent component = _ctx.component();
    
    /* leave component */
    _ctx.leaveComponent(component);
    
    /* now we are in the parent component's context, continue there */
    content.takeValuesFromRequest(_rq, _ctx);
    
    /* back to own component */
    _ctx.enterComponent(component, content);
  }
  
  @Override
  public Object invokeAction(WORequest _rq, WOContext _ctx) {
    WOElement content;
    
    if ((content = _ctx.componentContent()) == null)
      return null;
    
    WOComponent component = _ctx.component();
    
    /* leave component */
    _ctx.leaveComponent(component);
    
    /* now we are in the parent component's context, continue there */
    Object result = content.invokeAction(_rq, _ctx);
    
    /* back to own component */
    _ctx.enterComponent(component, content);
    
    return result;
  }
  
  @Override
  public void appendToResponse(WOResponse _r, WOContext _ctx) {
    Object cursor = _ctx.cursor();
    WOElement content;
    String    wofid;
    
    if ((content = _ctx.componentContent()) == null)
      return;
    
    /* check whether fragment processing is enabled */
    
    wofid = this.fragmentID != null
      ? this.fragmentID.stringValueInComponent(cursor)
      : null;
    
    WOComponent component = _ctx.component();
    
    /* copy other values */

    Object[] lExtraValues = null;
    if (this.extraKeys != null) {
      lExtraValues = new Object[this.extraKeys.length];
      
      for (int i = 0; i < this.extraKeys.length; i++) {
        /* retrieve value */
        lExtraValues[i] = this.extraValues[i].valueInComponent(cursor);
      }
    }
    
    /* leave component */
    _ctx.leaveComponent(component);
    
    /* apply copied values */
    
    if (lExtraValues != null) {
      Object setCursor = _ctx.cursor();
      
      for (int i = 0; i < this.extraKeys.length; i++) {
        NSKeyValueCodingAdditions.Utility.takeValueForKeyPath
          (setCursor, lExtraValues[i], this.extraKeys[i]);
      }
      
      this.extraValues = null;
    }
    
    /* call subtemplate */
    
    if (wofid != null) {
      boolean wasRenderingDisabled = _ctx.isRenderingDisabled();
      String  oldFragmentID        = _ctx.fragmentID();
      
      if (!wasRenderingDisabled) _ctx.disableRendering();
      _ctx.setFragmentID(wofid);
      
      content.appendToResponse(_r, _ctx);
      
      _ctx.setFragmentID(oldFragmentID);
      if (!wasRenderingDisabled) _ctx.enableRendering();
    }
    else {
      /* now we are in the parent component's context, continue there */
      content.appendToResponse(_r, _ctx);
    }
    
    /* back to own component */
    _ctx.enterComponent(component, content);
  }
}
