Package ch.agent.t2.timeutil

Source Code of ch.agent.t2.timeutil.RangeHolder

/*
*   Copyright 2011-2013 Hauser Olsson GmbH
*
* 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 ch.agent.t2.timeutil;

import ch.agent.t2.T2Exception;
import ch.agent.t2.T2Msg;
import ch.agent.t2.T2Msg.K;
import ch.agent.t2.time.Adjustment;
import ch.agent.t2.time.Day;
import ch.agent.t2.time.Range;
import ch.agent.t2.time.Resolution;
import ch.agent.t2.time.TimeDomain;
import ch.agent.t2.time.TimeIndex;

/**
* A RangeHolder helps applications manipulate time ranges.
* <p>
* If necessary, dates are adjusted. Adjustment is upwards for the
* start of the range and downwards for the end.
*
* @author Jean-Paul Vetterli
*/
public class RangeHolder {

  private TimeDomain domain;
  private DayExpression beginExpr; // beginExpr == null <==> endExpr == null
  private DayExpression endExpr;
  private Adjustment beginAdj = Adjustment.UP;
  private Adjustment endAdj = Adjustment.DOWN;
 
  /**
   * Construct a range holder in the given time domain and initialized
   * with the given time. If the given time is null the range will be empty.
   *
   * @param domain
   *            a non-null time domain
   * @param time
   *            a time index or null
   */
  private RangeHolder(TimeDomain domain, TimeIndex time) {
    this.domain = domain;
    if (time != null) {
      this.newExpr();
      this.beginExpr.setTime(time);
      this.endExpr.setTime(time);
    } else
      setEmpty();
  }
 
  /**
   * Construct a range holder with the given time domain and
   * initialized with the current time.
   *
   * @param domain
   *            a non-null time domain
   */
  public RangeHolder(TimeDomain domain) {
    this(domain, TimeUtil.now(domain));
  }

  /**
   * Construct a range holder in the daily time domain and
   * initialized with the current time.
   */
  public RangeHolder() {
    this(Day.DOMAIN);
  }

  /**
   * Construct a range holder for the given range.
   *
   * @param range a non-null range
   */
  public RangeHolder(Range range){
    this(range.getTimeDomain(), null);
    reset(range);
  }
 
  /**
   * Construct a range holder as a copy of the given model.
   *
   * @param model a non-null range holder
   */
  public RangeHolder(RangeHolder model) {
    domain = model.domain;
    beginExpr = model.beginExpr == null ? null : new DayExpression(model.beginExpr);
    endExpr = model.endExpr == null ? null : new DayExpression(model.endExpr);
    beginAdj = model.beginAdj;
    endAdj = model.endAdj;
  }
 
  private void setEmpty() {
    beginExpr = null;
    endExpr = null;
  }
 
  private void newExpr() {
    if (beginExpr == null) {
      beginExpr = new DayExpression(beginAdj);
      endExpr = new DayExpression(endAdj);
    }
  }
 
  /**
   * Return the time domain.
   *
   * @return the time domain of the range
   */
  public TimeDomain getTimeDomain() {
    return domain;
  }
 
  /**
   * Change the range to the given range.
   *
   * @param range a non-null range
   */
  public void reset(Range range){
    domain = range.getTimeDomain();
    if (range.isEmpty())
      setEmpty();
    else {
      newExpr();
      beginExpr.setTime(range.getFirst());
      endExpr.setTime(range.getLast());
    }
  }
 
  /**
   * Change the time domain of the range holder. The day expressions of
   * the current bounds are retained.
   *
   * @param domain a non-null domain
   * @throws T2Exception
   */
  public void reset(TimeDomain domain) throws T2Exception {
    if (domain == null)
      throw new IllegalArgumentException("domain null");
    String begin = getBeginText();
    String end = getEndText();
    this.domain = domain;
    setBegin(begin, false);
    setEnd(end);
  }

  /**
   * Set the date for the range beginning. A null or empty date is allowed.
   * This is useful for signaling that no date is specified.
   * The method has a side-effect on the other extremity of the range.
   * Refer to {@link DayExpression} for the valid syntax of dates.
   *
   * @param date a day expression
   * @throws T2Exception
   */
  public void setBegin(String date) throws T2Exception {
    setBegin(date, true);
  }
 
  private void setBegin(String date, boolean enforceValidRange) throws T2Exception {
    DayExpression previousBegin = beginExpr == null ? null : new DayExpression(beginExpr);
    if (date == null || date.length() == 0)
      setEmpty();
    else {
      newExpr();
      beginExpr.setExpression(domain, date);
      if (enforceValidRange)
        enforceValidRange(true, previousBegin);
    }
  }
 
  /**
   * Set the date for the range end. A null or empty date is allowed.
   * This is useful for signaling that no date is specified.
   * The method has a side-effect on the other extremity of the range.
   * Refer to {@link DayExpression} for the valid syntax of dates.
   *
   * @param date a day expression
   * @throws T2Exception
   */
  public void setEnd(String date) throws T2Exception {
    DayExpression previousEnd = endExpr == null ? null : new DayExpression(endExpr);
    if (date == null || date.length() == 0)
      setEmpty();
    else {
      newExpr();
      endExpr.setExpression(domain, date);
      enforceValidRange(false, previousEnd);
    }
  }
 
  /**
   * Increment the beginning of the range by the given amount. If no date is
   * currently set, the method has the same effect as setting the beginning to
   * the current time.
   * The method has a side-effect on the other extremity of the range.
   *
   * @param increment
   *            a positive or negative number
   */
  public void incrBegin(int increment) throws T2Exception {
    if (increment == 0)
      return;
    DayExpression previousBegin = null;
    if (beginExpr == null)
      setBegin(TimeUtil.now(domain).toString());
    else {
      previousBegin = new DayExpression(beginExpr);
      beginExpr.incr(increment);
    }
    enforceValidRange(true, previousBegin);
  }
 
  /**
   * Increase or decrease the beginning of the range by a unit or by a large amount.
   * What constitutes a large amount depends on the resolution of the time domain.
   * The method has a side-effect on the other extremity of the range.
   *
   * @param up if true increase, else decrease
   * @param large if true use a large amount, else a single unit
   * @throws T2Exception
   */
  public void incrBegin(boolean up, boolean large) throws T2Exception {
    int incr = 1;
    if (large) {
      if (beginExpr.isToday())
        incr = DateHolder.getLargeIncrement(Resolution.DAY);
      else
        incr = DateHolder.getLargeIncrement(domain.getResolution());
    }
    incrBegin(up ? incr : -incr);
  }
 
  /**
   * Increment the end of the range by the given amount. If no date is
   * currently set, the method has the same effect as setting the beginning to
   * the current time.
   * The method has a side-effect on the other extremity of the range.
   *
   * @param increment
   *            a positive or negative number
   */
  public void incrEnd(int increment) throws T2Exception {
    if (increment == 0)
      return;
    DayExpression previousEnd = null;
    if (endExpr == null)
      setEnd(TimeUtil.now(domain).toString());
    else {
      previousEnd = new DayExpression(endExpr);
      endExpr.incr(increment);
    }
    enforceValidRange(false, previousEnd);
  }
 
  /**
   * Increase or decrease the end of the range by a unit or by a large amount.
   * What constitutes a large amount depends on the resolution of the time domain.
   * The method has a side-effect on the other extremity of the range.
   *
   * @param up if true increase, else decrease
   * @param large if true use a large amount, else a single unit
   * @throws T2Exception
   */
  public void incrEnd(boolean up, boolean large) throws T2Exception {
    int incr = 1;
    if (large) {
      if (endExpr.isToday())
        incr = DateHolder.getLargeIncrement(Resolution.DAY);
      else
        incr = DateHolder.getLargeIncrement(domain.getResolution());
    }
    incrEnd(up ? incr : -incr);
  }

  /**
   * Return the text of the day expression set with {@link RangeHolder#setBegin(String) setBegin}.
   * If a date was never set, an empty string is returned.
   * To get the resolved date, use one of the {@link RangeHolder#getRange getRange} methods.
   * The method never returns null.
   *
   * @return the text of the current day expression for the beginning of the range or an empty string
   */
  public String getBeginText() {
    if (beginExpr == null)
      return "";
    else
      return beginExpr.getExpression();
  }
 
  /**
   * Return the text of the day expression set with {@link RangeHolder#setEnd(String) setEnd}.
   * If a date was never set, an empty string is returned.
   * To get the resolved date, use one of the {@link RangeHolder#getRange getRange} methods.
   * The method never returns null.
   *
   * @return the text of the current day expression for the end of the range or an empty string
   */
  public String getEndText() {
    if (endExpr == null)
      return "";
    else
      return endExpr.getExpression();
  }
 
  /**
   * Get the range evaluated in the time domain of the range holder.
   *
   * @return a range
   * @throws T2Exception
   */
  public Range getRange() throws T2Exception {
    return getRange(domain);
  }
 
  /**
   * Get the range evaluated in the context of the given domain.
   *
   * @param context a non-null time domain
   * @return a range
   * @throws T2Exception
   */
  public Range getRange(TimeDomain context) throws T2Exception {
    if (beginExpr == null)
      return new Range(context);
    else
      return new Range(beginExpr.getDate(context), endExpr.getDate(context));
  }
 
  /**
   * Get the range evaluated in the context of the given range.
   * If the holder does not contain any info, an empty range is returned. If
   * the domain needs conversion, steps are taken to avoid invalid
   * ranges. For example, when because of adjustments the daily range
   * [1980-11-22, 1980-11-22] would be turned into the Monday to Friday range
   * [1980-11-24, 1980-11-21], the method fixes it to [1980-11-21,
   * 1980-11-21].
   *
   * @param context non-null range
   * @return a range
   * @throws T2Exception
   */
  public Range getRange(Range context) throws T2Exception {
    TimeDomain contextDomain = context.getTimeDomain();
    if (beginExpr == null) {
      return new Range(contextDomain);
    } else {
      // be more permissive with context and fix ranges invalidated by conversion
      TimeIndex begin = beginExpr.getDate(context);
      TimeIndex end = endExpr.getDate(context);
      if (begin == null || end == null) // (consequence of empty context range when context needed)
        return new Range(contextDomain);
      else if (begin.compareTo(end) > 0 && (beginExpr.needContext() || endExpr.needContext()))
        return new Range(contextDomain);
      else {
        /*
         * There is a possibly that a valid range has been converted
         * into an invalid one. Typical case: daily(Sat, Sat) turned
         * into MoFr(Mon,Fri) because of adjustments. As this is not
         * the intended effect of adjustments, the problem is fixed
         * silently here.
         */
        if (begin.compareTo(end) > 0 && beginAdj == Adjustment.UP) {
          beginExpr.setTime(end);
          begin = beginExpr.getDate(context);
        }
        return new Range(begin, end);
      }
    }
  }
 
  /**
   * Return true if the range holder needs a context for evaluating dates.
   *
   * @return true if a context is needed
   */
  public boolean needContext() {
    return (beginExpr != null && beginExpr.needContext())
      || (endExpr != null && endExpr.needContext());
  }
 
  /**
   * This method enforces a valid range. If anything goes wrong, it resets the
   * day expressions to their previous state. When keepBegin is true, the
   * previous argument is the previous value of the begin day expression. When
   * it is false, the previous argument is the previous value of the end day
   * expression.
   *
   * @param keepBegin
   * @param previous
   * @throws T2Exception
   */
  private void enforceValidRange(boolean keepBegin, DayExpression previous) throws T2Exception {
    DayExpression previous2 = new DayExpression(keepBegin ? endExpr : beginExpr);
    if (!endExpr.enforceValidRange(domain, beginExpr, keepBegin)) {
      // repair
      if (keepBegin) {
        beginExpr.reset(previous);
        endExpr.reset(previous2);
      } else {
        beginExpr.reset(previous2);
        endExpr.reset(previous);
      }
      throw T2Msg.exception(K.T7027);
    }
  }
 
}
TOP

Related Classes of ch.agent.t2.timeutil.RangeHolder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.