/*
 * JBoss, Home of Professional Open Source
 * Copyright ${year}, Red Hat, Inc. and individual contributors
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This 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.1 of
 * the License, or (at your option) any later version.
 *
 * This software 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 this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.richfaces.renderkit;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.faces.application.ResourceDependencies;
import javax.faces.application.ResourceDependency;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;

import org.ajax4jsf.javascript.JSFunction;
import org.richfaces.cdk.annotations.JsfRenderer;
import org.richfaces.component.AbstractCollapsibleSubTable;
import org.richfaces.component.AbstractCollapsibleSubTableToggler;
import org.richfaces.renderkit.util.RendererUtils;

import com.google.common.base.Strings;

/**
 * @author Anton Belevich
 */
@JsfRenderer(type = "org.richfaces.CollapsibleSubTableTogglerRenderer", family = AbstractCollapsibleSubTableToggler.COMPONENT_FAMILY)
@ResourceDependencies({ @ResourceDependency(library = "javax.faces", name = "jsf.js"),
        @ResourceDependency(library = "org.richfaces", name = "jquery.js"),
        @ResourceDependency(library = "org.richfaces", name = "richfaces.js"),
        @ResourceDependency(library = "org.richfaces", name = "richfaces-queue.reslib"),
        @ResourceDependency(library = "org.richfaces", name = "richfaces-event.js"),
        @ResourceDependency(library = "org.richfaces", name = "collapsible-subtable-toggler.js"),
        @ResourceDependency(library = "org.richfaces", name = "collapsible-subtable.ecss") })
public abstract class CollapsibleSubTableTogglerRendererBase extends RendererBase {
    /**
     *
     */
    private static final RendererUtils RENDERER_UTILS = RendererUtils.getInstance();
    private static final String DISPLAY_NONE = "display: none;";
    private static final String UP_ICON_URL = "org.richfaces/up_icon.gif";
    private static final String DOWN_ICON_URL = "org.richfaces/down_icon.gif";
    private static final String EXPANDED_STATE = "expanded";
    private static final String COLLAPSED_STATE = "collapsed";
    private static final String EXPANDED_CONTROL_CLASS = "rf-csttg-exp";
    private static final String COLLAPSED_CONTROL_CLASS = "rf-csttg-colps";

    @Override
    protected void doDecode(FacesContext context, UIComponent component) {
        // TODO - review
        context.getPartialViewContext().getRenderIds().add(component.getClientId(context));
    }

    protected void encodeControl(FacesContext context, UIComponent component) throws IOException {
        AbstractCollapsibleSubTableToggler toggleControl = (AbstractCollapsibleSubTableToggler) component;
        AbstractCollapsibleSubTable subTable = findComponent(context, toggleControl);

        if (subTable != null) {
            boolean expanded = subTable.isExpanded();

            ResponseWriter writer = context.getResponseWriter();
            encodeControl(context, writer, toggleControl, expanded, true);
            encodeControl(context, writer, toggleControl, !expanded, false);

            JSFunction jsFunction = new JSFunction("new RichFaces.ui.CollapsibleSubTableToggler");
            String toggleId = toggleControl.getClientId(context);
            jsFunction.addParameter(toggleId);
            Map<String, Object> options = encodeOptions(context, toggleControl, subTable);
            jsFunction.addParameter(options);

            writer.startElement(HtmlConstants.SCRIPT_ELEM, subTable);
            writer.writeText(jsFunction.toScript(), null);
            writer.endElement(HtmlConstants.SCRIPT_ELEM);
        }
    }

    private boolean isEmpty(String value) {
        return (value == null || value.trim().length() == 0);
    }

    protected void encodeControl(FacesContext context, ResponseWriter writer, AbstractCollapsibleSubTableToggler control,
        boolean expanded, boolean visible) throws IOException {
        String state = getState(expanded);
        String styleClass = getStyleClass(context, control);
        String style = getStyle(context, control);

        writer.startElement(HtmlConstants.SPAN_ELEM, control);

        if (!visible) {
            writer.writeAttribute(HtmlConstants.STYLE_ATTRIBUTE, DISPLAY_NONE, null);
        }

        writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE, control.getClientId(context) + ":" + state, null);
        writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE,
            concatClasses(styleClass, expanded ? EXPANDED_CONTROL_CLASS : COLLAPSED_CONTROL_CLASS), null);
        writer.writeAttribute(HtmlConstants.STYLE_ATTRIBUTE, style, null);

        UIComponent controlFacet = control.getFacet(state);
        if (controlFacet != null && controlFacet.isRendered()) {

            if (!visible) {
                String facetStyle = (String) controlFacet.getAttributes().get(HtmlConstants.STYLE_ATTRIBUTE);
                facetStyle = facetStyle != null ? facetStyle + ";" + DISPLAY_NONE : DISPLAY_NONE;
                controlFacet.getAttributes().put(HtmlConstants.STYLE_ATTRIBUTE, facetStyle);
            }
            controlFacet.encodeAll(context);
        }

        String expandedIcon = control.getExpandedIcon();
        if (isEmpty(expandedIcon)) {
            expandedIcon = context.getApplication().getResourceHandler().createResource(DOWN_ICON_URL).getRequestPath();
        } else {
            expandedIcon = RenderKitUtils.getResourceURL(expandedIcon, context);
        }

        String collapsedIcon = control.getCollapsedIcon();
        if (isEmpty(collapsedIcon)) {
            collapsedIcon = context.getApplication().getResourceHandler().createResource(UP_ICON_URL).getRequestPath();
        } else {
            collapsedIcon = RenderKitUtils.getResourceURL(collapsedIcon, context);
        }

        String image = expanded ? expandedIcon : collapsedIcon;
        if (image != null && image.trim().length() > 0) {
            writer.startElement(HtmlConstants.IMG_ELEMENT, control);
            writer.writeAttribute(HtmlConstants.SRC_ATTRIBUTE, image, null);
            writer.writeAttribute(HtmlConstants.ALT_ATTRIBUTE, "", null);
            writer.endElement(HtmlConstants.IMG_ELEMENT);
        }

        String label = expanded ? control.getExpandedLabel() : control.getCollapsedLabel();
        if (label != null && label.trim().length() > 0) {
            writer.startElement(HtmlConstants.A_ELEMENT, control);
            writer.writeAttribute(HtmlConstants.HREF_ATTR, "javascript:void(0);", null);
            writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-csttg-lnk", null);
            writer.writeText(label, null);
            writer.endElement(HtmlConstants.A_ELEMENT);
        }

        writer.endElement(HtmlConstants.SPAN_ELEM);
    }

    public HashMap<String, Object> encodeOptions(FacesContext context, AbstractCollapsibleSubTableToggler toggleControl,
        AbstractCollapsibleSubTable subTable) {
        String forId = subTable.getClientId(context);
        String toggleControlId = toggleControl.getClientId(context);

        HashMap<String, Object> options = new HashMap<String, Object>();
        options.put("forId", forId);
        options.put("expandedControl", toggleControlId + ":expanded");
        options.put("collapsedControl", toggleControlId + ":collapsed");

        String eventName = toggleControl.getEvent();

        if (Strings.isNullOrEmpty(eventName)) {
            eventName = AbstractCollapsibleSubTableToggler.DEFAULT_EVENT;
        }

        eventName = eventName.trim().startsWith("on") ? eventName.substring(2) : eventName;
        options.put("eventName", eventName);
        return options;
    }

    public String getStyleClass(FacesContext context, AbstractCollapsibleSubTableToggler control) {
        return null;
    }

    public String getStyle(FacesContext context, AbstractCollapsibleSubTableToggler control) {
        return null;
    }

    protected AbstractCollapsibleSubTable findComponent(FacesContext context, AbstractCollapsibleSubTableToggler toggleControl) {
        String forId = toggleControl.getFor();
        if (forId != null && forId.length() > 0) {

            UIComponent subTable = RENDERER_UTILS.findComponentFor(context, toggleControl, forId);
            if (subTable instanceof AbstractCollapsibleSubTable) {
                return (AbstractCollapsibleSubTable) subTable;
            }
        }
        return null;
    }

    protected String getState(boolean expanded) {
        return expanded ? EXPANDED_STATE : COLLAPSED_STATE;
    }
}