/*
 * � Copyright IBM Corp. 2010, 2011
 * 
 * Licensed 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 com.ibm.xsp.extlib.renderkit.html_extended.data;

import java.io.IOException;

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

import com.ibm.commons.util.StringUtil;
import com.ibm.xsp.component.FacesDataIterator;
import com.ibm.xsp.context.FacesContextEx;
import com.ibm.xsp.event.PagerEvent;
import com.ibm.xsp.extlib.component.data.AbstractPager;
import com.ibm.xsp.extlib.event.ExtlibPagerEvent;
import com.ibm.xsp.extlib.renderkit.html_extended.FacesRendererEx;
import com.ibm.xsp.extlib.util.ExtLibUtil;
import com.ibm.xsp.util.AjaxUtilEx;
import com.ibm.xsp.util.FacesUtil;
import com.ibm.xsp.util.HtmlUtil;
import com.ibm.xsp.util.JavaScriptUtil;


public abstract class AbstractPagerRenderer extends FacesRendererEx {

    protected static final int PROP_PAGERTAG        = 1;
    protected static final int PROP_PAGERSTYLE      = 2;
    protected static final int PROP_PAGERCLASS      = 3;
    protected static final int PROP_PAGERROLE       = 4;
    protected static final int PROP_FORCEID         = 5;
        
    @Override
    protected Object getProperty(int prop) {
        switch(prop) {
            case PROP_PAGERTAG:     return "span"; // $NON-NLS-1$
            case PROP_PAGERROLE:    return "navigation"; // $NON-NLS-1$
            // these controls don't have a dojoType so id not forced
            case PROP_FORCEID:      return false;
        }
        return super.getProperty(prop);
    }
    
    
    @Override
    public void decode(FacesContext context, UIComponent component) {
        super.decode(context, component);

        // check that this component cause the submit
        String currentClientId = component.getClientId(context);
        String hiddenValue = FacesUtil.getHiddenFieldValue(context);
        if(StringUtil.isNotEmpty(hiddenValue) && hiddenValue.startsWith(currentClientId)) {
            int pos = hiddenValue.lastIndexOf('_');
            if (pos==currentClientId.length()) {
                String idSuffix = hiddenValue.substring(pos+1);
                try {
                    ExtlibPagerEvent pagerEvent = new ExtlibPagerEvent(component);

                	//>tmg:a11y
                    pagerEvent.setClientId(hiddenValue);
                    //<tmg:a11y
                    
                    if(initPagerEvent(context, component, pagerEvent, idSuffix)) {
                        component.queueEvent(pagerEvent);
                    }
                } catch(Exception ex) {}
            }
        }
    }
    protected abstract boolean initPagerEvent(FacesContext context, UIComponent component, PagerEvent pagerEvent, String idSuffix);

    @Override
    public void encodeBegin(FacesContext context, UIComponent component)
            throws IOException {
        ResponseWriter w = context.getResponseWriter();
        if(!component.isRendered()) {
            return;
        }
        
        AbstractPager pager = (AbstractPager)component;
        FacesDataIterator dataIterator = pager.findDataIterator();

        if(dataIterator!=null) {
            writeMain(context, w, pager, dataIterator);
        }

        //>tmg:a11y
        String _pagerClientId = (String)HtmlUtil.readEncodeParameter(context, pager, AbstractPager.PAGER_CLIENT_ID, /*remove*/ true);
        if(null != _pagerClientId){
            StringBuilder js = new StringBuilder();
            js.append("XSP.setFocus("); //$NON-NLS-1$
            JavaScriptUtil.addString(js, _pagerClientId); // $NON-NLS-1$
            js.append(");\n"); //$NON-NLS-1$
            JavaScriptUtil.addScriptOnLoad(js.toString());
        }
        //<tmg:a11y
    }

    protected void writeMain(FacesContext context, ResponseWriter w, AbstractPager pager, FacesDataIterator dataIterator) throws IOException {
        String tag = (String)getProperty(PROP_PAGERTAG);
        if(StringUtil.isNotEmpty(tag)) {
            w.startElement(tag, null);
            
            boolean shouldWriteId = false;
            String componentId = pager.getId();
            if( HtmlUtil.isUserId(componentId) ){
                // user set an ID in the XPage source
                shouldWriteId = true;
            }
            boolean forceId = (Boolean) getProperty(PROP_FORCEID);
            if( forceId ){
                // this control needs to write out an ID attribute to the HTML source,
                // usually needed when a dojoType attribute is always written.
                shouldWriteId = true;
            }
            if( shouldWriteId ){
                String clientId = pager.getClientId(context);
                w.writeAttribute("id", clientId, null); // $NON-NLS-1$
            }
            String role = (String)getProperty(PROP_PAGERROLE);
            if(StringUtil.isNotEmpty(role)) {
                w.writeAttribute("role", role,null); // $NON-NLS-1$
            }
            String ariaLabel = pager.getAriaLabel();
            if(StringUtil.isNotEmpty(ariaLabel)) {
                w.writeAttribute("aria-label", ariaLabel, null); // $NON-NLS-1$
            }
            String title = pager.getTitle();
            if(StringUtil.isNotEmpty(title)) {
                w.writeAttribute("title", title, null); // $NON-NLS-1$
            }
            String style = ExtLibUtil.concatStyles(pager.getStyle(), (String)getProperty(PROP_PAGERSTYLE));
            if(StringUtil.isNotEmpty(style)) {
                w.writeAttribute("style", style, null); // $NON-NLS-1$
            }
            String clazz = ExtLibUtil.concatStyleClasses(pager.getStyleClass(),(String)getProperty(PROP_PAGERCLASS));
            if(StringUtil.isNotEmpty(clazz)) {
                w.writeAttribute("class", clazz,null); // $NON-NLS-1$
            }
        }
        
        writePagerContent(context, w, pager, dataIterator);
        
        if(StringUtil.isNotEmpty(tag)) {
            w.endElement(tag);
        }
    }
    
    protected abstract void writePagerContent(FacesContext context, ResponseWriter w, AbstractPager pager, FacesDataIterator dataIterator) throws IOException;
    

    protected void setupSubmitOnClick(FacesContext context, ResponseWriter w,
            AbstractPager pager, FacesDataIterator dataIterator, String clientId, String sourceId) throws IOException {
        boolean immediate = false;

        UIComponent subTree = ((FacesContextEx)context).getSubTreeComponent();
        
        boolean partialExec = pager.isPartialExecute();
        String execId = null;
        if (partialExec) {
            execId = pager.getClientId(context);
            immediate = true;
        } else {
            if(subTree!=null) {
                partialExec = true;
                execId = subTree.getClientId(context);
                immediate = true;
            }
        }

        boolean partialRefresh = pager.isPartialRefresh();
        String refreshId = null;
        if(partialRefresh) {
            UIComponent refreshComponent = pager.findSharedDataPagerParent();
            if (null == refreshComponent) {
                refreshComponent = (UIComponent) pager.findDataIterator();
            }
            refreshId = AjaxUtilEx.getRefreshId(context, refreshComponent);
        } else {
            if(subTree!=null) {
                partialRefresh = true;
                refreshId = subTree.getClientId(context);
            }
        }
        
        // call some JavaScript in xspClient.js
        final String event = "onclick"; // $NON-NLS-1$
        // Note, the onClick event is also triggered if the user tabs to the
        // image\link and presses enter (Not just when clicked with a
        // mouse).

        // When the source is clicked, put its id in the hidden field and
        // submit the form.
        StringBuilder buff = new StringBuilder();
        if (partialRefresh) {
            JavaScriptUtil.appendAttachPartialRefreshEvent(buff, sourceId,
                    sourceId, execId, event,
                    /* clientSideScriptName */null,
                    immediate ? JavaScriptUtil.VALIDATION_NONE
                            : JavaScriptUtil.VALIDATION_FULL,
                    /* refreshId */refreshId,
                    /* onstart */getOnStart(pager),
                    /* oncomplete */getOnComplete(pager),
                    /* onerror */getOnError(pager));
        } else {
            JavaScriptUtil.appendAttachEvent(buff, sourceId, sourceId, execId,
                    event,
                    /* clientSideScriptName */null,
                    /* submit */true,
                    immediate ? JavaScriptUtil.VALIDATION_NONE
                            : JavaScriptUtil.VALIDATION_FULL);
        }
        String script = buff.toString();

        // Add the script block we just generated.
        JavaScriptUtil.addScriptOnLoad(script);
    }
    
    protected String getOnStart(AbstractPager component) {
        return (String)component.getAttributes().get("onStart"); // $NON-NLS-1$
    }
    protected String getOnComplete(AbstractPager component) {
        return (String)component.getAttributes().get("onComplete"); // $NON-NLS-1$
    }
    protected String getOnError(AbstractPager component) {
        return (String)component.getAttributes().get("onError"); // $NON-NLS-1$
    }
    
}