/**
 * License Agreement.
 *
 *  JBoss RichFaces - Ajax4jsf Component Library
 *
 * Copyright (C) 2007  Exadel, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation.
 *
 * This library 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 library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 */

package org.richfaces.component;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.faces.component.UICommand;
import javax.faces.component.UIComponent;
import javax.faces.component.UIComponentBase;
import javax.faces.component.UIData;
import javax.faces.context.FacesContext;
import javax.faces.el.MethodBinding;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.FacesEvent;
import javax.faces.event.PhaseId;
import javax.faces.model.ListDataModel;

import org.ajax4jsf.component.AjaxComponent;
import org.ajax4jsf.event.AjaxEvent;
import org.ajax4jsf.renderkit.AjaxRendererUtils;
import org.ajax4jsf.renderkit.RendererUtils;
import org.richfaces.event.DataFilterSliderAdapter;
import org.richfaces.event.DataFilterSliderEvent;
import org.richfaces.event.DataFilterSliderListener;
import org.richfaces.event.DataFilterSliderSource;

/**
 * JSF component class
 */
public abstract class UIDataFltrSlider extends UICommand implements DataFilterSliderSource, AjaxComponent {

    /**
     * The component type for this component.
     */
    public static final String COMPONENT_TYPE = "org.richfaces.DataFilterSlider";

    public static final String COMPONENT_FAMILY = "org.richfaces.DataFilterSlider";

    private transient boolean _active = false;

    public boolean getRendersChildren() {
        return true;
    }

    public void addSliderListener(DataFilterSliderListener listener) {
        addFacesListener(listener);
    }

    public DataFilterSliderListener[] getSliderListeners() {
        return (DataFilterSliderListener[]) getFacesListeners(DataFilterSliderListener.class);
    }

    public void removeSliderListener(DataFilterSliderListener listener) {
        removeFacesListener(listener);
    }

    public void broadcast(FacesEvent event) throws AbortProcessingException {
        super.broadcast(event);
        if (event instanceof DataFilterSliderEvent){
        	
        	 FacesContext context = FacesContext.getCurrentInstance();
             AjaxRendererUtils.addRegionByName(context, this, this.getId());
             String forAttr = this.getFor();
             RendererUtils rendUtil = RendererUtils.getInstance();
             AjaxRendererUtils.addRegionByName(context, this, rendUtil.correctForIdReference(forAttr, this));
             
            if(getSliderListeners().length < 1){
                addSliderListener(new DataFilterSliderAdapter(getSliderListener()));
            }
        }

    }

    public void processDecodes(FacesContext context) {
        if (context == null)
            throw new NullPointerException();

        if (!isRendered())
            return;

        // decode the Slider component
        decode(context);
    }

    /**
     * @return Returns the active.
     */
    public boolean isActive() {
        return _active;
    }

    /**
     * @param active The active to set. This method should never be called from user code.
     */
    public void setActive(boolean active) {
        _active = active;
    }

    private Map getSession() {
        return getFacesContext().getExternalContext().getSessionMap();
    }

    private transient UIData _UIData;

    public UIData getUIData() {
        List ajaxSliderList = (ArrayList) getSession().get("UISliderList");
        _UIData = getDataTable();
        if (ajaxSliderList == null) {
            ListDataModel ajaxSliderLDM = new ListDataModel();
            ajaxSliderLDM.setWrappedData(_UIData.getValue());
            getSession().put("UISliderList", ajaxSliderLDM.getWrappedData());
        } else {
            _UIData.setValue(ajaxSliderList);
        }

        return _UIData;

    }

    /**
     * Finds the dataTable which id is mapped to the "for" property
     *
     * @return the dataTable component
     */
    protected UIData getDataTable() {
        String forAttribute = getFor();
        UIComponent forComp;
        if (forAttribute == null) {
            // DataScroller may be a child of uiData
            forComp = getParent();
        } else {
            forComp = RendererUtils.getInstance().findComponentFor(this, forAttribute);
        }
        if (forComp == null) {
            throw new IllegalArgumentException("could not find dataTable with id '"
                    + forAttribute + "'. If you are outside the naming container, try prepending the form name like for=\"form1:tableName\"");
        } else if (!(forComp instanceof UIData)) {
            throw new IllegalArgumentException("component with id '" + forAttribute
                    + "' must be of type " + UIData.class.getName() + ", not type "
                    + forComp.getClass().getName());
        }

        return (UIData) forComp;
    }

    public void resetDataTable() {
        getSession().remove("UISliderList");
        getDataTable().setValue(getDataTable().getValueBinding("#{" + getForValRef() + "}"));
    }

    public void filterDataTable(int sliderVal) {

        UIData dataTable = getUIData();
        List filteredDataTable = new ArrayList();
        List dataTableList = (ArrayList) dataTable.getValue();
        String filterByString;
        int objectVal;

        for (int i = 0; i < dataTableList.size(); i++) {
            Object o = dataTableList.get(i);

            try {

                filterByString = o.getClass().getMethod(getFilterBy(), null).invoke(o, null).toString();

                if (filterByString.indexOf(".") > 0) {
                    filterByString = filterByString.substring(0, filterByString.indexOf("."));
                }

                objectVal = Integer.parseInt(filterByString);

                if (objectVal < sliderVal) {
                    filteredDataTable.add(o);
                }

            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        getDataTable().setValue(filteredDataTable);

    }

    public String getSliderRange() {
        String sliderValues = "";

        int segmentTotal;
        int segmentTotalStart;

        if (getStartRange().intValue() == 0) {
            segmentTotal = (getEndRange().intValue() / getIncrement().intValue());
            //set slider start to 0
            segmentTotalStart = 0;
        } else {
            //subtract 1 for 0 based array
            segmentTotal = (getEndRange().intValue() / getIncrement().intValue()) - 1;
            //set the slider start for the loop
            segmentTotalStart = getStartRange().intValue();
        }
        int j = segmentTotalStart;

        for (int i = segmentTotalStart; i <= segmentTotal; i++) {
            if (i != 0) {
                //Check to see if we are at start of slider
                if (i != j){
                    //increment by number given
                    j = j + getIncrement().intValue();
                }
            } else {
                //start at specified range
                j = getStartRange().intValue();
            }

            if (i == segmentTotal) {
                //this is the end so no comma and exact specified
                sliderValues = sliderValues + getEndRange();
            } else {
                //add to string
                sliderValues = sliderValues + j + ",";
            }
        }
        return sliderValues;
    }

    public abstract void setSliderListener(MethodBinding binding);

    public abstract MethodBinding getSliderListener();

    public abstract String getTrackStyleClass();

    public abstract void setTrackStyleClass(String trackStyleClass);

    public abstract boolean isOnSlideSubmit();
    
    public abstract void setOnSlideSubmit(boolean value);
    
    public abstract boolean isStoreResults();

    public abstract void setStoreResults(boolean storeResults);

    public abstract String getForValRef();

    public abstract void setForValRef(String forValRef);

    public abstract String getFilterBy();

    public abstract void setFilterBy(String filterBy);

    public abstract String getFor();

    public abstract void setFor(String _for);

    public abstract void setStyleClass(String styleClass);

    public abstract String getStyleClass();

    public abstract void setFieldStyleClass(String fieldStyleClass);

    public abstract String getFieldStyleClass();

    public abstract Integer getStartRange();

    public abstract void setStartRange(Integer startRange);

    public abstract Integer getEndRange();

    public abstract void setEndRange(Integer endRange);

    public abstract Integer getIncrement();

    public abstract void setIncrement(Integer increment);

    public abstract String getRangeStyleClass();

    public abstract void setRangeStyleClass(String rangeStyleClass);

    public abstract boolean isTrailer();

    public abstract void setTrailer(boolean trailer);

    public abstract String getTrailerStyleClass();

    public abstract void setTrailerStyleClass(String trailerStyleClass);

    public abstract String getHandleStyleClass();

    public abstract void setHandleStyleClass(String handleStyleClass);

    public abstract Integer getHandleValue();

    public abstract void setHandleValue(Integer handleValue);

    public abstract boolean isManualInput();

    public abstract void setManualInput(boolean manualInput);


    protected FacesContext getFacesContext() {
        return FacesContext.getCurrentInstance();
    }

    public void decode(FacesContext context) {
        super.decode(context);
    }
    
}   
 
