/*
 * ICESOFT COMMERCIAL SOURCE CODE LICENSE V 1.1
 *
 * The contents of this file are subject to the ICEsoft Commercial Source
 * Code License Agreement V1.1 (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.icesoft.com/license/commercial-source-v1.1.html
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations under
 * the License.
 *
 * Copyright 2009-2015 ICEsoft Technologies Canada, Corp. All Rights Reserved.
 */

package com.icesoft.components.accessible.panelpopup;

import com.icesoft.faces.component.ExtendedAttributeConstants;
import com.icesoft.faces.component.ext.renderkit.FormRenderer;
import com.icesoft.faces.component.ext.renderkit.GroupRenderer;
import com.icesoft.faces.component.paneltooltip.PanelTooltip;
import com.icesoft.components.accessible.util.CustomComponentUtils;
import com.icesoft.faces.context.DOMContext;
import com.icesoft.faces.context.effects.JavascriptContext;
import com.icesoft.faces.context.effects.LocalEffectEncoder;
import com.icesoft.faces.renderkit.dom_html_basic.HTML;
import com.icesoft.faces.renderkit.dom_html_basic.PassThruAttributeRenderer;
import com.icesoft.faces.util.CoreUtils;
import com.icesoft.components.accessible.util.CoreComponentUtils;
import com.icesoft.util.pooling.ClientIdPool;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import java.io.IOException;
import java.util.Map;

/**
 * <p>
 * PanelPopupRenderer is an extension of ICEfaces D2D GroupRenderer responsible
 * for rendering the PanelPopup component.
 * </p>
 */
public class PanelPopupRenderer extends GroupRenderer {
    private static Log log = LogFactory.getLog(PanelPopupRenderer.class);

    // Basically, everything is excluded
    private static final String[] PASSTHRU_EXCLUDE =
            new String[]{HTML.STYLE_ATTR};

    private static final String[] PASSTHRU_JS_EVENTS = LocalEffectEncoder.maskEvents(
            ExtendedAttributeConstants.getAttributes(
                    ExtendedAttributeConstants.ICE_PANELPOPUP));
    private static final String[] PASSTHRU =
            ExtendedAttributeConstants.getAttributes(
                    ExtendedAttributeConstants.ICE_PANELPOPUP,
                    new String[][]{PASSTHRU_EXCLUDE, PASSTHRU_JS_EVENTS});


    /*
      * (non-Javadoc)
      *
      * @see com.icesoft.faces.renderkit.dom_html_basic.GroupRenderer#getRendersChildren()
      */

    public boolean getRendersChildren() {
        return true;
    }

    /*
      * (non-Javadoc)
      *
      * @see com.icesoft.faces.component.ext.renderkit.GroupRenderer#encodeBegin(javax.faces.context.FacesContext,
      *      javax.faces.component.UIComponent)
      */

    public void encodeBegin(FacesContext facesContext, UIComponent uiComponent)
            throws IOException {
        validateParameters(facesContext, uiComponent, PanelPopup.class);

        String styleClass = (String) uiComponent.getAttributes().get(
                "styleClass");
        String headerClass = (String) uiComponent.getAttributes().get(
                "headerClass");
        String bodyClass = (String) uiComponent.getAttributes()
                .get("bodyClass");
        Boolean resizable = null; // resizable functionality has not been
        // implemented yet.
        Boolean modal = (Boolean) uiComponent.getAttributes().get("modal");
        if (log.isTraceEnabled()) {
            log.trace("Value of modal is [" + modal + "]");
        }
        Boolean visible = (Boolean) uiComponent.getAttributes().get("visible");

        String dndType = getDndType(uiComponent);

        DOMContext domContext = DOMContext.attachDOMContext(facesContext,
                uiComponent);

        // initialize DOMContext
        PanelPopup panelPopup = (PanelPopup) uiComponent;

        String clientId = uiComponent.getClientId(facesContext);
        
        if (CoreComponentUtils.isJavaScriptDisabled(facesContext) &&
        		visible.booleanValue()) {
        	Element bg = domContext.createRootElement(HTML.DIV_ELEM);
        	bg.setAttribute("class", "JSDISPnlPnlpopBg");
        	domContext.getCursorParent().appendChild(bg);
        	styleClass+= " JSDISPnlPop";
        }
        Element rootDiv = domContext.createRootElement(HTML.DIV_ELEM);
        setRootElementId(facesContext, rootDiv, uiComponent);
        rootDiv.setAttribute(HTML.NAME_ATTR, clientId);
        if (uiComponent instanceof PanelTooltip) {
            if (((PanelTooltip) uiComponent).isDynamic() && !((PanelTooltip) uiComponent).isVisible()) {
                rootDiv.setAttribute(HTML.STYLE_ATTR, "display:none;");
                domContext.stepOver();
                return;
            }
        }
        Element rootDiv2 = domContext.createElement(HTML.DIV_ELEM);
//			table.setAttribute(HTML.WIDTH_ATTR, "100%");
        rootDiv.appendChild(rootDiv2);
/*
        Text iframe = domContext.createTextNode("<!--[if lte IE 6.5]><iframe src=\"" +
                CoreUtils.resolveResourceURL(FacesContext.getCurrentInstance(), "/xmlhttp/blank") +
                "\" class=\"iceIEIFrameFix\" style=\"width:100%;height:100%;\"></iframe><![endif]-->");
        rootDiv.appendChild(iframe);
*/
        // extracted from GroupRenderer encodeBegin
        if (dndType != null) {
            // Drag an drop needs some hidden fields
            Element statusField = createHiddenField(domContext,
                    facesContext, uiComponent, STATUS);
            rootDiv.appendChild(statusField);
            Element targetID = createHiddenField(domContext, facesContext,
                    uiComponent, DROP);
            rootDiv.appendChild(targetID);
            UIComponent form = findForm(uiComponent);
            String formId = form.getClientId(facesContext);
            FormRenderer.addHiddenField(facesContext, ClientIdPool.get(formId + HIDDEN_FIELD));
        }
        // Write Modal Javascript so that on refresh it will still be modal.
        String script = modalJavascript(uiComponent, modal, visible, facesContext, clientId);
        Element scriptEle = domContext.createElement(HTML.SCRIPT_ELEM);
        scriptEle.setAttribute(HTML.ID_ATTR, ClientIdPool.get(clientId + "script"));
        scriptEle.setAttribute(HTML.SCRIPT_TYPE_ATTR, HTML.SCRIPT_TYPE_TEXT_JAVASCRIPT);
        Text scriptTextNode = domContext.createTextNodeUnescaped(script);
        scriptEle.appendChild(scriptTextNode);
        rootDiv.appendChild(scriptEle);

        Element root = (Element) domContext.getRootNode();

        try {
            root.setAttribute(HTML.CLASS_ATTR, styleClass);
        } catch (Exception e) {
            log.error("Error rendering Modal Panel Popup ", e);
        }
        JavascriptContext.fireEffect(uiComponent, facesContext);

        // get tables , our table is the first and only one
        NodeList divs = root.getElementsByTagName(HTML.DIV_ELEM);
        // assumption we want the first table in tables. there should only be
        // one
        Element t = (Element) divs.item(0);
        // clean out child nodes and build a fresh selectinputdate
        DOMContext.removeChildrenByTagName(t, HTML.TR_ELEM);

        doPassThru(facesContext, uiComponent, root);
        String handleId = null;
        if (panelPopup.getHeader() != null) {
            Element headerDiv = domContext.createElement(HTML.DIV_ELEM);
            headerDiv.setAttribute(HTML.CLASS_ATTR, headerClass);
            handleId = ClientIdPool.get(uiComponent.getClientId(facesContext) + "Handle");
            headerDiv.setAttribute(HTML.ID_ATTR, handleId);
//            headerTd.setAttribute(HTML.STYLE_ATTR, "width:100%;");
            // add header facet to header tr and add to table
            t.appendChild(headerDiv);
            // set the cursor parent to the new table row Element
            // to the new table row Element
            domContext.setCursorParent(headerDiv);

            UIComponent header = panelPopup.getHeader();
            CustomComponentUtils.renderChild(facesContext, header);
        }

        if (panelPopup.getBody() != null) {

            Element bodyDiv = domContext.createElement(HTML.DIV_ELEM);

            bodyDiv.setAttribute(HTML.CLASS_ATTR, bodyClass);
            // add body facet to body tr then add to table
            t.appendChild(bodyDiv);
            // set the cursor parent to the new table row Element
            // this will cause the renderChild method to append the child nodes
            // to the new table row Element
            domContext.setCursorParent(bodyDiv);

            UIComponent body = panelPopup.getBody();

            CustomComponentUtils.renderChild(facesContext, body);
        }
        // if the popup is resizable render a resize handle
        if (resizable != null && resizable.booleanValue()) {
            Element footerDiv = domContext.createElement(HTML.DIV_ELEM);
            footerDiv.setAttribute(HTML.HEIGHT_ATTR, "15px");
            footerDiv.setAttribute(HTML.STYLE_ATTR,
                    "text-align: right; float: right;");
            footerDiv.setAttribute(HTML.STYLE_CLASS_ATTR, "panelPopupFooter");
            Element img = domContext.createElement(HTML.IMG_ELEM);
            img.setAttribute(HTML.SRC_ATTR, CoreUtils.resolveResourceURL(
                    facesContext, "/xmlhttp/css/xp/css-images/resize.gif"));
            img.setAttribute(HTML.STYLE_ATTR, "cursor: se-resize");
            footerDiv.appendChild(img);
            t.appendChild(footerDiv);
        }

        panelPopup.applyStyle(facesContext, root);
        domContext.stepOver();

        // Rebroadcast Javascript to survive refresh
        if (dndType != null) {
            scriptTextNode.appendData("; Ice.DnD.adjustPosition('" + uiComponent.getClientId(facesContext) + "');");
            StringBuffer dropCall = new StringBuffer();
            String call = addJavascriptCalls(uiComponent, "DRAG", handleId,
                    facesContext, dropCall);
            scriptTextNode.appendData("; " + call);
            if (panelPopup.isClientOnly()) {
                //the "submit" method in the dragdrop_custom.js would check for this
                //element inside the panelPopup and will not fire submit if found
                Element clientOnly = domContext.createElement(HTML.INPUT_ELEM);
                clientOnly.setAttribute(HTML.TYPE_ATTR, "hidden");
                clientOnly.setAttribute(HTML.ID_ATTR, clientId + "clientOnly");
                root.appendChild(clientOnly);
            }
        }

        // autoPosition handling
        String autoPositionJS = null;
        boolean positionOnLoadOnly = panelPopup.isPositionOnLoadOnly();
        boolean dragged = panelPopup.isDragged();
        String positions = panelPopup.getAutoPosition();
        if (positions != null && !positions.equalsIgnoreCase("manual") && (!positionOnLoadOnly || (positionOnLoadOnly && !dragged))) {
            if (positions.indexOf(',') < 1) {
                if (positions.trim().length() != 0) {
                    log.warn("The autoPosition attribute should be used with an "
                            + " x and y value for the position, such as '20,40'");
                }
            } else {
                String x = positions.substring(0, positions.indexOf(','));
                String y = positions.substring(positions.indexOf(',') + 1);
                autoPositionJS = "Ice.autoPosition.start('" + clientId + "'," + x
                        + "," + y + ");";
            }

        } else {
            autoPositionJS = "Ice.autoPosition.stop('" + clientId + "');";
        }
        scriptTextNode.appendData("; " + autoPositionJS);

        // autoCentre handling
        boolean autoCentre = panelPopup.isAutoCentre();
        String centreJS;
        if (autoCentre && (!positionOnLoadOnly || (positionOnLoadOnly && !dragged))) {
            centreJS = "Ice.autoCentre.start('" + clientId + "');";
        } else {
            centreJS = "Ice.autoCentre.stop('" + clientId + "');";
        }

        scriptTextNode.appendData("; " + centreJS);

/*
        if (panelPopup instanceof PanelTooltip) {
            JavascriptContext.addJavascriptCall(facesContext, "ToolTipPanelPopupUtil.adjustPosition('" + clientId + "');");
        }
*/

        scriptTextNode.appendData("; Ice.iFrameFix.start('" + clientId + "','" +
                CoreUtils.resolveResourceURL(facesContext, "/xmlhttp/blank") + "');");
    }

    protected void doPassThru(FacesContext facesContext, UIComponent uiComponent,
                              Element root) {
        PassThruAttributeRenderer.renderNonBooleanHtmlAttributes(uiComponent,
                root, PASSTHRU);
        LocalEffectEncoder.encode(
                facesContext, uiComponent, PASSTHRU_JS_EVENTS, null, root, null);
    }

    private String modalJavascript(UIComponent uiComponent, Boolean modal, Boolean visible,
                                   FacesContext facesContext, String clientId) {
        String call = "";
        String iframeUrl = CoreUtils.resolveResourceURL(facesContext,
                "/xmlhttp/blank");
        if (modal != null) {
            if (modal.booleanValue() && visible.booleanValue()) {
                String trigger = "";
                // ICE-3563
                if (!((PanelPopup) uiComponent).isRunningModal()) {
                    Map requestParameterMap = facesContext.getExternalContext().getRequestParameterMap();
                    if (requestParameterMap.get("ice.focus") != null) {
                        trigger = (String) requestParameterMap.get("ice.focus");
                    }
                    ((PanelPopup) uiComponent).setRunningModal(true);
                    CoreComponentUtils.setFocusId("");
                }

                String autoPosition = (String) uiComponent.getAttributes().get("autoPosition");
                call = "Ice.modal.start('" + clientId + "', '" + iframeUrl
                        + "', '" + trigger + "'," + "manual".equalsIgnoreCase(autoPosition) + ");";
                if (log.isTraceEnabled()) {
                    log.trace("Starting Modal Function");
                }
            } else {
                // ICE-3563
                if (((PanelPopup) uiComponent).isRunningModal()) {
                    ((PanelPopup) uiComponent).setRunningModal(false);
                    CoreComponentUtils.setFocusId("");
                }
                call = "Ice.modal.stop('" + clientId + "');";
                if (log.isTraceEnabled()) {
                    log.trace("Stopping modal function");
                }
            }
        }
        return call;
    }

    /*
      * (non-Javadoc)
      *
      * @see com.icesoft.faces.renderkit.dom_html_basic.GroupRenderer#encodeChildren(javax.faces.context.FacesContext,
      *      javax.faces.component.UIComponent)
      */

    public void encodeChildren(FacesContext facesContext,
                               UIComponent uiComponent) throws IOException {
    }

    /*
      * (non-Javadoc)
      *
      * @see com.icesoft.faces.component.ext.renderkit.GroupRenderer#encodeEnd(javax.faces.context.FacesContext,
      *      javax.faces.component.UIComponent)
      */

    public void encodeEnd(FacesContext facesContext, UIComponent uiComponent)
            throws IOException {
        if (log.isTraceEnabled()) {
            log.trace("Encode End Called");
        }
    }
}