root/usr/src/cmd/pools/poold/com/sun/solaris/domain/pools/Statistic.java
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 *
 * ident        "%Z%%M% %I%     %E% SMI"
 */

package com.sun.solaris.domain.pools;

import java.math.BigInteger;
import java.util.Date;
import java.util.Iterator;
import java.text.*;

import com.sun.solaris.service.pools.UnsignedInt64;

/**
 * Contains the information relating to a specific statistic for an
 * object. The Statistic has no notion of the source of the data, it
 * is simply a repository for holding statistical information.
 */
interface Statistic
{
        /**
         * Return the start of the sample period for which the
         * statistic is representative.
         */
        public Date getStart();

        /**
         * Return the end of the sample period for which the
         * statistic is representative.
         */
        public Date getEnd();

        /**
         * Get the value of this statistic.
         */
        public Object getValue();

        /**
         * Get the value of this statistic as a Long.
         */
        public Long getLongValue();

        /**
         * Get the value of this statistic as a Double.
         */
        public Double getDoubleValue();

        /**
         * Get the value of this statistic as a UnsignedInt64.
         */
        public UnsignedInt64 getUnsignedInt64Value();
}

/**
 * An interface for Statistics which may be aggregated.
 */
interface AggregateStatistic extends Statistic
{
        /**
         * Add the supplied statistic to this.
         *
         * @param o The other statistic.
         */
        public AggregateStatistic add(AggregateStatistic o);

        /**
         * Subtract the supplied statistic from this.
         *
         * @param o The other statistic.
         */
        public AggregateStatistic subtract(AggregateStatistic o);

        /**
         * Produce the aggregate of all objects in the supplied
         * iterator (which must be of the same type) whose start and
         * end dates lie within the supplied ranges. If either start
         * or end is null, then that bound is not applied. i.e. if no
         * start date is supplied, then start checking is disabled.
         *
         * @param start The start date for qualification in the snapshot.
         * @param end The end date for qualification in the snapshot.
         * @throws IllegalArgumentException If the iterator is empty.
         */
        public AggregateStatistic getSnapshotForInterval(Iterator it,
            Date start, Date end) throws IllegalArgumentException;
}

/**
 * A basic Statistic implementation which makes it easy to derive
 * concrete statistic types. This is an immutable class, the state is
 * set when the object is constructed and cannot be later changed.
 */
abstract class AbstractStatistic implements Statistic
{
        /**
         * The value of the statistic.
         */
        private final Object value;

        /**
         * The start of the interval during which the statistic was
         * captured.
         */
        private final Date start;

        /**
         * The end of the interval during which the statistic was
         * captured.
         */
        private final Date end;

        /**
         * Formatter for the sample start time, used by toString().
         */
        private static final DateFormat df = new SimpleDateFormat("kk:mm:ss");

        /**
         * Constructor. This is provided as a mechanism to allow
         * inherited classes to correctly initialize their state.
         *
         * @param value The value of this statistic.
         */
        protected AbstractStatistic(Object value)
        {
                this(value, null, null);
        }

        /**
         * Constructor. This is provided as a mechanism to allow
         * inherited classes to correctly initialize their state.
         *
         * @param value The value of this statistic.
         * @param start The start of the sample period which this
         * statistic represents.
         * @param end The end of the sample period which this
         * statistic represents.
         */
        protected AbstractStatistic(Object value, Date start, Date end)
        {
                this.value = value;
                this.start = start;
                this.end = end;
        }

        /**
         * Return the start of the sample period for which the
         * statistic is representative.
         */
        public Date getStart()
        {
                return (start);
        }


        /**
         * Return the end of the sample period for which the
         * statistic is representative.
         */
        public Date getEnd()
        {
                return (end);
        }

        /**
         * Get the value of this statistic.
         */
        public Object getValue()
        {
                return (value);
        }

        public abstract Long getLongValue();
        public abstract Double getDoubleValue();
        public abstract UnsignedInt64 getUnsignedInt64Value();

        /**
         * Return the string representation of this statistic.
         */
        public String toString()
        {
                StringBuffer buf = new StringBuffer();

                buf.append(value);
                if (start != null && end != null) {
                        buf.append(" from ");
                        buf.append(df.format(start));
                        buf.append(" to ");
                        buf.append(df.format(end));
                }
                return (buf.toString());
        }
}

/**
 * A statistic of type Double.
 */
final class DoubleStatistic extends AbstractStatistic
    implements AggregateStatistic
{

        /**
         * Constructor.
         *
         * @param value The value of this statistic.
         */
        public DoubleStatistic(Double value)
        {
                super(value);
        }

        /**
         * Constructor.
         *
         * @param value The value of this statistic.
         * @param start The start of the interval over which this
         * statistic is representative.
         * @param end The end of the interval over which this
         * statistic is representative.
         */
        public DoubleStatistic(Double value, Date start, Date end)
        {
                super(value, start, end);
        }

        public Double getDoubleValue()
        {
                return ((Double) getValue());
        }

        public Long getLongValue()
        {
                return (Long.valueOf(((Double) getValue()).longValue()));
        }

        public UnsignedInt64 getUnsignedInt64Value()
        {
                return (new UnsignedInt64(Long.toString(((Double) getValue()).
                                              longValue())));
        }

        public AggregateStatistic add(AggregateStatistic o)
        {
                Double v1 = getDoubleValue();
                Double v2 = o.getDoubleValue();

                return (new DoubleStatistic(Double.valueOf(v1.doubleValue() +
                                            v2.doubleValue()),
                        getStart(), getEnd()));
        }

        public AggregateStatistic subtract(AggregateStatistic o)
        {
                Double v1 = getDoubleValue();
                Double v2 = o.getDoubleValue();

                return (new DoubleStatistic(Double.valueOf(v1.doubleValue() -
                                            v2.doubleValue()),
                        getStart(), getEnd()));
        }

        public AggregateStatistic getSnapshotForInterval(Iterator it,
            Date start, Date end) throws IllegalArgumentException
        {
                double total = 0;
                int count = 0;
                Date first = start, last = end;

                while (it.hasNext()) {
                        DoubleStatistic s = (DoubleStatistic) it.next();
                        if (start != null) {
                                if (s.getStart().compareTo(start) < 0)
                                        continue;
                        }
                        if (first == null)
                                first = s.getStart();
                        if (end != null) {
                                if (s.getEnd().compareTo(end) > 0)
                                        continue;
                        }
                        last = s.getEnd();
                        total += s.getDoubleValue().doubleValue();
                        count++;
                }
                if (count == 0)
                        throw new IllegalArgumentException("Cannot derive a " +
                            "snapshot from an empty iterator");
                return (new DoubleStatistic(Double.valueOf(total / count),
                        first, last));
        }
}

/**
 * A statistic of type Long.
 */
final class LongStatistic extends AbstractStatistic
    implements AggregateStatistic
{

        /**
         * Constructor.
         *
         * @param value The value of this statistic.
         * @param start The start of the interval over which this
         * statistic is representative.
         * @param end The end of the interval over which this
         * statistic is representative.
         */
        public LongStatistic(Long value, Date start, Date end)
        {
                super(value, start, end);
        }

        public Double getDoubleValue()
        {
                return (Double.valueOf(((Long) getValue()).longValue()));
        }

        public Long getLongValue()
        {
                return ((Long) getValue());
        }

        public UnsignedInt64 getUnsignedInt64Value()
        {
                return (new UnsignedInt64(Long.toString(((Long) getValue()).
                                              longValue())));
        }

        public AggregateStatistic add(AggregateStatistic o)
        {
                Long v1 = getLongValue();
                Long v2 = o.getLongValue();

                return (new LongStatistic(Long.valueOf(v1.longValue() +
                                            v2.longValue()),
                        getStart(), getEnd()));
        }

        public AggregateStatistic subtract(AggregateStatistic o)
        {
                Long v1 = getLongValue();
                Long v2 = o.getLongValue();

                return (new LongStatistic(Long.valueOf(v1.longValue() -
                                            v2.longValue()),
                        getStart(), getEnd()));
        }

        public AggregateStatistic getSnapshotForInterval(Iterator it,
            Date start, Date end) throws IllegalArgumentException
        {
                long total = 0;
                int count = 0;
                Date first = start, last = end;
                while (it.hasNext()) {
                        LongStatistic s = (LongStatistic) it.next();
                        if (start != null) {
                                if (s.getStart().compareTo(start) < 0)
                                        continue;
                        }
                        if (first == null)
                                first = s.getStart();
                        if (end != null) {
                                if (s.getEnd().compareTo(end) > 0)
                                        continue;
                        }
                        last = s.getEnd();
                        total += s.getLongValue().longValue();
                        count++;
                }
                if (count == 0)
                        throw new IllegalArgumentException("Cannot derive a " +
                            "snapshot from an empty iterator");
                return (new LongStatistic(Long.valueOf(total / count), first,
                        last));
        }
}

/**
 * A statistic of type UnsignedInt64.
 */
final class UnsignedInt64Statistic extends AbstractStatistic
    implements AggregateStatistic
{

        /**
         * Constructor.
         *
         * @param value The value of this statistic.
         * @param start The start of the interval over which this
         * statistic is representative.
         * @param end The end of the interval over which this
         * statistic is representative.
         */
        public UnsignedInt64Statistic(UnsignedInt64 value, Date start,
            Date end)
        {
                super(value, start, end);
        }

        public Double getDoubleValue()
        {
                return (Double.valueOf(
                    ((UnsignedInt64) getValue()).longValue()));
        }

        public Long getLongValue()
        {
                return (Long.valueOf(((UnsignedInt64) getValue()).longValue()));
        }

        public UnsignedInt64 getUnsignedInt64Value()
        {
                return ((UnsignedInt64) getValue());
        }

        public AggregateStatistic add(AggregateStatistic o)
        {
                UnsignedInt64 v1 = getUnsignedInt64Value();
                UnsignedInt64 v2 = o.getUnsignedInt64Value();

                return (new UnsignedInt64Statistic(
                    new UnsignedInt64(v1.add(v2)),
                        getStart(), getEnd()));
        }

        public AggregateStatistic subtract(AggregateStatistic o)
        {
                UnsignedInt64 v1 = getUnsignedInt64Value();
                UnsignedInt64 v2 =  o.getUnsignedInt64Value();

                return (new UnsignedInt64Statistic(
                    new UnsignedInt64(v1.subtract(v2)),
                        getStart(), getEnd()));
        }

        public AggregateStatistic getSnapshotForInterval(Iterator it,
            Date start, Date end) throws IllegalArgumentException
        {
                BigInteger total = new BigInteger("0");
                int count = 0;
                Date first = start, last = end;
                while (it.hasNext()) {
                        UnsignedInt64Statistic s = (UnsignedInt64Statistic)
                            it.next();
                        if (start != null) {
                                if (s.getStart().compareTo(start) < 0)
                                        continue;
                        }
                        if (first == null)
                                first = s.getStart();

                        if (end != null) {
                                if (s.getEnd().compareTo(end) > 0)
                                        continue;
                        }
                        last = s.getEnd();
                        total = total.add(s.getUnsignedInt64Value());
                        count++;
                }
                if (count == 0)
                        throw new IllegalArgumentException("Cannot derive a " +
                            "snapshot from an empty iterator");
                return (new UnsignedInt64Statistic(
                    new UnsignedInt64(total.divide(new BigInteger(
                    Integer.toString(count)))), first, last));
        }
}