Package org.dbwiki.data.time

Source Code of org.dbwiki.data.time.TimeSequence

/*
    BEGIN LICENSE BLOCK
    Copyright 2010-2011, Heiko Mueller, Sam Lindley, James Cheney and
    University of Edinburgh

    This file is part of Database Wiki.

    Database Wiki 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, either version 3 of the License, or
    (at your option) any later version.

    Database Wiki 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 Database Wiki.  If not, see <http://www.gnu.org/licenses/>.
    END LICENSE BLOCK
*/
package org.dbwiki.data.time;

import java.util.Vector;

import org.dbwiki.exception.data.WikiDataException;

/** Represents a set of time points using a sequence of intervals.
* Invariants we should maintain:
* 1.  The intervals are disjoint
* 2.  The intervals are increasing (start1 < end1 < start2 < end2 ...)
* 3.  There are no gaps
* @author jcheney
*
*/
public class TimeSequence {
  /*
   * Private Constants
   */
 
  public static final String OpenIntervalChar = "*";
 
 
  /*
   * Private variables
   */
 
  private Vector<TimeInterval> _intervals;
 
  /*
   * Constructors
   */
 
  /** Make a time sequence with an empty set of time intervals
   *
   */
  public TimeSequence() {
    _intervals = new Vector<TimeInterval>();
  }
 
  /** Generate a time sequence from a text representation of the timestamp
   * @param text
   * @throws org.dbwiki.exception.WikiException
   */
 
  public TimeSequence(String text) throws org.dbwiki.exception.WikiException {

    _intervals = parseTimeSequence(text);
    this.checkForConsistency();
  }
 
  /** Parses a string of the form s-e,...,s-e to a time sequence
   * TODO: Clean this up to avoid string surgery
   * @param text
   * @return
   */
  public static Vector<TimeInterval> parseTimeSequence(String text) {
    String tmp = text;

    Vector<TimeInterval> intervals = new Vector<TimeInterval>();
   
    int pos;
    while ((pos = tmp.indexOf(',')) != -1) {
      intervals.add(TimeInterval.parseInterval(tmp.substring(0, pos).trim()));
      tmp = tmp.substring(pos + 1).trim();
    }
    intervals.add(TimeInterval.parseInterval(tmp));
    return intervals;
  }
 

 
 
  /** Make set with single interval starting at time and ending at "now"
   *
   * @param time
   * @param timestampPrinter
   */
  public TimeSequence(int time) {
    _intervals = new Vector<TimeInterval>();
    _intervals.add(new TimeInterval(time));
  }

  /** Make set with single interval starting at start and ending at end
   *
   * @param start
   * @param end
   * @param timestampPrinter
   */
  public TimeSequence(int start, int end) {
    _intervals = new Vector<TimeInterval>();
    _intervals.add(new TimeInterval(start, end));
  }
 
  /** Make a time sequence from a version
   *
   * @param version
   */
  public TimeSequence(Version version) {
    this(version.number());
  }

  /** Make a time sequence from a given set of time intervals
   *
   * @param intervals
   */
  public TimeSequence(Vector<TimeInterval> intervals) {
    _intervals = intervals;
  }

  /** Make a time sequence from a vector of intervals
   *
   * @param intervals
   * @param timestampPrinter
   */
  public TimeSequence(Vector<TimeInterval> intervals, VersionIndex index) {
    _intervals = intervals;
  }

 
  /*
   * Public Methods
   */

  /** Adds the given time interval to the time sequence
   *
   * @param interval
   */
  public void add(TimeInterval interval) {
   
    if (_intervals.isEmpty()) {
      _intervals.add(interval);
    } else {
      if (!_intervals.lastElement().isOpen()) {
        if (_intervals.lastElement().end() > interval.start()) {
          if (interval.isOpen()) {
            _intervals.lastElement().extend(interval.end());
          } else {
            _intervals.lastElement().extend(Math.max(_intervals.lastElement().end(), interval.end()));
          }
        } else if (_intervals.lastElement().end() == (interval.start() - 1)) {
          _intervals.lastElement().extend(interval.end());
        } else {
          _intervals.add(interval);
        }
      }
    }
  }

  /** Tests whether there is a change between the given time and now
   *
   */
  public boolean changedSince(int time) {
    TimeInterval interval = _intervals.lastElement();
   
    if (interval.isOpen()) {
      return (interval.start() > time);
    } else {
      return (interval.end() >= time);
    }
  }
 
  /** Tests whether the set contains a given time.
   *
   * @param time
   * @return
   */
  public boolean contains(int time) {
    for (int iInterval = 0; iInterval < _intervals.size(); iInterval++) {
      if (_intervals.get(iInterval).contains(time)) {
        return true;
      }
    }
    return false;
  }

  /** Creates a new time sequence that is a copy of the current one plus an open interval starting at time
   *
   * @param time
   * @return
   */
  public TimeSequence continueAt(int time) {
    Vector<TimeInterval> intervals = new Vector<TimeInterval>();
    for (int iInterval = 0; iInterval < _intervals.size(); iInterval++) {
      intervals.add(_intervals.get(iInterval));
    }
    intervals.add(new TimeInterval(time));
    return new TimeSequence(intervals);
  }
 
  /**
   * Extend set with [start,end] provided there isn't already an interval starting at start
   * @param start
   * @param end
   */
  public void elongate(int start, int end) {
    for (int iInterval = 0; iInterval < _intervals.size(); iInterval++) {
      if (_intervals.get(iInterval).start() == start) {
        return;
      }
    }
    _intervals.add(new TimeInterval(start, end));
  }
 
  /** Create a new TimeSequence that is a copy of this one except that the last
   * interval is adjusted to be [start,time], overriding the old end value.
   * Typically used when the interval is open.
   *
   * @param time
   * @return
   */
  public TimeSequence finishAt(int time) {
    Vector<TimeInterval> intervals = new Vector<TimeInterval>();
    for (int iInterval = 0; iInterval < _intervals.size() - 1; iInterval++) {
      intervals.add(_intervals.get(iInterval));
    }
    TimeInterval interval = _intervals.lastElement();
    intervals.add(new TimeInterval(interval.start(), time));
    return new TimeSequence(intervals);
  }
 
  /** The first (smallest?) value
   * */
  public int firstValue() {
    return _intervals.get(0).start();
  }

  /** Returns the time interval at position index
   *
   * @param index
   * @return
   */
  public TimeInterval get(int index) {
    return _intervals.get(index);
  }
 
  /** Create a new TimeSequence that is an intersection of all the intervals
   * of this TimeSequence and a given TimeSequence
   * @param timestamp
   * @return
   * @throws org.dbwiki.exception.WikiException
   */
  public TimeSequence intersect(TimeSequence timestamp) {
   
    Vector<TimeInterval> intervals = new Vector<TimeInterval>();
    for (int iInterval = 0; iInterval < _intervals.size(); iInterval++) {
      TimeInterval intervalI = this.get(iInterval);
      for (int jInterval = 0; jInterval < timestamp.size(); jInterval++) {
        TimeInterval intervalJ = timestamp.get(jInterval);
        if (intervalI.overlap(intervalJ)) {
          intervals.add(intervalI.intersect(intervalJ));
        }
      }
    }
    return new TimeSequence(intervals);
  }

  /** Creates a copy of the list of intervals
   * FIXME #time: It doesn't seem necessary to make a copy, since the copy isn't used destructively anywhere.
   *
   * @return
   */
  public TimeInterval[] intervals() {
    TimeInterval[] intervals = new TimeInterval[_intervals.size()];
    for (int iInterval = 0; iInterval < _intervals.size(); iInterval++) {
      intervals[iInterval] = _intervals.get(iInterval);
    }
    return intervals;
  }

  /**
   * Determine whether a set is current, by checking whether the last interval
   * ends "now"
   * @return
   */
  public boolean isCurrent() {
    return _intervals.lastElement().isOpen();
  }

  /**
   * Determine whether the timestamp is empty
   * @return
   */
  public boolean isEmpty() {
    return _intervals.isEmpty();
  }
 
  /**
   * Fetch the last interval in the set.
   * @return
   */
  public TimeInterval lastInterval() {
    return _intervals.lastElement();
  }
 
  /**
   * Fetch the last value, either -1 for "now" or the endpoint of the last interval.
   * @return
   */
  public int lastValue() {
    TimeInterval interval = _intervals.lastElement();
    if (interval.isOpen()) {
      return -1;
    } else {
      return interval.end();
    }
  }

  public boolean overlap(TimeSequence timestamp) {
   
    if ((this.isCurrent()) && (timestamp.isCurrent())) {
      return true;
    }
   
    int idxI = 0;
    int idxJ = 0;
   
    while ((idxI < this.size()) && (idxJ < timestamp.size())) {
      TimeInterval intervalI = this.get(idxI);
      TimeInterval intervalJ = timestamp.get(idxJ);
      if (intervalI.overlap(intervalJ)) {
        return true;
      } else if (intervalI.start() < intervalJ.start()) {
        idxI++;
      } else {
        idxJ++;
      }
    }
    return false;
  }
 
  /** Returns the number of intervals in this time sequence
   *
   * @return
   */
  public int size() {
    return _intervals.size();
  }
 
  /** Builds a string of start-end pairs
   *
   * @return
   */
  public String toIntString() {
    String text = _intervals.get(0).toIntString();
    if (_intervals.size() > 1) {
      for (int iInterval = 1; iInterval < _intervals.size(); iInterval++) {
        text = text + "," + _intervals.get(iInterval).toIntString();
      }
    }
    return text;
  }
 
  /** Builds a string representing the interval, using timestampPrinter to convert
   * version numbers to datetimes
   *
   * @return
   * @throws org.dbwiki.exception.WikiException
   */
  /*@Deprecated
  public String toPrintString() throws org.dbwiki.exception.WikiException {
    return _timestampPrinter.toString(this);
  }*/
 
  public TimeSequence union(TimeSequence timestamp) {
   
    TimeSequence result = new TimeSequence();
   
    int idxI = 0;
    int idxJ = 0;
   
    while ((idxI < this.size()) && (idxJ < timestamp.size())) {
      TimeInterval intervalI = this.get(idxI);
      TimeInterval intervalJ = timestamp.get(idxJ);
      if (intervalI.contains(intervalJ)) {
        idxJ++;
      } else if (intervalJ.contains(intervalI)) {
        idxI++;
      } else if (intervalI.overlap(intervalJ)) {
        if ((intervalI.isOpen()) || (intervalJ.isOpen())) {
          result.add(new TimeInterval(Math.min(intervalI.start(), intervalJ.start())));
        } else {
          result.add(new TimeInterval(Math.min(intervalI.start(), intervalJ.start()), Math.max(intervalI.end(), intervalJ.end())));
        }
        idxI++;
        idxJ++;
      } else if (intervalI.start() < intervalJ.start()) {
        result.add(intervalI.copy());
        idxI++;
      } else {
        result.add(intervalJ.copy());
        idxJ++;
      }
    }
    while (idxI < this.size()) {
      result.add(this.get(idxI++).copy());
    }
    while (idxJ < timestamp.size()) {
      result.add(timestamp.get(idxJ++).copy());
    }
   
    return result;
  }

  /*
   * Private Methods
   */
 
  /**
   * FIXME: A bit hacky.
   *
   */
  private void checkForConsistency() throws org.dbwiki.exception.WikiException {
   
    for (int iInterval = 1; iInterval < _intervals.size(); iInterval++) {
      if (_intervals.get(iInterval - 1).isOpen()) {
        throw new WikiDataException(WikiDataException.InvalidTimestamp, this.toIntString());
      }
      if (_intervals.get(iInterval).start() <= _intervals.get(iInterval - 1).end()) {
        throw new WikiDataException(WikiDataException.InvalidTimestamp, this.toIntString());
      }
    }
  }

 
}
TOP

Related Classes of org.dbwiki.data.time.TimeSequence

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.