/*
 *  Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you under the Apache License, Version 2.0 (the
 *  "License"); you may not use this file except in compliance
 *  with the License.  You may obtain a copy of the License at
 * 
 *  http://www.apache.org/licenses/LICENSE-2.0
 * 
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an
 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations
 *  under the License.
 */
package org.apache.myfaces.trinidadinternal.renderkit.html.layout;

import java.io.IOException;
import java.util.ListIterator;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;

import org.apache.myfaces.trinidad.component.UIXShowDetail;
import org.apache.myfaces.trinidad.context.RenderingContext;
import org.apache.myfaces.trinidad.logging.TrinidadLogger;
import org.apache.myfaces.trinidad.render.CoreRenderer;
import org.apache.myfaces.trinidad.render.RenderUtils;

import org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.SkinSelectors;
import org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.XhtmlConstants;
import org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.XhtmlUtils;
import org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.XhtmlRenderer;
import org.apache.myfaces.trinidadinternal.ui.UIConstants;
import org.apache.myfaces.trinidadinternal.ui.UIXRenderingContext;
import org.apache.myfaces.trinidadinternal.ui.laf.base.BaseLafUtils;
import org.apache.myfaces.trinidadinternal.ui.laf.base.xhtml.XhtmlLafRenderer;

/**
 * Renderer for PanelRadio
 *
 * @version $Name:  $ ($Revision: adfrt/faces/adf-faces-impl/src/main/java/oracle/adfinternal/view/faces/renderkit/html/layout/CoreShowOneRadioRenderer.java#0 $) $Date: 10-nov-2005.19:01:13 $
 */
public class CorePanelRadioRenderer extends ShowOneListRendererBase
{
  /**
   *  {@inheritDoc}
   */
  @Override
  protected void renderListDisplay(FacesContext context,
                                   UIComponent component,
                                   String disclosedChildId)
    throws IOException
  {
    _LOG.finest("CorePanelRadioRenderer.renderRadioFacet: " +
                "disclosedChildId: {0}" + disclosedChildId);

    // This renders the select controls alongwith javascript onchange handler.
    UIXRenderingContext rCtx = getRenderingContext(context, component);

    String compId = component.getClientId(context);

    ResponseWriter out = context.getResponseWriter();

    // draw table to contain the select UI control
    out.startElement("table", component);
    out.writeAttribute("id", compId + _RADIO_TABLE_SUFFIX_ID_CONST, null);
    out.writeAttribute("border", "0", null);
    out.writeAttribute("cellspacing", "0", null);
    out.writeAttribute("cellpadding", "0", null);

    if (!XhtmlLafRenderer.isInaccessibleMode(rCtx))
    {
      out.writeAttribute("summary", "", null);
    }

    out.startElement("tr", component);

    String label = (String)component.getAttributes().get("label");

    out.startElement("td", component);
    out.writeAttribute("align", "left", null);
    out.writeAttribute("nowrap", Boolean.TRUE, null);
    out.startElement("span", component);

    XhtmlLafRenderer.
      renderStyleClassAttribute(rCtx,
                                SkinSelectors.AF_LABEL_TEXT_STYLE_CLASS);

    if (label != null)
      out.writeText(label, null);

    out.endElement("span");
    out.endElement("td");

    // Render filler / separator between label and select control
    renderSpacerTD(out, component, getLabelControlSeparatorSize());

    _renderRadioItemsInTD(context,
                          component,
                          out,
                          rCtx,
                          compId,
                          disclosedChildId);

    out.endElement("tr");
    out.endElement("table");
  }

  /**
   *  Generates markup for rendering HTML radio controls.
   *
   *  Each radio control is corresponding to a rendered UIXShowDetail child.
   *  The disable showDetail children are shown as disabled radio buttons.
   */
  @SuppressWarnings("unchecked")
  private void _renderRadioItemsInTD(FacesContext context,
                                     UIComponent component,
                                     ResponseWriter out,
                                     UIXRenderingContext rCtx,
                                     String compId,
                                     String disclosedChildId)
    throws IOException
  {
    out.startElement("td", component);
    out.writeAttribute("valign", "top", null);
    out.writeAttribute("nowrap", Boolean.TRUE, null);

    String formName = RenderUtils.getFormId(context, component);

    // each of the radio buttons would occupy a td in a tr
    // so there will be as many rows as the number of children and each row
    // in turn will have only one td - to contain the radio button
    out.startElement("table", component);
    out.writeAttribute("id", compId + disclosedChildId, null);
    out.writeAttribute("summary", "", null);
    out.writeAttribute("border", "0", null);
    out.writeAttribute("cellspacing", "0", null);
    out.writeAttribute("cellpadding", "0", null);

    ListIterator<UIComponent> children = component.getChildren().listIterator();
    while (children.hasNext())
    {
      UIComponent child = children.next();
      if (! (child instanceof UIXShowDetail) )
      {
        continue;
        // Can't do any thing with non-showDetail children.
      }
      UIXShowDetail detailItem = (UIXShowDetail) child;

      String childClientId = child.getClientId(context);
      out.startElement("tr", component);
      out.startElement("td", component);

      boolean isRTL = BaseLafUtils.isRightToLeft(rCtx);
      if (isRTL)
      {
        out.writeAttribute("align", "right", null);
      }
      else
      {
        out.writeAttribute("align", "left", null);
      }
      out.writeAttribute("valign", "top", null);
      out.writeAttribute("nowrap", Boolean.TRUE, null);

      out.startElement("span", component);
      out.writeAttribute("id",
                         childClientId + _RADIO_SPAN_SUFFIX_ID_CONST,
                         null);

      Boolean disabledObj =
        (Boolean) detailItem.getAttributes().get(
          UIConstants.DISABLED_ATTR.getAttributeName());
      boolean disabled = false; // by default is enabled.
      if (disabledObj != null)
      {
        disabled = disabledObj.booleanValue();
      }

      if (! disclosedChildId.equals(childClientId) && (! disabled) )
      {
        boolean isImmediate = detailItem.isImmediate();
        String submitJS = _getRadioSubmitJS(component,
                                            rCtx,
                                            formName,
                                            compId,
                                            childClientId,
                                            isImmediate);
        //PH:onclick javascript handler for a HTML SPAN element is not supported
        //on PIE, IE Mobile or Blackberry 4.0. Therefore, create onclick 
        //javascript for non-PDAs only.
        if(!CoreRenderer.isPDA(RenderingContext.getCurrentInstance()))
          out.writeAttribute("onclick", submitJS, null);
      }

      // render the radio button now
      out.startElement("input", component);
      out.writeAttribute("id", childClientId, null);
      out.writeAttribute("value", childClientId, null);
      out.writeAttribute("name", compId, null);
        
      //PH: onclick javascript handler for an INPUT element is supported on a 
      //PDA. Therefore, create javascript for onclick on an INPUT element 
      //instead of a SPAN element.
      if(CoreRenderer.isPDA(RenderingContext.getCurrentInstance()))
      {
         boolean isImmediate = detailItem.isImmediate();
         String submitJS = _getRadioSubmitJS(component,
                                             rCtx,
                                             formName,
                                             compId,
                                             childClientId,
                                             isImmediate);
         out.writeAttribute("onclick", submitJS, null);
      }
      
      if (disabled)
      {
        out.writeAttribute("disabled", Boolean.TRUE, null);
      }

      out.writeAttribute("type", "radio", null);
      if (disclosedChildId.equals(childClientId) )
      {
        out.writeAttribute("checked", Boolean.TRUE, null);
      }
      out.endElement("input");

      out.startElement("label", component);
      out.writeAttribute("for", childClientId, null);

      Character accessChar =
        (Character) detailItem.getAttributes().get("accessKey");
      if (accessChar != null)
      {
        out.writeAttribute("accessKey", accessChar.toString(), null);
      }

      out.startElement("span", component);

      String radioSpanClass = getFieldTextClass();
      if (disabled)
      {
        radioSpanClass = SkinSelectors.AF_FIELD_TEXT_DISABLED_STYLE_CLASS;
      }
      XhtmlLafRenderer.renderStyleClassAttribute(rCtx,
                                                 radioSpanClass);

      writeLabel(out,
                 detailItem,
                 (String) detailItem.getAttributes().get("text"));

      out.endElement("span");
      out.endElement("label");
      out.endElement("span");
      out.endElement("td");
      out.endElement("tr");
    }

    // For Non-JavaScript browsers, render a input element(type= submit) to 
    // submit the page. Encode the name attribute with the parameter name 
    // and value thus it would enable the browsers to include the name of 
    // this element in its payLoad if it submits the page.

    if (!XhtmlRenderer.supportsScripting
                      (RenderingContext.getCurrentInstance()))
    {
      out.startElement("tr", component);
      out.startElement("td", component);

      if (BaseLafUtils.isRightToLeft(rCtx))
      {
        out.writeAttribute("align", "right", null);
      }
      else
      {
        out.writeAttribute("align", "left", null);
      }

      out.writeAttribute("valign", "top", null);
      out.writeAttribute("nowrap", Boolean.TRUE, null);

      String nameAttri = XhtmlUtils.getEncodedParameter
                                       (XhtmlConstants.MULTIPLE_VALUE_PARAM)
                         + XhtmlUtils.getEncodedParameter(compId)
                         + XhtmlUtils.getEncodedParameter
                                       (XhtmlConstants.EVENT_PARAM)
                         + XhtmlConstants.SHOW_EVENT;

      out.startElement("span", null);
      out.startElement("input", null);
      out.writeAttribute("value",XhtmlConstants.NO_JS_PARAMETER_KEY_BUTTON , null);
      out.writeAttribute("type","submit", null);
      out.writeAttribute("name", nameAttri, null);
      out.endElement("input");
      out.endElement("span");
      out.endElement("td");
      out.endElement("tr");

    }

    out.endElement("table");
    out.endElement("td");
  }

  /**
   *  Gets onclick javascript to be associated with radio onlcick event.
   *
   *  Checks if component is contained within a form, if not, returns null.
   *  Further, checks if PPR is supported and returns a script to be called
   *  for this case else returns a script where PPR is not required.
   */
  private String _getRadioSubmitJS(UIComponent component,
                                   UIXRenderingContext rCtx,
                                   String formName,
                                   String compId,
                                   String detailChildId,
                                   boolean isImmediate)
  {
    if (formName == null)
    {
      _LOG.warning("PAGE_NOT_CONTAIN_FORM_ELEMENT");
      return null;
    }

    String validate = "1";
    if (isImmediate)
    {
      validate = "0";
    }

    // Check if PPR enabled, do a _submitPartialChange, else do a formSubmit.
    String onClickHandler = "";
    boolean pprEnabled = elementSupportsPartial(rCtx, compId);
    if (pprEnabled)
    {
      //PH:If agent is of type PDA, call submitForm instead of doing a full
      //page submission since PPR on this component is not supported although
      //pprEnabled is true for PIE and IE Mobile
      if(CoreRenderer.isPDA(RenderingContext.getCurrentInstance())) 
      {
        StringBuilder jsBuff = new StringBuilder(135);
        jsBuff.append("submitForm('")
              .append(formName)
              .append("',")
              .append(validate)
              .append(",{event:'show',source:'")
              .append(detailChildId)
              .append("'});return true;");
              
        onClickHandler = jsBuff.toString();          
      }
      else
      {
        StringBuilder jsBuff = new StringBuilder(220);
        jsBuff.append("_submitPartialChange('")
              .append(formName)
              .append("',")
              .append(validate)
              .append(", {event:'show',source:'")
              .append(detailChildId)
              .append("'});return true;");
    
        onClickHandler = jsBuff.toString();
      }
    }
    else
    {
      StringBuilder jsBuff = new StringBuilder(135);
      jsBuff.append("submitForm('")
            .append(formName)
            .append("',")
            .append(validate)
            .append(",{event:'show',source:'")
            .append(detailChildId)
            .append("'});return true;");
      onClickHandler = jsBuff.toString();
    }
    return onClickHandler;
  }

  private static final String _RADIO_TABLE_SUFFIX_ID_CONST = "_sor_tbl";
  private static final String _RADIO_SPAN_SUFFIX_ID_CONST =
    _RADIO_TABLE_SUFFIX_ID_CONST + "_span";

  private static final TrinidadLogger _LOG =
    TrinidadLogger.createTrinidadLogger(CorePanelRadioRenderer.class);
}
