/**
 * 
 */
package org.richfaces.renderkit.html;

import java.io.IOException;
import java.io.Serializable;

import javax.faces.FacesException;
import javax.faces.context.FacesContext;

import org.ajax4jsf.javascript.JSFunction;
import org.ajax4jsf.javascript.JSFunctionDefinition;
import org.ajax4jsf.resource.InternetResource;
import org.ajax4jsf.resource.InternetResourceBuilder;
import org.ajax4jsf.resource.ResourceNotFoundException;
import org.ajax4jsf.webapp.WebXml;
import org.richfaces.component.UIColumn;
import org.richfaces.component.UIExtendedDataTable;

/**
 * Abstract renderer class for table menu.
 * 
 * @author pawelgo
 * 
 */
public abstract class TableMenuRenderer implements Serializable {

    public final static String CHANGE_COL_VISIBILITY = "change_col_v";

    protected FacesContext context;
    protected UIExtendedDataTable table;
    protected UIColumn column;

    protected JSFunction changeColumnVisibilityFunction;
    protected JSFunction sortFunction;
    protected JSFunction groupFunction;
    protected JSFunction prepareFunction;
    protected JSFunctionDefinition onAjaxCompleteFunction;

    protected static InternetResourceBuilder resourceBuilder;

    /**
     * Performs initial operations and renders table menu.
     * 
     * @param context
     *            faces context
     * @param table
     *            table component
     * @param column
     *            current column
     * @return created menu (DOM element) id
     * @throws IOException
     */
    public String renderMenu(FacesContext context, UIExtendedDataTable table,
            UIColumn column) throws IOException {
        this.context = context;
        this.table = table;
        this.column = column;
        return render();
    }

    /**
     * Renders table menu.
     * 
     * @return created menu (DOM element) id
     * @throws IOException
     */
    protected abstract String render() throws IOException;

    /**
     * Creates JavaScript code to be executed in order to show menu on some
     * event.
     * 
     * @return JavaScript code causes showing menu
     */
    public abstract JSFunctionDefinition createShowMenuEventFunction();

    /**
     * Base stub method for produce Internet resource ( image, script ... )
     * since resources must be implemented in "lightweight" pattern, it
     * instances put in internal map to caching.
     * 
     * @param resourceURI -
     *            relative ( to renderer class ) URI to resource in jar or key
     *            for generate ( in Java2D , for example ).
     * @return - resource instance for this URI.
     * @throws ResourceNotFoundException -
     *             if requested resource not instantiated.
     */
    public InternetResource getResource(String resourceURI)
            throws FacesException {
        return getResourceBuilder().createResource(null, resourceURI);
    }

    protected static InternetResourceBuilder getResourceBuilder() {
        if (resourceBuilder == null) {
            resourceBuilder = InternetResourceBuilder.getInstance();
        }
        return resourceBuilder;
    }

    protected String getUri(InternetResource resource, FacesContext context) {
        return getFacesResourceURL(context, resource.getKey());
    }// getUri

    protected String getFacesResourceURL(FacesContext context, String Url) {
        WebXml webXml = WebXml.getInstance(context);
        StringBuffer buf = new StringBuffer();
        buf.append(webXml.getResourcePrefix()).append(Url);
        // Insert suffix mapping
        if (webXml.isPrefixMapping()) {
            buf.insert(0, webXml.getFacesFilterPrefix());
        } else {
            int index;
            if ((index = buf.indexOf("?")) >= 0) {
                buf.insert(index, webXml.getFacesFilterSuffix());
            } else {
                buf.append(webXml.getFacesFilterSuffix());
            }
        }
        return buf.toString();
    }// getFacesResourceURL

    /**
     * Sets function to be called on complete AJAX request fired by menu action
     * 
     * @param functionDefinition
     *            function to be called on complete AJAX request
     */
    public void setOnAjaxCompleteFunction(
            JSFunctionDefinition functionDefinition) {
        this.onAjaxCompleteFunction = functionDefinition;
    }

    /**
     * Set JavaScript function for change column visibility.
     * 
     * @param changeColumnVisibilityFunction
     *            JavaScript function
     */
    public void setChangeColumnVisibilityFunction(
            JSFunction changeColumnVisibilityFunction) {
        this.changeColumnVisibilityFunction = changeColumnVisibilityFunction;
    }

    /**
     * Set JavaScript function for sort table.
     * 
     * @param sortFunction
     *            JavaScript function
     */
    public void setSortFunction(JSFunction sortFunction) {
        this.sortFunction = sortFunction;
    }

    /**
     * Set JavaScript function for group table.
     * 
     * @param groupFunction
     *            JavaScript function
     */
    public void setGroupFunction(JSFunction groupFunction) {
        this.groupFunction = groupFunction;
    }

    /**
     * Set JavaScript function called before send AJAX request.
     * 
     * @param prepareFunction
     *            JavaScript function
     */
    public void setPrepareFunction(JSFunction prepareFunction) {
        this.prepareFunction = prepareFunction;
    }

}
