/*
 * RHQ Management Platform
 * Copyright (C) 2005-2008 Red Hat, Inc.
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation version 2 of the License.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
package org.rhq.enterprise.gui.legacy.action.resource.common.monitor.alerts.config;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.validator.GenericValidator;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;

import org.rhq.core.domain.alert.AlertCondition;
import org.rhq.core.domain.alert.AlertDampening;
import org.rhq.core.domain.alert.AlertDefinition;
import org.rhq.core.domain.alert.AlertPriority;
import org.rhq.core.domain.alert.BooleanExpression;
import org.rhq.core.domain.auth.Subject;
import org.rhq.core.domain.event.EventSeverity;
import org.rhq.core.domain.measurement.AvailabilityType;
import org.rhq.core.domain.measurement.MeasurementDefinition;
import org.rhq.core.domain.operation.OperationRequestStatus;
import org.rhq.core.domain.util.PageControl;
import org.rhq.enterprise.gui.legacy.Constants;
import org.rhq.enterprise.gui.legacy.action.resource.ResourceForm;
import org.rhq.enterprise.gui.legacy.beans.OptionItem;
import org.rhq.enterprise.gui.legacy.util.RequestUtils;
import org.rhq.enterprise.server.alert.AlertDefinitionManagerLocal;
import org.rhq.enterprise.server.alert.AlertTemplateManagerLocal;
import org.rhq.enterprise.server.alert.GroupAlertDefinitionManagerLocal;
import org.rhq.enterprise.server.util.LookupUtil;

/**
 * Form for editing / creating new alert definitions.
 */
public final class DefinitionForm extends ResourceForm {
    private Log log = LogFactory.getLog(DefinitionForm.class);

    // alert definition properties
    private Integer ad; // nullable
    private String name;
    private String description;
    private int priority;
    private boolean active;
    private int recoverId;
    private String conditionExpression;

    // conditions
    private List<ConditionBean> conditions;

    // default metric to select, if available
    private int metricId;
    private String metricName;

    // default metric to select, if available
    private int callTimeMetricId;
    private String callTimeMetricName;

    // dampening rules (1 = every time)
    // 2) Each time condition set is true
    private String consecutiveCountValue;

    // 3) If condition set is true X times out of the last Y times it is evaluated
    private String partialCountValue;
    private String partialCountPeriod;

    // 4) If condition set is true, but ignoring it the next X times
    private String inverseCountValue;

    // 5) Once every X times conditions are exceeded within a time period of Y <time>
    private String durationCountValue;
    private String durationCountPeriod;
    private int durationCountPeriodUnits;

    // enable action recovery & filters
    private int whenEnabled; // alertDef.id of "Recovery Alert for <alertDef.name>"
    private boolean disableForRecovery; // whenEnable isn't valid if this is checked
    private boolean filteringControlActions;
    private boolean filteringNotificationActions;

    // for drop-downs
    private Collection baselines;
    private List<MeasurementDefinition> metrics;
    private List<MeasurementDefinition> traits;
    private List<MeasurementDefinition> calltimeMetrics;
    private Collection<Map.Entry<String, Integer>> alertnames;
    private Collection<Map.Entry<String, String>> conditionExpressionNames;
    private boolean resourceConfigurationSupported;

    //    private boolean cascade;
    private boolean readOnly;

    private static String[] controlActionStatuses = { OperationRequestStatus.INPROGRESS.name(),
        OperationRequestStatus.SUCCESS.name(), OperationRequestStatus.FAILURE.name(),
        OperationRequestStatus.CANCELED.name() };

    private static String[] eventSeverities = { EventSeverity.DEBUG.name(), EventSeverity.INFO.name(),
        EventSeverity.WARN.name(), EventSeverity.ERROR.name(), EventSeverity.FATAL.name() };

    private static OptionItem[] availabilityOptions;

    static {
        AvailabilityType[] values = AvailabilityType.values();

        availabilityOptions = new OptionItem[values.length];
        for (int i = 0; i < availabilityOptions.length; i++) {
            availabilityOptions[i] = new OptionItem("Goes " + values[i].name(), values[i].name());
        }
    }

    private static int[] priorities = new int[] { AlertPriority.HIGH.ordinal(), AlertPriority.MEDIUM.ordinal(),
        AlertPriority.LOW.ordinal() };

    private static int[] timeUnits = new int[] { Constants.ALERT_ACTION_ENABLE_UNITS_MINUTES,
        Constants.ALERT_ACTION_ENABLE_UNITS_HOURS, Constants.ALERT_ACTION_ENABLE_UNITS_DAYS,
        Constants.ALERT_ACTION_ENABLE_UNITS_WEEKS };

    private static String[] comparators = new String[] { Constants.ALERT_THRESHOLD_COMPARATOR_GT,
        Constants.ALERT_THRESHOLD_COMPARATOR_EQ, Constants.ALERT_THRESHOLD_COMPARATOR_LT };

    private static String[] calltimeOptions = new String[] { Constants.CALLTIME_MAX, Constants.CALLTIME_MIN,
        Constants.CALLTIME_AVG };

    private static String[] calltimeOperators = new String[] { Constants.CALLTIME_SHRINKS, Constants.CALLTIME_CHANGES,
        Constants.CALLTIME_GROWS };

    // special form handlers
    private boolean addingCondition;
    private int deletedCondition;

    public DefinitionForm() {
        // do nothing
    }

    public Integer getAd() {
        return ad;
    }

    public void setAd(Integer ad) {
        this.ad = ad;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String getDescription() {
        return description;
    }

    @Override
    public void setDescription(String description) {
        this.description = description;
    }

    public int getPriority() {
        return priority;
    }

    public void setPriority(int priority) {
        this.priority = priority;
    }

    public boolean isActive() {
        return active;
    }

    public void setActive(boolean active) {
        this.active = active;
    }

    /**
     * @return Returns the recoverId.
     */
    public int getRecoverId() {
        return recoverId;
    }

    /**
     * @param recoverId The recoverId to set.
     */
    public void setRecoverId(int recoverId) {
        this.recoverId = recoverId;
    }

    /*----------------------------------------------------------------
      This method is needed for some fancy Javascript processing.  Do
      not remove.
      ----------------------------------------------------------------*/
    public ConditionBean[] getConditions() {
        ConditionBean[] conds = new ConditionBean[conditions.size()];
        return conditions.toArray(conds);
    }

    public ConditionBean getCondition(int index) {
        if (index >= conditions.size()) {
            setNumConditions(index + 1);
        }

        return conditions.get(index);
    }

    public int getMetricId() {
        return metricId;
    }

    public void setMetricId(int metricId) {
        this.metricId = metricId;
    }

    public String getMetricName() {
        return metricName;
    }

    public void setMetricName(String metricName) {
        this.metricName = metricName;

        // Select default metric
        this.getCondition(0).setMetricName(metricName);
    }

    public int getCallTimeMetricId() {
        return callTimeMetricId;
    }

    public void setCallTimeMetricId(int callTimeMetricId) {
        this.callTimeMetricId = callTimeMetricId;
    }

    public String getCallTimeMetricName() {
        return callTimeMetricName;
    }

    public void setCallTimeMetricName(String callTimeMetricName) {
        this.callTimeMetricName = callTimeMetricName;

        // Select default metric
        this.getCondition(0).setCallTimeMetricName(callTimeMetricName);
    }

    /*
     * NEVER INVOKED public void setCondition(int index, ConditionBean condition) { log.trace("setCondition(" + index +
     * ", " + condition + ")"); if (conditions.size() > index) { conditions.set(index, condition); } else {
     * conditions.add(condition); } }
     */

    public int getNumConditions() {
        return conditions.size();
    }

    public void setNumConditions(int numConditions) {
        while (conditions.size() < numConditions) {
            conditions.add(new ConditionBean());
        }
        while (conditions.size() > numConditions) {
            conditions.remove(conditions.size() - 1);
        }
    }

    /**
     * Get when to enable the actions.
     */
    public int getWhenEnabled() {
        return whenEnabled;
    }

    public void setWhenEnabled(int whenEnabled) {
        this.whenEnabled = whenEnabled;
    }

    public String getPartialCountValue() {
        return partialCountValue;
    }

    public void setPartialCountValue(String partialCountValue) {
        this.partialCountValue = partialCountValue;
    }

    public String getPartialCountPeriod() {
        return partialCountPeriod;
    }

    public void setPartialCountPeriod(String partialCountPeriod) {
        this.partialCountPeriod = partialCountPeriod;
    }

    public String getDurationCountValue() {
        return durationCountValue;
    }

    public void setDurationCountValue(String durationCountValue) {
        this.durationCountValue = durationCountValue;
    }

    public String getDurationCountPeriod() {
        return durationCountPeriod;
    }

    public void setDurationCountPeriod(String durationCountPeriod) {
        this.durationCountPeriod = durationCountPeriod;
    }

    public int getDurationCountPeriodUnits() {
        return durationCountPeriodUnits;
    }

    public void setDurationCountPeriodUnits(int durationCountPeriodUnits) {
        this.durationCountPeriodUnits = durationCountPeriodUnits;
    }

    /**
     * @return Returns the disableForRecovery.
     */
    public boolean isDisableForRecovery() {
        return disableForRecovery;
    }

    /**
     * @param disableForRecovery The disableForRecovery to set.
     */
    public void setDisableForRecovery(boolean disableForRecovery) {
        this.disableForRecovery = disableForRecovery;
    }

    public boolean isFilteringControlActions() {
        return filteringControlActions;
    }

    public void setFilteringControlActions(boolean filteringControlActions) {
        this.filteringControlActions = filteringControlActions;
    }

    public boolean isFilteringNotificationActions() {
        return filteringNotificationActions;
    }

    public void setFilteringNotificationActions(boolean filteringNotificationActions) {
        this.filteringNotificationActions = filteringNotificationActions;
    }

    public boolean isAddingCondition() {
        return addingCondition;
    }

    public void setAddingCondition(boolean addingCondition) {
        log.trace("setAddingCondition(" + addingCondition + ")");
        this.addingCondition = addingCondition;
    }

    public int getDeletedCondition() {
        return deletedCondition;
    }

    public void setDeletedCondition(int deletedCondition) {
        log.trace("setDeletedCondition(" + deletedCondition + ")");
        this.deletedCondition = deletedCondition;
    }

    public void deleteCondition(int deletedCondition) {
        if (deletedCondition < conditions.size()) {
            conditions.remove(deletedCondition);
        }
    }

    public Collection getBaselines() {
        return baselines;
    }

    public void setBaselines(Collection baselines) {
        this.baselines = baselines;
    }

    public List<MeasurementDefinition> getMetrics() {
        return metrics;
    }

    public void setMetrics(List<MeasurementDefinition> metrics) {
        this.metrics = metrics;
    }

    public List<MeasurementDefinition> getTraits() {
        return traits;
    }

    public void setTraits(List<MeasurementDefinition> traits) {
        this.traits = traits;
    }

    /**
     * @return Returns the alertnames.
     */
    public Collection<Map.Entry<String, Integer>> getAlertnames() {
        return alertnames;
    }

    /**
     * @param alertnames The alertnames to set.
     */
    public void setAlertnames(Collection<Map.Entry<String, Integer>> alertnames) {
        this.alertnames = alertnames;
    }

    public String[] getControlActionStatuses() {
        return controlActionStatuses;
    }

    public String[] getEventSeverities() {
        return eventSeverities;
    }

    public OptionItem[] getAvailabilityOptions() {
        return availabilityOptions;
    }

    public int[] getPriorities() {
        return priorities;
    }

    public int[] getTimeUnits() {
        return timeUnits;
    }

    public String[] getComparators() {
        return comparators;
    }

    @Override
    @SuppressWarnings("deprecation")
    public void reset(ActionMapping mapping, HttpServletRequest request) {
        super.reset(mapping, request);
        setDefaults();

        try {
            Subject subject = RequestUtils.getSubject(request);

            List<AlertDefinition> alertDefinitions = null;

            // if there's a "type" param, then its an alert template (can't use isAlertTemplate because the
            // definitionForm was just cleared on reset()
            if (request.getParameter("id") != null && !request.getParameter("id").equals("")) {
                AlertDefinitionManagerLocal alertDefinitionManager = LookupUtil.getAlertDefinitionManager();
                Integer resourceId = RequestUtils.getResourceId(request);

                alertDefinitions = alertDefinitionManager.findAlertDefinitions(subject, resourceId, PageControl
                    .getUnlimitedInstance());
            } else if (request.getParameter("type") != null && !request.getParameter("type").equals("")) {
                AlertTemplateManagerLocal alertTemplateManager = LookupUtil.getAlertTemplateManager();
                Integer resourceTypeId = RequestUtils.getResourceTypeId(request);

                alertDefinitions = alertTemplateManager.getAlertTemplates(subject, resourceTypeId, PageControl
                    .getUnlimitedInstance());
            } else {
                GroupAlertDefinitionManagerLocal groupAlertDefinitionManager = LookupUtil
                    .getGroupAlertDefinitionManager();
                Integer groupId = RequestUtils.getGroupId(request);

                alertDefinitions = groupAlertDefinitionManager.findGroupAlertDefinitions(subject, groupId, PageControl
                    .getUnlimitedInstance());
            }

            Map<String, Integer> alertDefinitionNameToIdMap = new HashMap<String, Integer>(alertDefinitions.size());
            for (AlertDefinition alertDefinition : alertDefinitions) {
                if (alertDefinition.getRecoveryId() != 0) {
                    continue; // already a recovery definition for something else
                }
                alertDefinitionNameToIdMap.put(alertDefinition.getName(), alertDefinition.getId());
            }

            setAlertnames(alertDefinitionNameToIdMap.entrySet());
        } catch (Exception e) {
            setAlertnames(new ArrayList<Map.Entry<String, Integer>>(0));
        }

        Map<String, String> expressionsMap = new HashMap<String, String>();
        expressionsMap.put(BooleanExpression.ALL.toString(), BooleanExpression.ALL.name());
        expressionsMap.put(BooleanExpression.ANY.toString(), BooleanExpression.ANY.name());
        setConditionExpressionNames(expressionsMap.entrySet());
    }

    /**
     * Import basic properties from The AlertDefinitionValue to this form.
     *
     * @param alertDef
     */
    public void importProperties(AlertDefinition alertDef) {
        this.setAd(alertDef.getId());
        this.setName(alertDef.getName());
        this.setDescription(alertDef.getDescription());
        this.setActive(alertDef.getEnabled());
        this.setPriority(alertDef.getPriority().ordinal());
        this.setReadOnly(alertDef.isReadOnly());

        // no point is getting this here, because it's edited on the conditions tiles
        //this.setConditionExpression( alertDef.getConditionExpression().name() );
    }

    /**
     * Export basic properties from this form to the AlertDefinitionValue.
     *
     * @param alertDef
     */
    public void exportProperties(AlertDefinition alertDef) {
        //alertDef.setId( this.getId() );
        alertDef.setName(this.getName());
        alertDef.setDescription(this.getDescription());
        alertDef.setEnabled(this.isActive());
        alertDef.setPriority(AlertPriority.values()[this.getPriority()]);
        alertDef.setReadOnly(this.isReadOnly());

        // no point is setting this here, because it's edited on the conditions tiles
        //alertDef.setConditionExpression( BooleanExpression.valueOf( this.getConditionExpression() ) );
    }

    /**
     * Import the conditions and enablement properties from the AlertDefinitionValue to this form.
     */
    public void importConditionsEnablement(AlertDefinition alertDef, Subject subject) throws Exception {
        // we import the id here, too, so that the update will work
        this.setAd(alertDef.getId());

        this.setConditionExpression(alertDef.getConditionExpression().name());

        /*
         * conditions
         */
        Set<AlertCondition> conds = alertDef.getConditions();
        setNumConditions(conds.size());
        int i = 0;
        for (AlertCondition cond : conds) {
            ConditionBean condBean = conditions.get(i++);
            condBean.importProperties(cond, subject);
        }

        /*
         * recovery
         */
        recoverId = alertDef.getRecoveryId();
        disableForRecovery = alertDef.getWillRecover();
        filteringControlActions = alertDef.getControlFiltered();
        filteringNotificationActions = alertDef.getNotifyFiltered();

        /*
         * dampening
         */
        AlertDampening alertDampening = alertDef.getAlertDampening();
        AlertDampening.Category category = alertDampening.getCategory();

        if (AlertDampening.Category.CONSECUTIVE_COUNT == category) {
            consecutiveCountValue = String.valueOf(alertDampening.getValue());
        } else if (AlertDampening.Category.PARTIAL_COUNT == category) {
            partialCountPeriod = String.valueOf(alertDampening.getPeriod());
            partialCountValue = String.valueOf(alertDampening.getValue());
        } else if (AlertDampening.Category.INVERSE_COUNT == category) {
            inverseCountValue = String.valueOf(alertDampening.getValue());
        } else if (AlertDampening.Category.DURATION_COUNT == category) {
            durationCountValue = String.valueOf(alertDampening.getValue());
            durationCountPeriod = String.valueOf(alertDampening.getPeriod());
            durationCountPeriodUnits = alertDampening.getPeriodUnits().ordinal() + 1;
        }

        whenEnabled = alertDampening.getCategory().ordinal();
    }

    /**
     * Export the conditions and enablement properties from this form to the specified alert def.
     */
    public void exportConditionsEnablement(AlertDefinition alertDef, HttpServletRequest request, Subject subject)
        throws Exception {
        alertDef.setConditionExpression(BooleanExpression.valueOf(this.getConditionExpression()));

        /*
         * conditions
         */
        log.debug("Exporting " + this.getNumConditions() + " conditions...");
        alertDef.removeAllConditions();
        for (int i = 0; i < this.getNumConditions(); ++i) {
            ConditionBean condBean = this.getCondition(i);
            AlertCondition newCondition = condBean.exportProperties(request, subject);
            alertDef.addCondition(newCondition);
        }

        /*
         * recovery
         */
        alertDef.setRecoveryId(this.getRecoverId());
        alertDef.setWillRecover(this.isDisableForRecovery());
        alertDef.setNotifyFiltered(this.isFilteringNotificationActions());
        alertDef.setControlFiltered(this.isFilteringControlActions());

        /*
         * dampening
         */
        AlertDampening alertDampening = new AlertDampening(AlertDampening.Category.values()[this.getWhenEnabled()]);
        alertDef.setAlertDampening(alertDampening);

        AlertDampening.Category category = alertDampening.getCategory();
        if (category == AlertDampening.Category.CONSECUTIVE_COUNT) {
            alertDampening.setValue(Integer.valueOf(this.getConsecutiveCountValue()));
        } else if (category == AlertDampening.Category.PARTIAL_COUNT) {
            alertDampening.setValue(Integer.valueOf(this.getPartialCountValue()));
            alertDampening.setPeriod(Integer.valueOf(this.getPartialCountPeriod()));
        } else if (category == AlertDampening.Category.INVERSE_COUNT) {
            alertDampening.setValue(Integer.valueOf(this.getInverseCountValue()));
        } else if (alertDampening.getCategory() == AlertDampening.Category.DURATION_COUNT) {
            alertDampening.setValue(Integer.valueOf(this.getDurationCountValue()));
            alertDampening.setPeriod(Integer.valueOf(this.getDurationCountPeriod()));

            alertDampening.setPeriodUnits(AlertDampening.TimeUnits.values()[this.getDurationCountPeriodUnits() - 1]);
        }
    }

    public void resetConditions() {
        conditions = new ArrayList<ConditionBean>();
        setNumConditions(1);
    }

    @Override
    public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
        // don't validate if we are preparing the form ...
        if (!shouldValidate(mapping, request)) {
            return null;
        }

        ActionErrors errs = super.validate(mapping, request);
        if (null == errs) {
            errs = new ActionErrors();
        }

        // only do this advanced validation if we are editing
        // conditions or creating a new definition
        if (mapping.getName().equals("NewAlertDefinitionForm")
            || mapping.getName().equals("EditAlertDefinitionConditionsForm")) {
            for (int i = 0; i < getNumConditions(); ++i) {
                ConditionBean cond = getCondition(i);
                cond.validate(request, errs, i);
            }

            AlertDampening.Category selectedCategory = AlertDampening.Category.values()[getWhenEnabled()];
            if (selectedCategory == AlertDampening.Category.CONSECUTIVE_COUNT) {
                validatePositive(getConsecutiveCountValue(), "consecutiveCountValue", errs);
            } else if (selectedCategory == AlertDampening.Category.PARTIAL_COUNT) {
                // using a boolean expression will shortcut the checking to the first failure
                if (validatePositive(getPartialCountValue(), "partialCountValue", errs)
                    && validatePositive(getPartialCountPeriod(), "partialCountPeriod", errs)
                    && (Integer.parseInt(getPartialCountValue()) > Integer.parseInt(getPartialCountPeriod()))) {
                    errs.add("partialCountPeriod", new ActionMessage("alert.config.error.PartialCountRangeTooSmall"));
                }
            } else if (selectedCategory == AlertDampening.Category.INVERSE_COUNT) {
                validatePositive(getInverseCountValue(), "inverseCountValue", errs);
            } else if (selectedCategory == AlertDampening.Category.DURATION_COUNT) {
                // using a boolean expression will shortcut the checking to the first failure
                boolean valid = validatePositive(getDurationCountValue(), "durationCountValue", errs)
                    && validatePositive(getDurationCountPeriod(), "durationCountPeriod", errs);
            }
        }

        return errs;
    }

    private boolean validatePositive(String field, String fieldName, ActionErrors errs) {
        if (GenericValidator.isBlankOrNull(field)) {
            errs.add(fieldName, new ActionMessage("alert.config.error.DampeningFieldRequired"));
            return false;
        }

        if ((GenericValidator.isInt(field) == false) || (Integer.parseInt(field) < 1)) {
            errs.add(fieldName, new ActionMessage("alert.config.error.InvalidDampeningField"));
            return false;
        }

        return true;
    }

    private void setDefaults() {
        ad = null;
        name = null;
        description = null;
        priority = AlertPriority.MEDIUM.ordinal();
        active = true;
        resetConditions();
        conditionExpression = BooleanExpression.ALL.name();
        whenEnabled = AlertDampening.Category.NONE.ordinal();
        consecutiveCountValue = null;
        partialCountValue = null;
        partialCountPeriod = null;
        inverseCountValue = null;
        durationCountValue = null;
        durationCountPeriod = null;
        durationCountPeriodUnits = AlertDampening.TimeUnits.MINUTES.ordinal() + 1;
        filteringControlActions = false;
        filteringNotificationActions = false;
        addingCondition = false;
        deletedCondition = Constants.ALERT_CONDITION_NONE_DELETED;
        baselines = null;
        //        cascade = false;
    }

    public void setAvailabilityActions(List<OptionItem> availabilityActions) {
        // TODO Auto-generated method stub
    }

    public String getConditionExpression() {
        return conditionExpression;
    }

    public void setConditionExpression(String conditionExpression) {
        this.conditionExpression = conditionExpression;
    }

    public Collection<Map.Entry<String, String>> getConditionExpressionNames() {
        return conditionExpressionNames;
    }

    public void setConditionExpressionNames(Collection<Map.Entry<String, String>> conditionExpressionNames) {
        this.conditionExpressionNames = conditionExpressionNames;
    }

    public boolean isResourceConfigurationSupported() {
        return resourceConfigurationSupported;
    }

    public void setResourceConfigurationSupported(boolean resourceConfigurationSupported) {
        this.resourceConfigurationSupported = resourceConfigurationSupported;
    }

    public String getConsecutiveCountValue() {
        return consecutiveCountValue;
    }

    public void setConsecutiveCountValue(String consecutiveTimes) {
        this.consecutiveCountValue = consecutiveTimes;
    }

    public String getInverseCountValue() {
        return inverseCountValue;
    }

    public void setInverseCountValue(String inverseCountValue) {
        this.inverseCountValue = inverseCountValue;
    }

    public boolean isReadOnly() {
        return readOnly;
    }

    public boolean getReadOnly() {
        return readOnly;
    }

    public void setReadOnly(boolean readOnly) {
        this.readOnly = readOnly;
    }

    public List<MeasurementDefinition> getCalltimeMetrics() {
        return calltimeMetrics;
    }

    public void setCalltimeMetrics(List<MeasurementDefinition> calltimeMetrics) {
        this.calltimeMetrics = calltimeMetrics;
    }

    public String[] getCalltimeOptions() {
        return calltimeOptions;
    }

    public void setCalltimeOptions(String[] calltimeOptions) {
        DefinitionForm.calltimeOptions = calltimeOptions;
    }

    public String[] getCalltimeOperators() {
        return calltimeOperators;
    }

    public void setCalltimeOperators(String[] calltimeOperators) {
        DefinitionForm.calltimeOperators = calltimeOperators;
    }
}