gr.abiss.calipso.domain.ColumnHeading.java Source code

Java tutorial

Introduction

Here is the source code for gr.abiss.calipso.domain.ColumnHeading.java

Source

/*
 * Copyright (c) 2007 - 2010 Abiss.gr <info@abiss.gr>  
 *
 *  This file is part of Calipso, a software platform by www.Abiss.gr.
 *
 *  Calipso is free software: you can redistribute it and/or modify 
 *  it under the terms of the GNU Affero General Public License as published by 
 *  the Free Software Foundation, either version 3 of the License, or 
 *  (at your option) any later version.
 * 
 *  Calipso 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 Affero General Public License for more details.
 * 
 *  You should have received a copy of the GNU General Public License 
 *  along with Calipso. If not, see http://www.gnu.org/licenses/agpl.html
 * 
 * This file incorporates work released by the JTrac project and  covered 
 * by the following copyright and permission notice:  
 * 
 *   Copyright 2002-2005 the original author or authors.
 * 
 *   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 gr.abiss.calipso.domain;

import static gr.abiss.calipso.domain.ColumnHeading.Name.ASSET_TYPE;
import static gr.abiss.calipso.domain.ColumnHeading.Name.ASSIGNED_TO;
import static gr.abiss.calipso.domain.ColumnHeading.Name.DETAIL;
import static gr.abiss.calipso.domain.ColumnHeading.Name.DUE_TO;
import static gr.abiss.calipso.domain.ColumnHeading.Name.ID;
import static gr.abiss.calipso.domain.ColumnHeading.Name.LOGGED_BY;
import static gr.abiss.calipso.domain.ColumnHeading.Name.PLANNED_EFFORT;
import static gr.abiss.calipso.domain.ColumnHeading.Name.REPORTED_BY;
import static gr.abiss.calipso.domain.ColumnHeading.Name.SPACE;
import static gr.abiss.calipso.domain.ColumnHeading.Name.STATUS;
import static gr.abiss.calipso.domain.ColumnHeading.Name.SUMMARY;
import static gr.abiss.calipso.domain.ColumnHeading.Name.TIME_FROM_CREATION_TO_CLOSE;
import static gr.abiss.calipso.domain.ColumnHeading.Name.TIME_FROM_CREATION_TO_FIRST_REPLY;
import static gr.abiss.calipso.domain.ColumnHeading.Name.TIME_STAMP;
import static gr.abiss.calipso.domain.ColumnHeading.Name.TOTAL_RESPONSE_TIME;
import static gr.abiss.calipso.domain.FilterCriteria.Expression.BETWEEN;
import static gr.abiss.calipso.domain.FilterCriteria.Expression.CONTAINS;
import static gr.abiss.calipso.domain.FilterCriteria.Expression.EQ;
import static gr.abiss.calipso.domain.FilterCriteria.Expression.GT;
import static gr.abiss.calipso.domain.FilterCriteria.Expression.IN;
import static gr.abiss.calipso.domain.FilterCriteria.Expression.IS_NULL;
import static gr.abiss.calipso.domain.FilterCriteria.Expression.LT;
import static gr.abiss.calipso.domain.FilterCriteria.Expression.NOT_EQ;
import gr.abiss.calipso.CalipsoService;
import gr.abiss.calipso.domain.FilterCriteria.Expression;
import gr.abiss.calipso.util.DateUtils;
import gr.abiss.calipso.util.StdFieldsUtils;
import gr.abiss.calipso.wicket.EffortField;
import gr.abiss.calipso.wicket.components.formfields.CheckBoxMultipleChoice;

import org.apache.wicket.extensions.markup.html.form.DateTextField;
import org.apache.wicket.extensions.yui.calendar.DateField;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.log4j.Logger;
import org.apache.wicket.Component;
import org.apache.wicket.MarkupContainer;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.form.IChoiceRenderer;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.panel.Fragment;
import org.apache.wicket.model.PropertyModel;
import org.bouncycastle.asn1.cmp.OOBCertHash;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Restrictions;

/**
 * used to render columns in the search results table and also in the search
 * filter screen
 */
public class ColumnHeading implements Serializable {
    /**
     * Please make proper use of logging, see http://www.owasp.org/index.php/Category:Logging_and_Auditing_Vulnerability
     */
    private static final Logger logger = Logger.getLogger(ColumnHeading.class);
    private static final Map<String, Name> NAMES_MAP;

    // set up a static Map to resolve a String to our ColumnHeading.Name enum
    // value
    static {
        NAMES_MAP = new HashMap<String, Name>();
        for (Name n : Name.values()) {
            NAMES_MAP.put(n.text, n);
        }
    }

    /**
     * Resolve a String to a valid enum value for ColumnHeading.Name
     */
    private static Name convertToName(String text) {
        Name n = NAMES_MAP.get(text);
        if (n == null) {
            throw new RuntimeException("Bad name " + text);
        }
        return n;
    }

    /**
     * test if a given string is a valid column heading name
     */
    public static boolean isValidName(String text) {
        return NAMES_MAP.containsKey(text);
    }

    public static boolean isValidFieldOrColumnName(String text) {
        return isValidName(text) || Field.isValidName(text);
    }

    public enum Name {
        // name/text
        ID("id"), SUMMARY("summary"), DETAIL("detail"), LOGGED_BY("loggedBy"), REPORTED_BY("reportedBy"), STATUS(
                "status"), ASSIGNED_TO("assignedTo"), DUE_TO("dueTo"), TIME_STAMP("timeStamp"), SPACE(
                        "space"), ASSET_TYPE("assets"), TOTAL_RESPONSE_TIME(
                                "totalResponseTime"), TIME_FROM_CREATION_TO_FIRST_REPLY(
                                        "timeFromCreationToFirstReply"), TIME_FROM_CREATION_TO_CLOSE(
                                                "timeFromCreationToClose"), PLANNED_EFFORT(
                                                        "plannedEffort"), ORGANIZATION(
                                                                "organization"), USER("user");

        private String text;

        Name(String text) {
            this.text = text;
        }

        public String getText() {
            return text;
        }

        @Override
        public String toString() {
            return text;
        }

    }

    private Field field;
    private Name name;
    private String label;
    private boolean visible = true;
    private boolean isDbField = true;
    private boolean visibleCriterium = true;
    private Processor processor;

    private FilterCriteria filterCriteria = new FilterCriteria();

    // ---------------------------------------------------------------------------------------------

    public ColumnHeading(Name name) {
        this.name = name;
        if (name == DETAIL || name == SPACE) {
            visible = false;
        }

        if (name == TOTAL_RESPONSE_TIME || name == TIME_FROM_CREATION_TO_FIRST_REPLY
                || name == TIME_FROM_CREATION_TO_CLOSE) {
            isDbField = false;
            // visible = false;
        }

        if (name == TOTAL_RESPONSE_TIME) {
            visible = false;
            visibleCriterium = false;
        }

        processor = getProcessor();
    }

    // ---------------------------------------------------------------------------------------------
    /**
     * For standard fields, does not require DB-based localization
     */
    public ColumnHeading(Name name, Component c) {
        this(name);

        this.label = localize(name.getText(), c);
    }

    // ---------------------------------------------------------------------------------------------

    /**
     * For standard fields, does not require DB-based localization
     */
    public ColumnHeading(String name, Component c) {
        this(convertToName(name));

        this.label = localize(name, c);
    }

    // ---------------------------------------------------------------------------------------------

    public ColumnHeading(Field field, Space space) {
        this.field = field;

        this.label = space.getPropertyTranslationResourceKey(field.getName().getText());//field.getLabel();
        if (this.label == null) {
            this.label = field.getName().getText();
        }
        processor = getProcessor();
    }

    // ---------------------------------------------------------------------------------------------

    public boolean isField() {
        return field != null;
    }

    public boolean isDropDownType() {
        if (isField()) {
            return field.isDropDownType();
        } else {
            return name == LOGGED_BY || name == ASSIGNED_TO || name == REPORTED_BY || name == STATUS;
        }
    }

    private String localize(String key, Component c) {
        return c.getLocalizer().getString("item_list." + key, c);
    }

    public static List<ColumnHeading> getColumnHeadings(Space s, User u, Component c) {
        return getColumnHeadings(s, u, c, null);
    }

    public static List<ColumnHeading> getColumnHeadings(Space s, User u, Component c, CalipsoService calipso) {
        Map<StdField.Field, StdFieldMask> fieldMaskMap = u.getStdFieldsForSpace(s);

        List<ColumnHeading> list = new ArrayList<ColumnHeading>();
        list.add(new ColumnHeading(ID, c));
        if (s == null || s.isItemSummaryEnabled()) {
            list.add(new ColumnHeading(SUMMARY, c));
        }
        list.add(new ColumnHeading(DETAIL, c));
        list.add(new ColumnHeading(STATUS, c));
        list.add(new ColumnHeading(ASSIGNED_TO, c));
        list.add(new ColumnHeading(LOGGED_BY, c));
        list.add(new ColumnHeading(REPORTED_BY, c).setVisible(false));
        //logger.info("fieldMaskMap.get(StdField.Field.DUE_TO"+fieldMaskMap.get(StdField.Field.DUE_TO).getMask().getName());
        if (fieldMaskMap.get(StdField.Field.DUE_TO) != null
                && !fieldMaskMap.get(StdField.Field.DUE_TO).getMask().equals(StdFieldMask.Mask.HIDDEN)) {
            list.add(new ColumnHeading(StdField.Field.DUE_TO.getName(), c));
        } // if
        if (fieldMaskMap.get(StdField.Field.ASSET_TYPE) != null
                && !fieldMaskMap.get(StdField.Field.ASSET_TYPE).getMask().equals(StdFieldMask.Mask.HIDDEN)) {
            list.add(new ColumnHeading(StdField.Field.ASSET_TYPE.getName(), c));
        } // if

        list.add(new ColumnHeading(TOTAL_RESPONSE_TIME, c));

        if (fieldMaskMap.get(StdField.Field.TIME_FROM_CREATION_TO_FIRST_REPLY) != null && !fieldMaskMap
                .get(StdField.Field.TIME_FROM_CREATION_TO_FIRST_REPLY).getMask().equals(StdFieldMask.Mask.HIDDEN)) {
            list.add(new ColumnHeading(StdField.Field.TIME_FROM_CREATION_TO_FIRST_REPLY.getName(), c));
        } // if

        if (fieldMaskMap.get(StdField.Field.TIME_FROM_CREATION_TO_CLOSE) != null && !fieldMaskMap
                .get(StdField.Field.TIME_FROM_CREATION_TO_CLOSE).getMask().equals(StdFieldMask.Mask.HIDDEN)) {
            list.add(new ColumnHeading(StdField.Field.TIME_FROM_CREATION_TO_CLOSE.getName(), c));
        } // if

        if (fieldMaskMap.get(StdField.Field.PLANNED_EFFORT) != null
                && !fieldMaskMap.get(StdField.Field.PLANNED_EFFORT).getMask().equals(StdFieldMask.Mask.HIDDEN)) {
            list.add(new ColumnHeading(StdField.Field.PLANNED_EFFORT.getName(), c));
        } // if

        for (Field f : s.getMetadata().getFieldList()) {
            if (!f.getName().isFile()) {
                ColumnHeading ch = new ColumnHeading(f, s);
                if (f.getCustomAttribute() == null && calipso != null) {
                    f.setCustomAttribute(calipso.loadItemCustomAttribute(s, f.getName().getText()));
                }
                if (f.getCustomAttribute() != null) {
                    boolean show = f.getCustomAttribute().isShowInSearchResults();
                    ch.setVisible(show);
                    //logger.info("show: "+ch.isVisible());
                }
                //            else{
                //               logger.info("show: custom attr was null");
                //            }
                list.add(ch);
            }
        }
        list.add(new ColumnHeading(TIME_STAMP, c));

        return list;
    }

    public static List<ColumnHeading> getColumnHeadings(User u, Component c) {

        List<ColumnHeading> list = new ArrayList<ColumnHeading>();
        list.add(new ColumnHeading(ID, c));
        list.add(new ColumnHeading(SPACE, c));
        list.add(new ColumnHeading(SUMMARY, c));
        list.add(new ColumnHeading(DETAIL, c));
        list.add(new ColumnHeading(STATUS));
        list.add(new ColumnHeading(LOGGED_BY, c));
        list.add(new ColumnHeading(ASSIGNED_TO, c));
        list.add(new ColumnHeading(REPORTED_BY, c));

        if (!StdFieldsUtils.getFieldMask(u, new StdField(StdField.Field.DUE_TO)).getMask()
                .equals(StdFieldMask.Mask.HIDDEN)) {
            list.add(new ColumnHeading(StdField.Field.DUE_TO.getName(), c));
        }

        list.add(new ColumnHeading(TIME_STAMP, c));
        list.add(new ColumnHeading(TOTAL_RESPONSE_TIME, c));

        if (!StdFieldsUtils.getFieldMask(u, new StdField(StdField.Field.TIME_FROM_CREATION_TO_FIRST_REPLY))
                .getMask().equals(StdFieldMask.Mask.HIDDEN)) {
            list.add(new ColumnHeading(StdField.Field.TIME_FROM_CREATION_TO_FIRST_REPLY.getName(), c));
        }

        if (!StdFieldsUtils.getFieldMask(u, new StdField(StdField.Field.TIME_FROM_CREATION_TO_CLOSE)).getMask()
                .equals(StdFieldMask.Mask.HIDDEN)) {
            list.add(new ColumnHeading(StdField.Field.TIME_FROM_CREATION_TO_CLOSE.getName(), c));
        }

        if (!StdFieldsUtils.getFieldMask(u, new StdField(StdField.Field.ASSET_TYPE)).getMask()
                .equals(StdFieldMask.Mask.HIDDEN)) {
            list.add(new ColumnHeading(StdField.Field.ASSET_TYPE.getName(), c));
        }

        if (!StdFieldsUtils.getFieldMask(u, new StdField(StdField.Field.PLANNED_EFFORT)).getMask()
                .equals(StdFieldMask.Mask.HIDDEN)) {
            list.add(new ColumnHeading(StdField.Field.PLANNED_EFFORT.getName(), c));
        }

        return list;
    }

    public static List<ColumnHeading> getColumnHeadings(Space s) {
        List<ColumnHeading> list = new ArrayList<ColumnHeading>();
        list.add(new ColumnHeading(ID));
        if (s == null || s.isItemSummaryEnabled()) {
            list.add(new ColumnHeading(SUMMARY));
        }
        list.add(new ColumnHeading(DETAIL));
        list.add(new ColumnHeading(STATUS));
        list.add(new ColumnHeading(LOGGED_BY));
        list.add(new ColumnHeading(ASSIGNED_TO));
        list.add(new ColumnHeading(REPORTED_BY));
        list.add(new ColumnHeading(DUE_TO));
        list.add(new ColumnHeading(ASSET_TYPE));
        list.add(new ColumnHeading(TOTAL_RESPONSE_TIME));
        list.add(new ColumnHeading(TIME_FROM_CREATION_TO_FIRST_REPLY));
        list.add(new ColumnHeading(TIME_FROM_CREATION_TO_CLOSE));
        list.add(new ColumnHeading(PLANNED_EFFORT));

        for (Field f : s.getMetadata().getFieldList()) {

            //if(!f.getName().isFile()){
            list.add(new ColumnHeading(f, s));
            //}
        }
        list.add(new ColumnHeading(TIME_STAMP));

        return list;
    }

    public static List<ColumnHeading> getColumnHeadings(User u) {

        List<ColumnHeading> list = new ArrayList<ColumnHeading>();
        list.add(new ColumnHeading(ID));
        list.add(new ColumnHeading(SPACE));
        list.add(new ColumnHeading(SUMMARY));
        list.add(new ColumnHeading(DETAIL));
        list.add(new ColumnHeading(LOGGED_BY));
        list.add(new ColumnHeading(ASSIGNED_TO));
        list.add(new ColumnHeading(REPORTED_BY));
        list.add(new ColumnHeading(ASSET_TYPE));
        list.add(new ColumnHeading(DUE_TO));
        list.add(new ColumnHeading(TIME_STAMP));
        list.add(new ColumnHeading(TOTAL_RESPONSE_TIME));
        list.add(new ColumnHeading(TIME_FROM_CREATION_TO_FIRST_REPLY));
        list.add(new ColumnHeading(TIME_FROM_CREATION_TO_CLOSE));
        list.add(new ColumnHeading(PLANNED_EFFORT));

        return list;
    }

    public List<Expression> getValidFilterExpressions() {
        return processor.getValidFilterExpressions();
    }

    public Fragment getFilterUiFragment(MarkupContainer container, User user, Space space,
            CalipsoService calipsoService) {
        return processor.getFilterUiFragment(container, user, space, calipsoService);
    }

    public void addRestrictions(CustomCriteria customCriteria) {
        if (processor instanceof ProcessorCustom) {
            ProcessorCustom processorCustom = (ProcessorCustom) processor;
            processorCustom.addRestrictions(customCriteria);
        }
    }

    public void addRestrictions(DetachedCriteria criteria) {
        processor.addRestrictions(criteria);
    }

    public String getAsQueryString() {
        return processor.getAsQueryString();
    }

    public void loadFromQueryString(String s, User user, CalipsoService calipsoService) {
        processor.loadFromQueryString(s, user, calipsoService);
    }

    /**
     * also see description below for the private getProcessor() method
     */
    private abstract class Processor implements Serializable {

        /*
         * return the possible expressions (equals, greater-than etc) to show on
         * filter UI for selection
         */
        abstract List<Expression> getValidFilterExpressions();

        /*
         * return the wicket ui fragment that will be shown over ajax (based on
         * selected expression)
         */
        abstract Fragment getFilterUiFragment(MarkupContainer container, User user, Space space,
                CalipsoService calipsoService);

        /*
         * get as hibernate restriction and append to passed in criteria that
         * will be used to query the database
         */
        abstract void addRestrictions(DetachedCriteria criteria);

        /*
         * return a querystring representation of the filter criteria to create
         * a bookmarkable url
         */
        abstract String getAsQueryString();

        /*
         * load a querystring representation and initialize filter critera when
         * acting on a bookmarkable url
         */
        abstract void loadFromQueryString(String s, User user, CalipsoService calipsoService);

    }

    private abstract class ProcessorCustom extends Processor {
        abstract void addRestrictions(CustomCriteria customCriteria);
    }

    /**
     * this routine is a massive if-then construct that acts as a factory for
     * the right implementation of the responsibilities defined in the
     * "Processor" class (above) based on the type of ColumnHeading - the right
     * implementation will be returned. having everything in one place below,
     * makes it easy to maintain, as the logic of each of the methods are
     * closely interdependent for a given column type for e.g. the kind of
     * hibernate criteria needed depends on what is made available on the UI
     */
    private Processor getProcessor() {
        if (isField()) {
            switch (field.getName().getType()) {
            // ==============================================================

            case 1:
            case 2:
            case 3:
                return new Processor() {
                    List<Expression> getValidFilterExpressions() {
                        return getAsList(IN);
                    }

                    Fragment getFilterUiFragment(MarkupContainer container, User user, Space space,
                            CalipsoService calipsoService) {
                        final Fragment fragment = new Fragment("fragParent", "multiSelect", container);
                        //final Map<String, String> options = field.getOptions();
                        List<CustomAttributeLookupValue> lookupValues = calipsoService.findLookupValues(space,
                                field.getName().getText());
                        // TODO: create a leaf-node only finder method in calipso service
                        List<CustomAttributeLookupValue> leafLookupValues = new LinkedList<CustomAttributeLookupValue>();

                        // leaf selection only for now
                        for (CustomAttributeLookupValue val : lookupValues) {
                            if (CollectionUtils.isEmpty(val.getChildren())) {
                                leafLookupValues.add(val);
                            }
                        }
                        lookupValues = null;

                        final CheckBoxMultipleChoice choice = new CheckBoxMultipleChoice("values", leafLookupValues,
                                new IChoiceRenderer<CustomAttributeLookupValue>() {

                                    @Override
                                    public Object getDisplayValue(CustomAttributeLookupValue object) {
                                        return fragment.getString(object.getNameTranslationResourceKey());
                                    }

                                    @Override
                                    public String getIdValue(CustomAttributeLookupValue object, int index) {
                                        return object.getId() + "";
                                    }
                                });
                        fragment.add(choice);
                        choice.setModel(new PropertyModel(filterCriteria, "values"));
                        return fragment;
                    }

                    void addRestrictions(DetachedCriteria criteria) {
                        if (filterHasValueList()) {
                            List values = filterCriteria.getValues();
                            List<Integer> keys = new ArrayList<Integer>(values.size());
                            for (Object o : values) {
                                if (o instanceof CustomAttributeLookupValue) {
                                    CustomAttributeLookupValue val = (CustomAttributeLookupValue) o;
                                    keys.add(NumberUtils.createInteger(val.getId() + ""));
                                } else {
                                    keys.add(NumberUtils.createInteger(o + ""));
                                }
                            }
                            criteria.add(Restrictions.in(getNameText(), keys));
                        }
                    }

                    String getAsQueryString() {
                        return getQueryStringFromValueList();
                    }

                    void loadFromQueryString(String s, User user, CalipsoService calipsoService) {
                        setValueListFromQueryString(s);
                    }
                };
            // ==============================================================
            case 4: // decimal number
                return new Processor() {
                    List<Expression> getValidFilterExpressions() {
                        return getAsList(EQ, NOT_EQ, GT, LT, BETWEEN);
                    }

                    Fragment getFilterUiFragment(MarkupContainer container, User user, Space space,
                            CalipsoService calipsoService) {
                        Fragment fragment = new Fragment("fragParent", "textField", container);
                        TextField textField = new TextField("value", Double.class);
                        textField.setModel(new PropertyModel(filterCriteria, "value"));
                        fragment.add(textField);
                        if (filterCriteria.getExpression() == BETWEEN) {
                            TextField textField2 = new TextField("value2", Double.class);
                            textField2.setModel(new PropertyModel(filterCriteria, "value2"));
                            fragment.add(textField2);
                        } else {
                            fragment.add(new WebMarkupContainer("value2").setVisible(false));
                        }
                        return fragment;
                    }

                    void addRestrictions(DetachedCriteria criteria) {
                        if (filterHasValue()) {
                            Object value = filterCriteria.getValue();
                            switch (filterCriteria.getExpression()) {
                            case EQ:
                                criteria.add(Restrictions.eq(getNameText(), value));
                                break;
                            case NOT_EQ:
                                criteria.add(Restrictions.not(Restrictions.eq(name.text, value)));
                                break;
                            case GT:
                                criteria.add(Restrictions.gt(getNameText(), value));
                                break;
                            case LT:
                                criteria.add(Restrictions.lt(getNameText(), value));
                                break;
                            case BETWEEN:
                                criteria.add(Restrictions.gt(getNameText(), value));
                                criteria.add(Restrictions.lt(getNameText(), filterCriteria.getValue2()));
                                break;
                            default:
                            }
                        }
                    }

                    String getAsQueryString() {
                        return getQueryStringFromValue(Double.class);
                    }

                    void loadFromQueryString(String s, User user, CalipsoService calipsoService) {
                        setValueFromQueryString(s, Double.class);
                    }

                };
            // ==============================================================
            case 6: // date
                return new Processor() {
                    List<Expression> getValidFilterExpressions() {
                        return getAsList(EQ, NOT_EQ, GT, LT, BETWEEN);
                    }

                    Fragment getFilterUiFragment(MarkupContainer container, User user, Space space,
                            CalipsoService calipsoService) {
                        Fragment fragment = new Fragment("fragParent", "dateField", container);
                        DateField calendar = new DateField("value",
                                new PropertyModel(filterCriteria, "value")/*,
                                                                          false*/);
                        fragment.add(calendar);
                        if (filterCriteria.getExpression() == BETWEEN) {
                            DateField calendar2 = new DateField("value2",
                                    new PropertyModel(filterCriteria, "value2")/*,
                                                                               false*/);
                            fragment.add(calendar2);
                        } else {
                            fragment.add(new WebMarkupContainer("value2").setVisible(false));
                        }
                        return fragment;
                    }

                    void addRestrictions(DetachedCriteria criteria) {
                        if (filterHasValue()) {
                            Object value = filterCriteria.getValue();
                            switch (filterCriteria.getExpression()) {
                            case EQ:
                                criteria.add(Restrictions.eq(getNameText(), value));
                                break;
                            case NOT_EQ:
                                criteria.add(Restrictions.not(Restrictions.eq(getNameText(), value)));
                                break;
                            case GT:
                                criteria.add(Restrictions.gt(getNameText(), value));
                                break;
                            case LT:
                                criteria.add(Restrictions.lt(getNameText(), value));
                                break;
                            case BETWEEN:
                                criteria.add(Restrictions.gt(getNameText(), value));
                                criteria.add(Restrictions.lt(getNameText(), filterCriteria.getValue2()));
                                break;
                            default:
                            }
                        }
                    }

                    String getAsQueryString() {
                        return getQueryStringFromValue(Date.class);
                    }

                    void loadFromQueryString(String s, User user, CalipsoService calipsoService) {
                        setValueFromQueryString(s, Date.class);
                    }
                };
            // ==============================================================
            case 5: // free text
                return new Processor() {
                    List<Expression> getValidFilterExpressions() {
                        return getAsList(CONTAINS);
                    }

                    Fragment getFilterUiFragment(MarkupContainer container, User user, Space space,
                            CalipsoService calipsoService) {
                        return getTextFieldFragment(container);
                    }

                    void addRestrictions(DetachedCriteria criteria) {
                        if (filterHasValue()) {
                            criteria.add(Restrictions.ilike(getNameText(), (String) filterCriteria.getValue(),
                                    MatchMode.ANYWHERE));
                        }
                    }

                    String getAsQueryString() {
                        return getQueryStringFromValue(String.class);
                    }

                    void loadFromQueryString(String s, User user, CalipsoService calipsoService) {
                        setValueFromQueryString(s, String.class);
                    }
                };
            // TODO:
            case 10:// organization
                return new Processor() {
                    List<Expression> getValidFilterExpressions() {
                        return getAsList(CONTAINS);
                    }

                    Fragment getFilterUiFragment(MarkupContainer container, User user, Space space,
                            CalipsoService calipsoService) {
                        return getTextFieldFragment(container);
                    }

                    void addRestrictions(DetachedCriteria criteria) {
                        if (filterHasValue()) {
                            criteria.add(Restrictions.ilike(getNameText(), (String) filterCriteria.getValue(),
                                    MatchMode.ANYWHERE));
                        }
                    }

                    String getAsQueryString() {
                        return getQueryStringFromValue(String.class);
                    }

                    void loadFromQueryString(String s, User user, CalipsoService calipsoService) {
                        setValueFromQueryString(s, String.class);
                    }
                };
            // TODO:
            case 11:// file
                return new Processor() {
                    List<Expression> getValidFilterExpressions() {
                        return getAsList(CONTAINS);
                    }

                    Fragment getFilterUiFragment(MarkupContainer container, User user, Space space,
                            CalipsoService calipsoService) {
                        return getTextFieldFragment(container);
                    }

                    void addRestrictions(DetachedCriteria criteria) {
                        if (filterHasValue()) {
                            criteria.add(Restrictions.ilike(getNameText(), (String) filterCriteria.getValue(),
                                    MatchMode.ANYWHERE));
                        }
                    }

                    String getAsQueryString() {
                        return getQueryStringFromValue(String.class);
                    }

                    void loadFromQueryString(String s, User user, CalipsoService calipsoService) {
                        setValueFromQueryString(s, String.class);
                    }
                };
            case 200:// attachment
                return new Processor() {
                    List<Expression> getValidFilterExpressions() {
                        return getAsList(CONTAINS);
                    }

                    Fragment getFilterUiFragment(MarkupContainer container, User user, Space space,
                            CalipsoService calipsoService) {
                        return getTextFieldFragment(container);
                    }

                    void addRestrictions(DetachedCriteria criteria) {
                        if (filterHasValue()) {
                            criteria.add(Restrictions.ilike(getNameText(), (String) filterCriteria.getValue(),
                                    MatchMode.ANYWHERE));
                        }
                    }

                    String getAsQueryString() {
                        return getQueryStringFromValue(String.class);
                    }

                    void loadFromQueryString(String s, User user, CalipsoService calipsoService) {
                        setValueFromQueryString(s, String.class);
                    }
                };
            case 20:// is user
                return new Processor() {
                    List<Expression> getValidFilterExpressions() {
                        return getAsList(CONTAINS);
                    }

                    Fragment getFilterUiFragment(MarkupContainer container, User user, Space space,
                            CalipsoService calipsoService) {
                        return getTextFieldFragment(container);
                    }

                    void addRestrictions(DetachedCriteria criteria) {
                        if (filterHasValue()) {
                            criteria.add(Restrictions.ilike(getNameText(), (String) filterCriteria.getValue(),
                                    MatchMode.ANYWHERE));
                        }
                    }

                    String getAsQueryString() {
                        return getQueryStringFromValue(String.class);
                    }

                    void loadFromQueryString(String s, User user, CalipsoService calipsoService) {
                        setValueFromQueryString(s, String.class);
                    }
                };

            case 25:// is user
                return new Processor() {
                    List<Expression> getValidFilterExpressions() {
                        return getAsList(CONTAINS);
                    }

                    Fragment getFilterUiFragment(MarkupContainer container, User user, Space space,
                            CalipsoService calipsoService) {
                        return getTextFieldFragment(container);
                    }

                    void addRestrictions(DetachedCriteria criteria) {
                        if (filterHasValue()) {
                            criteria.add(Restrictions.ilike(getNameText(), (String) filterCriteria.getValue(),
                                    MatchMode.ANYWHERE));
                        }
                    }

                    String getAsQueryString() {
                        return getQueryStringFromValue(String.class);
                    }

                    void loadFromQueryString(String s, User user, CalipsoService calipsoService) {
                        setValueFromQueryString(s, String.class);
                    }
                };
            case 100: // Assignable spaces (move to space)
                return new Processor() {
                    List<Expression> getValidFilterExpressions() {
                        return getAsList(IN);
                    }

                    Fragment getFilterUiFragment(MarkupContainer container, User user, Space space,
                            CalipsoService calipsoService) {
                        Fragment fragment = new Fragment("fragParent", "multiSelect", container);
                        final Map<String, String> options = field.getOptions();
                        List<String> keys = null;
                        if (options != null) {
                            keys = new ArrayList(options.keySet()); // bound
                            // value
                        } else {
                            keys = new ArrayList();
                        }

                        List<Space> spaces = new LinkedList<Space>();
                        for (String key : keys) {
                            // spaces.add(ComponentUtils.getJtrac(c).loadSpace(Long.parseLong(key)));
                            spaces.add(calipsoService.loadSpace(Long.parseLong(key)));
                        } // for
                        CheckBoxMultipleChoice choice = new CheckBoxMultipleChoice("values", spaces,
                                new IChoiceRenderer<Space>() {
                                    private static final long serialVersionUID = 1L;

                                    @Override
                                    public Object getDisplayValue(Space o) {
                                        logger.info("Option for space: " + o);
                                        String name = o.getName();
                                        return name != null ? name : o.getId();
                                    }

                                    @Override
                                    public String getIdValue(Space o, int index) {
                                        return o.getId() + "";
                                    }
                                });

                        fragment.add(choice);
                        choice.setModel(new PropertyModel(filterCriteria, "values"));
                        return fragment;
                    }

                    void addRestrictions(DetachedCriteria criteria) {
                        if (filterHasValueList()) {
                            List values = filterCriteria.getValues();
                            criteria.add(Restrictions.in(getNameText(), values));
                        }
                    }

                    String getAsQueryString() {
                        return getQueryStringFromValueList();
                    }

                    void loadFromQueryString(String s, User user, CalipsoService calipsoService) {
                        setValueListFromQueryString(s);
                    }
                };
            // ==============================================================
            default:
                throw new RuntimeException("Unknown Column Heading " + name);
            }
        } else { // this is not a custom field but one of the "built-in" columns
            switch (name) {
            // ==============================================================
            case ID:
                return new Processor() {
                    List<Expression> getValidFilterExpressions() {
                        return getAsList(EQ);
                    }

                    Fragment getFilterUiFragment(MarkupContainer container, User user, Space space,
                            CalipsoService calipsoService) {
                        return getTextFieldFragment(container);
                    }

                    void addRestrictions(DetachedCriteria criteria) {
                        if (filterHasValue()) {
                            // should never come here for criteria: see
                            // ItemSearch#getRefId()
                            throw new RuntimeException("should not come here for 'id'");
                        }
                    }

                    String getAsQueryString() {
                        return getQueryStringFromValue(String.class);
                    }

                    void loadFromQueryString(String s, User user, CalipsoService calipsoService) {
                        setValueFromQueryString(s, String.class);
                    }
                };
            // ==============================================================
            case SUMMARY:
                return new Processor() {
                    List<Expression> getValidFilterExpressions() {
                        return getAsList(CONTAINS);
                    }

                    Fragment getFilterUiFragment(MarkupContainer container, User user, Space space,
                            CalipsoService calipsoService) {
                        return getTextFieldFragment(container);
                    }

                    void addRestrictions(DetachedCriteria criteria) {
                        if (filterHasValue()) {
                            criteria.add(Restrictions.ilike(getNameText(), (String) filterCriteria.getValue(),
                                    MatchMode.ANYWHERE));
                        }
                    }

                    String getAsQueryString() {
                        return getQueryStringFromValue(String.class);
                    }

                    void loadFromQueryString(String s, User user, CalipsoService calipsoService) {
                        setValueFromQueryString(s, String.class);
                    }
                };
            // ==============================================================
            case DETAIL:
                return new Processor() {
                    List<Expression> getValidFilterExpressions() {
                        return getAsList(CONTAINS);
                    }

                    Fragment getFilterUiFragment(MarkupContainer container, User user, Space space,
                            CalipsoService calipsoService) {
                        return getTextFieldFragment(container);
                    }

                    void addRestrictions(DetachedCriteria criteria) {
                        // do nothing, 'detail' already processed, see:
                        // ItemSearch#getSearchText()
                    }

                    String getAsQueryString() {
                        return getQueryStringFromValue(String.class);
                    }

                    void loadFromQueryString(String s, User user, CalipsoService calipsoService) {
                        setValueFromQueryString(s, String.class);
                    }
                };

            // ==============================================================
            case STATUS:
                return new Processor() {
                    List<Expression> getValidFilterExpressions() {
                        return getAsList(IN);
                    }

                    Fragment getFilterUiFragment(MarkupContainer container, User user, Space space,
                            CalipsoService calipsoService) {
                        Fragment fragment = new Fragment("fragParent", "multiSelect", container);
                        // status selectable only when context space is not null
                        // final Map<Integer, String> options =
                        // space.getMetadata().getStatesMap();
                        final Map<Integer, String> options;
                        if (space == null) {
                            options = State.getSpecialStates();
                        } else {
                            options = space.getMetadata().getStatesMap();
                        }
                        options.remove(State.NEW);
                        CheckBoxMultipleChoice choice = new CheckBoxMultipleChoice("values",
                                new ArrayList(options.keySet()), new IChoiceRenderer() {
                                    public Object getDisplayValue(Object o) {
                                        return options.get(o);
                                    }

                                    public String getIdValue(Object o, int i) {
                                        return o.toString();
                                    }
                                });
                        fragment.add(choice);
                        choice.setModel(new PropertyModel(filterCriteria, "values"));
                        return fragment;
                    }

                    void addRestrictions(DetachedCriteria criteria) {
                        if (filterHasValueList()) {
                            criteria.add(Restrictions.in(getNameText(), filterCriteria.getValues()));
                        }
                    }

                    String getAsQueryString() {
                        return getQueryStringFromValueList();
                    }

                    void loadFromQueryString(String s, User user, CalipsoService calipsoService) {
                        //logger.info("loadFromQueryString: "+s);
                        setStatusListFromQueryString(s);
                    }
                };
            // ==============================================================
            case ASSIGNED_TO:
            case LOGGED_BY:
            case REPORTED_BY:
                return new Processor() {
                    List<Expression> getValidFilterExpressions() {
                        return getAsList(IN, IS_NULL);
                    }

                    Fragment getFilterUiFragment(MarkupContainer container, User user, Space space,
                            CalipsoService calipsoService) {
                        Fragment fragment = new Fragment("fragParent", "multiSelect", container);
                        List<User> users = null;
                        if (space == null) {
                            users = calipsoService.findUsersForUser(user);
                        } else {
                            users = calipsoService.findUsersForSpace(space.getId());
                        }
                        CheckBoxMultipleChoice choice = new CheckBoxMultipleChoice("values", users,
                                new IChoiceRenderer() {
                                    public Object getDisplayValue(Object o) {
                                        return ((User) o).getFullName();
                                    }

                                    public String getIdValue(Object o, int i) {
                                        return ((User) o).getId() + "";
                                    }
                                });
                        fragment.add(choice);
                        choice.setModel(new PropertyModel(filterCriteria, "values"));
                        return fragment;
                    }

                    void addRestrictions(DetachedCriteria criteria) {
                        if (filterHasValueList()) {
                            criteria.add(Restrictions.in(getNameText(), filterCriteria.getValues()));
                        } else if (filterIsNullExpression()) {
                            criteria.add(Restrictions.isNull(getNameText()));
                        }
                    }

                    String getAsQueryString() {
                        return getQueryStringFromUserList();
                    }

                    void loadFromQueryString(String s, User user, CalipsoService calipsoService) {
                        setUserListFromQueryString(s, calipsoService);
                    }
                };
            // ==============================================================

            case ASSET_TYPE:
                return new Processor() {
                    List<Expression> getValidFilterExpressions() {
                        return getAsList(IN);
                    }

                    Fragment getFilterUiFragment(MarkupContainer container, User user, Space space,
                            CalipsoService calipsoService) {
                        Fragment fragment = new Fragment("fragParent", "multiSelect", container);

                        List<AssetType> assetTypes = calipsoService.findAllAssetTypes();
                        CheckBoxMultipleChoice choice = new CheckBoxMultipleChoice("values", assetTypes,
                                new IChoiceRenderer() {
                                    public Object getDisplayValue(Object o) {
                                        return ((AssetType) o).getName();
                                    }

                                    public String getIdValue(Object o, int i) {
                                        return String.valueOf(((AssetType) o).getId());
                                    }
                                });
                        fragment.add(choice);
                        choice.setModel(new PropertyModel(filterCriteria, "values"));

                        return fragment;
                    }

                    void addRestrictions(DetachedCriteria criteria) {
                        if (filterHasValueList()) {
                            criteria.createAlias("assets", "assets");
                            criteria.add(Restrictions.in("assets.assetType", filterCriteria.getValues()));
                        }
                    }

                    String getAsQueryString() {
                        return getQueryStringFromAssetTypeList();
                    }

                    void loadFromQueryString(String s, User user, CalipsoService calipsoService) {
                        setAssetTypeListFromQueryString(s, user, calipsoService);
                    }
                };
            // ==============================================================
            case TIME_STAMP:
            case DUE_TO:
                return new Processor() {
                    List<Expression> getValidFilterExpressions() {
                        return getAsList(BETWEEN, GT, LT, EQ, NOT_EQ);
                    }

                    Fragment getFilterUiFragment(MarkupContainer container, User user, Space space,
                            CalipsoService calipsoService) {
                        Fragment fragment = new Fragment("fragParent", "dateField", container);
                        DateField calendar = new DateField("value",
                                new PropertyModel(filterCriteria, "value")/*,
                                                                          false*/);
                        fragment.add(calendar);
                        if (filterCriteria.getExpression() == BETWEEN) {
                            DateField calendar2 = new DateField("value2",
                                    new PropertyModel(filterCriteria, "value2")/*,
                                                                               false*/);
                            fragment.add(calendar2);
                        } else {
                            fragment.add(new WebMarkupContainer("value2").setVisible(false));
                        }
                        return fragment;
                    }

                    void addRestrictions(DetachedCriteria criteria) {
                        if (filterHasValue()) {
                            Object value = filterCriteria.getValue();
                            switch (filterCriteria.getExpression()) {
                            case EQ:
                                criteria.add(Restrictions.eq(getNameText(), value));
                                break;
                            case NOT_EQ:
                                criteria.add(Restrictions.not(Restrictions.eq(getNameText(), value)));
                                break;
                            case GT:
                                criteria.add(Restrictions.gt(getNameText(), value));
                                break;
                            case LT:
                                criteria.add(Restrictions.lt(getNameText(), value));
                                break;
                            case BETWEEN:
                                criteria.add(Restrictions.gt(getNameText(), value));
                                criteria.add(Restrictions.lt(getNameText(), filterCriteria.getValue2()));
                                break;
                            default:
                            }
                        }
                    }

                    String getAsQueryString() {
                        return getQueryStringFromValue(Date.class);
                    }

                    void loadFromQueryString(String s, User user, CalipsoService calipsoService) {
                        setValueFromQueryString(s, Date.class);
                    }
                };
            // ==============================================================
            case SPACE:
                return new Processor() {
                    List<Expression> getValidFilterExpressions() {
                        return getAsList(IN);
                    }

                    Fragment getFilterUiFragment(MarkupContainer container, User user, Space space,
                            CalipsoService calipsoService) {
                        Fragment fragment = new Fragment("fragParent", "multiSelect", container);
                        List<Space> spaces = new ArrayList(user.getSpaces());
                        CheckBoxMultipleChoice choice = new CheckBoxMultipleChoice("values", spaces,
                                new IChoiceRenderer() {
                                    public Object getDisplayValue(Object o) {
                                        return ((Space) o).getName();
                                    }

                                    public String getIdValue(Object o, int i) {
                                        return ((Space) o).getId() + "";
                                    }
                                });
                        fragment.add(choice);
                        choice.setModel(new PropertyModel(filterCriteria, "values"));
                        return fragment;
                    }

                    void addRestrictions(DetachedCriteria criteria) {
                        // already handled space as special case, see
                        // ItemSearch#getSelectedSpaces()
                    }

                    String getAsQueryString() {
                        return getQueryStringFromSpaceList();
                    }

                    void loadFromQueryString(String s, User user, CalipsoService calipsoService) {
                        setSpaceListFromQueryString(s, user, calipsoService);
                    }
                };

            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            case TOTAL_RESPONSE_TIME:
            case TIME_FROM_CREATION_TO_FIRST_REPLY:
            case TIME_FROM_CREATION_TO_CLOSE:
                return new ProcessorCustom() {
                    private Class validationClass = null;

                    List<Expression> getValidFilterExpressions() {
                        return getAsList(BETWEEN, GT, LT);
                    }

                    Fragment getFilterUiFragment(MarkupContainer container, User user, Space space,
                            CalipsoService calipsoService) {
                        Fragment fragment = new Fragment("fragParent", "effortField", container);
                        WebMarkupContainer days = new WebMarkupContainer("days");

                        if (name.equals(TOTAL_RESPONSE_TIME)) {
                            validationClass = Double.class;
                        } else {
                            validationClass = Long.class;
                        }

                        TextField textField = new TextField("value", validationClass);
                        days.add(textField);
                        // textField.setModel(new PropertyModel(this,
                        // "filterCriteria.value"));
                        textField.setModel(new PropertyModel(filterCriteria, "value"));
                        fragment.add(days);

                        WebMarkupContainer days2 = new WebMarkupContainer("days2");
                        if (filterCriteria.getExpression() == BETWEEN) {
                            TextField textField2 = new TextField("value2", validationClass);
                            days2.add(textField2);
                            // textField2.setModel(new PropertyModel(this,
                            // "filterCriteria.value2"));
                            textField2.setModel(new PropertyModel(filterCriteria, "value2"));
                        } // if
                        else {
                            fragment.add(new WebMarkupContainer("value2").setVisible(false));
                            days2.setVisible(false);
                        } // else
                        fragment.add(days2);
                        // fragment.setVisible(isVisible());
                        return fragment;
                    }

                    void addRestrictions(DetachedCriteria criteria) {
                    }

                    void addRestrictions(CustomCriteria customCriteria) {
                        if (filterHasValue()) {
                            String criteriaObjectClass = null;
                            if (validationClass != null) {
                                criteriaObjectClass = validationClass.getCanonicalName();
                            } // if

                            Object value = filterCriteria.getValue();
                            Object value2 = filterCriteria.getValue2();

                            Double v1 = new Double(value.toString());
                            value = v1 * 86400;// In Seconds
                            switch (filterCriteria.getExpression()) {
                            case GT:
                                customCriteria.add(name.getText(), CustomCriteria.GT, value.toString(),
                                        criteriaObjectClass);
                                break;
                            case LT:
                                customCriteria.add(name.getText(), CustomCriteria.LT, value.toString(),
                                        criteriaObjectClass);
                                break;
                            case BETWEEN:
                                Double v2 = new Double(value2.toString());
                                value2 = v2 * 86400; // In Seconds
                                customCriteria.add(name.getText(), CustomCriteria.GET, value.toString(),
                                        criteriaObjectClass);
                                customCriteria.add(name.getText(), CustomCriteria.LET, value2.toString(),
                                        criteriaObjectClass);
                                break;
                            default:
                            }
                        }
                    }

                    String getAsQueryString() {
                        return getQueryStringFromValue(Long.class);
                    }

                    void loadFromQueryString(String s, User user, CalipsoService calipsoService) {
                        setValueFromQueryString(s, Long.class);
                    }
                };

            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            case PLANNED_EFFORT:
                return new Processor() {
                    List<Expression> getValidFilterExpressions() {
                        return getAsList(EQ, NOT_EQ, GT, LT, BETWEEN);
                    }

                    Fragment getFilterUiFragment(MarkupContainer container, User user, Space space,
                            CalipsoService calipsoService) {
                        Fragment fragment = new Fragment("fragParent", "effortField2", container);
                        EffortField effortField = new EffortField("value",
                                new PropertyModel(filterCriteria, "value"), false);
                        fragment.add(effortField);
                        if (filterCriteria.getExpression() == BETWEEN) {
                            EffortField effortField2 = new EffortField("value2",
                                    new PropertyModel(filterCriteria, "value2"), false);
                            fragment.add(new WebMarkupContainer("and"));
                            fragment.add(effortField2);
                        } else {
                            fragment.add(new WebMarkupContainer("and").setVisible(false));
                            fragment.add(new WebMarkupContainer("value2").setVisible(false));
                        }
                        return fragment;
                    }

                    void addRestrictions(DetachedCriteria criteria) {
                        if (filterHasValue()) {
                            Object value = filterCriteria.getValue();
                            switch (filterCriteria.getExpression()) {
                            case EQ:
                                criteria.add(Restrictions.eq(getNameText(), value));
                                break;
                            case NOT_EQ:
                                criteria.add(Restrictions.not(Restrictions.eq(getNameText(), value)));
                                break;
                            case GT:
                                criteria.add(Restrictions.gt(getNameText(), value));
                                break;
                            case LT:
                                criteria.add(Restrictions.lt(getNameText(), value));
                                break;
                            case BETWEEN:
                                criteria.add(Restrictions.gt(getNameText(), value));
                                criteria.add(Restrictions.lt(getNameText(), filterCriteria.getValue2()));
                                break;
                            default:
                            }
                        }
                    }

                    String getAsQueryString() {
                        return getQueryStringFromValue(Integer.class);
                    }

                    void loadFromQueryString(String s, User user, CalipsoService calipsoService) {
                        setValueFromQueryString(s, Integer.class);
                    }
                };

            // ==============================================================
            default:
                throw new RuntimeException("Unknown Column Heading " + name);
            }
        }
    }

    private List<Expression> getAsList(Expression... expressions) {
        List<Expression> list = new ArrayList<Expression>();
        for (Expression e : expressions) {
            list.add(e);
        }
        return list;
    }

    private Fragment getTextFieldFragment(MarkupContainer container) {
        Fragment fragment = new Fragment("fragParent", "textField", container);
        TextField textField = new TextField("value", String.class);
        textField.setModel(new PropertyModel(filterCriteria, "value"));
        fragment.add(textField);
        fragment.add(new WebMarkupContainer("value2").setVisible(false));
        return fragment;
    }

    private boolean filterHasValueList() {
        if (filterCriteria.getExpression() != null && filterCriteria.getValues() != null
                && filterCriteria.getValues().size() > 0) {
            return true;
        }
        return false;
    }

    private boolean filterHasValue() {
        Object value = filterCriteria.getValue();
        if (filterCriteria.getExpression() != null && value != null && value.toString().trim().length() > 0) {
            return true;
        }
        return false;
    }

    private boolean filterIsNullExpression() {
        return (filterCriteria.getExpression() != null)
                && (filterCriteria.getExpression().equals(FilterCriteria.Expression.IS_NULL));
    }

    private String prependExpression(String s) {
        if (s.equals("")) {
            return filterCriteria.getExpression().getKey();
        } else {
            return filterCriteria.getExpression().getKey() + "_" + s;
        }
    }

    private String getQueryStringFromValueList() {
        if (!filterHasValueList()) {
            return null;
        }
        String temp = "";
        for (Object o : filterCriteria.getValues()) {
            if (temp.length() > 0) {
                temp = temp + "_";
            }
            if (o instanceof CustomAttributeLookupValue) {
                temp = temp + ((CustomAttributeLookupValue) o).getId();
            } else {
                temp = temp + o;
            }

        }
        return prependExpression(temp);
    }

    private String getQueryStringFromValue(Class clazz) {
        if (!filterHasValue()) {
            return null;
        }
        String temp = "";
        if (clazz.equals(Date.class)) {
            temp = DateUtils.format((Date) filterCriteria.getValue());
            if (filterCriteria.getValue2() != null) {
                temp = temp + "_" + DateUtils.format((Date) filterCriteria.getValue2());
            }
        } else {
            temp = filterCriteria.getValue() + "";
            if (filterCriteria.getValue2() != null) {
                temp = temp + "_" + filterCriteria.getValue2();
            }
        }
        return prependExpression(temp);
    }

    // TODO refactor code duplication
    private String getQueryStringFromUserList() {
        boolean hasValueList = filterHasValueList();
        Expression expression = filterCriteria.getExpression();

        if (!hasValueList && expression == null) {
            return null;
        }
        String temp = "";
        if (hasValueList) {
            for (User u : (List<User>) filterCriteria.getValues()) {
                if (temp.length() > 0) {
                    temp = temp + "_";
                }
                temp = temp + u.getId();
            }
        }
        return prependExpression(temp);
    }

    // TODO refactor code duplication
    private String getQueryStringFromSpaceList() {
        if (!filterHasValueList()) {
            return null;
        }
        String temp = "";
        for (Space s : (List<Space>) filterCriteria.getValues()) {
            if (temp.length() > 0) {
                temp = temp + "_";
            }
            temp = temp + s.getId();
        }
        return prependExpression(temp);
    }

    // TODO refactor code duplication
    private String getQueryStringFromAssetTypeList() {
        if (!filterHasValueList()) {
            return null;
        }
        String temp = "";
        for (AssetType a : (List<AssetType>) filterCriteria.getValues()) {
            if (temp.length() > 0) {
                temp = temp + "_";
            }
            temp = temp + a.getId();
        }
        return prependExpression(temp);
    }

    private List<String> setExpressionAndGetRemainingTokens(String s) {
        String[] tokens = s.split("_");
        filterCriteria.setExpression(FilterCriteria.convertToExpression(tokens[0]));
        List<String> remainingTokens = new ArrayList<String>();
        // ignore first token, this has been parsed as Expression above
        for (int i = 1; i < tokens.length; i++) {
            remainingTokens.add(tokens[i]);
        }
        return remainingTokens;
    }

    private void setValueListFromQueryString(String raw) {
        filterCriteria.setValues(setExpressionAndGetRemainingTokens(raw));
    }

    // TODO refactor with more methods in filtercriteria
    private void setValueFromQueryString(String raw, Class clazz) {
        List<String> tokens = setExpressionAndGetRemainingTokens(raw);
        String v1 = tokens.get(0);
        String v2 = tokens.size() > 1 ? tokens.get(1) : null;
        if (clazz.equals(Double.class)) {
            filterCriteria.setValue(new Double(v1));
            if (v2 != null) {
                filterCriteria.setValue2(new Double(v2));
            }
        } else if (clazz.equals(Long.class)) {
            filterCriteria.setValue(new Long(v1));
            if (v2 != null) {
                filterCriteria.setValue2(new Long(v2));
            }
        } else if (clazz.equals(Integer.class)) {
            filterCriteria.setValue(new Integer(v1));
            if (v2 != null) {
                filterCriteria.setValue2(new Integer(v2));
            }
        } else if (clazz.equals(Date.class)) {
            filterCriteria.setValue(DateUtils.convert(v1));
            if (v2 != null) {
                filterCriteria.setValue2(DateUtils.convert(v2));
            }
        } else { // String
            filterCriteria.setValue(v1);
            if (v2 != null) {
                filterCriteria.setValue2(v2);
            }
        }

    }

    private void setUserListFromQueryString(String raw, CalipsoService calipsoService) {
        List<String> tokens = setExpressionAndGetRemainingTokens(raw);
        if (tokens.size() != 0) {
            List<User> users = calipsoService.findUsersWhereIdIn(getAsListOfLong(tokens));
            filterCriteria.setValues(users);
        }
    }

    private void setSpaceListFromQueryString(String raw, User user, CalipsoService calipsoService) {
        List<String> tokens = setExpressionAndGetRemainingTokens(raw);
        List<Space> temp = calipsoService.findSpacesWhereIdIn(getAsListOfLong(tokens));
        // for security, prevent URL spoofing to show spaces not allocated to
        // user
        List<Space> spaces = new ArrayList<Space>();
        for (Space s : temp) {
            if (user.isAllocatedToSpace(s.getId())) {
                spaces.add(s);
            }
        }
        filterCriteria.setValues(spaces);
    }

    private void setAssetTypeListFromQueryString(String raw, User user, CalipsoService calipsoService) {
        List<String> tokens = setExpressionAndGetRemainingTokens(raw);

        // AssetTypeSearch assetTypeSearch = new AssetTypeSearch()
        List<AssetType> temp = calipsoService.findAssetTypesWhereIdIn(getAsListOfLong(tokens));
        // calipsoService.findSpacesWhereIdIn(getAsListOfLong(tokens));
        // for security, prevent URL spoofing to show spaces not allocated to
        // user
        List<AssetType> assetTypes = new ArrayList<AssetType>();
        for (AssetType a : temp) {
            if (user.isAllocatedToSpace(a.getId())) {
                assetTypes.add(a);
            }
        }
        filterCriteria.setValues(assetTypes);
    }

    private void setStatusListFromQueryString(String raw) {
        List<String> tokens = setExpressionAndGetRemainingTokens(raw);
        List<Integer> statuses = new ArrayList<Integer>();
        for (String s : tokens) {
            statuses.add(new Integer(s));
        }
        filterCriteria.setValues(statuses);
    }

    private List<Long> getAsListOfLong(List<String> tokens) {
        List<Long> ids = new ArrayList<Long>();
        for (String s : tokens) {
            ids.add(new Long(s));
        }
        return ids;
    }

    /* custom accessor */
    public void setName(String nameAsString) {
        name = convertToName(nameAsString);
    }

    public String getNameText() {
        if (isField()) {
            return field.getName().getText();
        }
        return name.text;
    }

    // ==========================================================================

    public Name getName() {
        return name;
    }

    public Field getField() {
        return field;
    }

    public String getLabel() {
        return label;
    }

    public FilterCriteria getFilterCriteria() {
        return filterCriteria;
    }

    public void setFilterCriteria(FilterCriteria filterCriteria) {
        this.filterCriteria = filterCriteria;
    }

    public boolean isVisible() {
        return visible;
    }

    public ColumnHeading setVisible(boolean visible) {
        this.visible = visible;
        return this;
    }

    public boolean isDbField() {
        return isDbField;
    }

    public void setDbField(boolean isDbField) {
        this.isDbField = isDbField;
    }

    public boolean isVisibleCriterium() {
        return visibleCriterium;
    }

    public void setVisibleCriterium(boolean visibleCriterium) {
        this.visibleCriterium = visibleCriterium;
    }

    @Override
    public int hashCode() {
        return name.hashCode();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof ColumnHeading)) {
            return false;
        }
        final ColumnHeading ch = (ColumnHeading) o;
        return ch.getName().equals(name);
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("name [").append(name);
        sb.append("]; filterCriteria [").append(filterCriteria);
        sb.append("]");
        return sb.toString();
    }
}