All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.integratedmodelling.engine.modelling.TemporalSeries Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 *  Copyright (C) 2007, 2015:
 *  
 *    - Ferdinando Villa 
 *    - integratedmodelling.org
 *    - any other authors listed in @author annotations
 *
 *    All rights reserved. This file is part of the k.LAB software suite,
 *    meant to enable modular, collaborative, integrated 
 *    development of interoperable data and model components. For
 *    details, see http://integratedmodelling.org.
 *    
 *    This program is free software; you can redistribute it and/or
 *    modify it under the terms of the Affero General Public License 
 *    Version 3 or any later version.
 *
 *    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
 *    Affero General Public License for more details.
 *  
 *     You should have received a copy of the Affero General Public License
 *     along with this program; if not, write to the Free Software
 *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *     The license is also available at: https://www.gnu.org/licenses/agpl.html
 *******************************************************************************/
package org.integratedmodelling.engine.modelling;

import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map.Entry;
import java.util.TreeMap;

import org.integratedmodelling.api.knowledge.IConcept;
import org.integratedmodelling.api.knowledge.IKnowledge;
import org.integratedmodelling.api.metadata.IMetadata;
import org.integratedmodelling.api.modelling.IDirectObservation;
import org.integratedmodelling.api.modelling.IExtent;
import org.integratedmodelling.api.modelling.IObservableSemantics;
import org.integratedmodelling.api.modelling.IObserver;
import org.integratedmodelling.api.modelling.IScale;
import org.integratedmodelling.api.modelling.IScale.Index;
import org.integratedmodelling.api.modelling.IScale.Locator;
import org.integratedmodelling.api.modelling.ITopologicallyComparable;
import org.integratedmodelling.api.modelling.storage.IStorage;
import org.integratedmodelling.api.space.ISpatialExtent;
import org.integratedmodelling.api.time.ITemporalExtent;
import org.integratedmodelling.api.time.ITemporalSeries;
import org.integratedmodelling.api.time.ITimeDuration;
import org.integratedmodelling.api.time.ITimeInstant;
import org.integratedmodelling.api.time.ITimePeriod;
import org.integratedmodelling.collections.Pair;
import org.integratedmodelling.common.configuration.KLAB;
import org.integratedmodelling.common.knowledge.Observation;
import org.integratedmodelling.common.vocabulary.NS;
import org.integratedmodelling.engine.time.literals.PeriodValue;
import org.integratedmodelling.engine.time.literals.TimeValue;
import org.integratedmodelling.exceptions.KlabException;
import org.integratedmodelling.exceptions.KlabRuntimeException;
import org.integratedmodelling.exceptions.KlabValidationException;
import org.joda.time.Interval;

public class TemporalSeries extends Observation implements ITemporalSeries {

    // a wrapper for the typed object, which also stores start/end time for which it's valid
    private class WrappedObject {
        final ITimePeriod timePeriod;
        final T           item;

        public WrappedObject(final ITimePeriod timePeriod, final T item) {
            this.timePeriod = timePeriod;
            this.item = item;
        }
    }

    // a sorted collection which can query for "greatest prior"
    private final TreeMap collection = new TreeMap();

    @Override
    public T getFirst() {
        try {
            return collection.firstEntry().getValue().item;
        } catch (Exception e) {
            return null;
        }
    }

    @Override
    public T getLast() {
        try {
            return collection.lastEntry().getValue().item;
        } catch (Exception e) {
            return null;
        }
    }

    @Override
    public T getAtTime(ITimeInstant time) {
        return getWrappedObjectAtTime(time).item;
    }

    @Override
    public IConcept getType() {
        return getObservable().getType();
    }

    @Override
    public T getPrior(ITimeInstant time) {
        Entry entry = collection.lowerEntry(time);
        if (entry == null) {
            return null;
        }
        if (entry.getValue().timePeriod.contains(time)) {
            entry = collection.lowerEntry(entry.getKey());
        }
        if (entry == null) {
            return null;
        }
        return entry.getValue().item;
    }

    @Override
    public T getFollowing(ITimeInstant time) {
        Entry earliestNextEntry = collection.ceilingEntry(time);
        // NOTE: by exclusive-inclusive semantics, key might equal time, which is OK.

        if (earliestNextEntry == null) {
            // no intervals exist which start after the query time.
            return null;
        }
        return earliestNextEntry.getValue().item;
    }

    private WrappedObject getWrappedObjectAtTime(ITimeInstant time) {
        Entry latestPriorEntry = collection.lowerEntry(time);
        if (latestPriorEntry == null) {
            // no intervals exist which start before the query time.
            return null;
        }
        WrappedObject latestPrior = latestPriorEntry.getValue();
        if (!latestPrior.timePeriod.contains(time)) {
            // the latest-starting interval prior to the query time expires before the query time,
            // so there is no matching interval for this query time.
            return null;
        }
        // the interval contains the time, so return the enclosed value.
        return latestPrior;
    }

    @Override
    public void put(ITimeInstant start, ITimeInstant end, T item) throws KlabException {
        Interval interval = new Interval(start.getMillis(), end.getMillis());
        put(interval, item);
    }

    public void put(Interval interval, T item) throws KlabException {
        PeriodValue timePeriod = new PeriodValue(interval);
        put(timePeriod, item);
    }

    @Override
    public void put(ITimePeriod timePeriod, T item) {
        ITimeInstant endTime = new TimeValue(timePeriod.getEnd().getMillis());
        WrappedObject wrapper = new WrappedObject(timePeriod, item);

        // do any existing periods overlap with what is being written?
        Entry latestPriorEntry = collection.floorEntry(endTime);
        if (latestPriorEntry != null && latestPriorEntry.getValue().timePeriod.contains(endTime)) {
            // latest prior entry overlaps the end time, so we can't write the interval.
            throw new KlabRuntimeException("Cannot write the interval " + wrapper + " to TemporalScale "
                    + this + " because it overlaps with interval " + latestPriorEntry + ".");
        }

        ITimeInstant startTime = new TimeValue(timePeriod.getStart().getMillis());
        collection.put(startTime, wrapper);
    }

    @Override
    public void remove(ITimeInstant time) {
        WrappedObject wrappedObject = getWrappedObjectAtTime(time);
        collection.remove(wrappedObject.timePeriod.getStart());
    }

    @Override
    public ITimePeriod shorten(ITimeInstant spliceTime) throws KlabException {
        WrappedObject originalWrappedObject = getWrappedObjectAtTime(spliceTime);
        T item = originalWrappedObject.item;
        ITimePeriod originalTimePeriod = originalWrappedObject.timePeriod;

        // sanity check - new end time must be within original time period
        if (!originalTimePeriod.contains(spliceTime)) {
            throw new KlabValidationException("shorten() was called using the new end time "
                    + spliceTime.toString() + ", which is outside the original time period "
                    + originalTimePeriod.toString());
        }

        // create the new state. We don't have to validate for overlaps because we know we're shrinking the
        // time period.
        ITimePeriod newTimePeriod = new PeriodValue(originalTimePeriod.getStart().getMillis(), spliceTime
                .getMillis());
        WrappedObject newWrappedObject = new WrappedObject(newTimePeriod, item);
        collection.remove(originalTimePeriod.getStart());
        collection.put(originalTimePeriod.getStart(), newWrappedObject);

        return newTimePeriod;
    }

    @Override
    public ITimePeriod bisect(ITimeInstant spliceTime, T object) throws KlabException {
        ITimeInstant endTime = getWrappedObjectAtTime(spliceTime).timePeriod.getEnd();
        shorten(spliceTime);
        PeriodValue newTimePeriod = new PeriodValue(spliceTime.getMillis(), endTime.getMillis());
        put(newTimePeriod, object);
        return newTimePeriod;
    }

    @Override
    public Collection getOverlapping(ITimePeriod timePeriod) {
        Collection result = new LinkedList();

        // step forward through time finding all overlapping time periods
        Entry currentEntry = collection.floorEntry(timePeriod.getStart());
        WrappedObject wrappedObject;
        while (currentEntry != null) {
            // does the next wrappedObject time period overlap the one requested?
            wrappedObject = currentEntry.getValue();
            if (!wrappedObject.timePeriod.overlaps(timePeriod)) {
                break;
            }
            result.add(wrappedObject.item);
            currentEntry = collection.higherEntry(currentEntry.getKey());
        }

        return result;
    }

    /* THE ITemporalExtent METHODS */
    @Override
    public ITemporalExtent getExtent(int stateIndex) {
        Entry result = collection.firstEntry();
        ITimeInstant currentPosition = result.getKey();
        for (int i = 0; i < stateIndex && result != null; i++) {
            result = collection.higherEntry(currentPosition);
            currentPosition = result.getKey();
        }
        return result == null ? null : result.getValue().timePeriod;
    }

    @Override
    public ITimePeriod collapse() {
        ITimeInstant start = getStart();
        ITimeInstant end = getEnd();
        if (start == null || end == null) {
            return null;
        }
        return new PeriodValue(start.getMillis(), end.getMillis());
    }

    @Override
    public ITemporalExtent intersection(IExtent other) throws KlabException {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public ITimeInstant getStart() {
        return collection.firstKey();
    }

    @Override
    public ITimeInstant getEnd() {
        Entry lastEntry = collection.lastEntry();
        if (lastEntry == null) {
            return null;
        }
        return lastEntry.getValue().timePeriod.getEnd();
    }

    @Override
    public IConcept getDomainConcept() {
        return KLAB.c(NS.TIME_DOMAIN);
    }


    @Override
    public boolean isCovered(int stateIndex) {
        // TODO Auto-generated method stub
        return true;
    }

    @Override
    public IExtent merge(IExtent extent, boolean force) throws KlabException {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public Pair, Double> checkCoverage(ITopologicallyComparable obj)
            throws KlabException {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public boolean isConsistent() {
        return true;
    }

    @Override
    public boolean isEmpty() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public long getValueCount() {
        return collection.size();
    }

    @Override
    public IObserver getObserver() {
        return null;
    }

    @Override
    public boolean isSpatiallyDistributed() {
        return false;
    }

    @Override
    public boolean isTemporallyDistributed() {
        return getValueCount() > 1;
    }

    @Override
    public boolean isTemporal() {
        return true;
    }

    @Override
    public boolean isSpatial() {
        return false;
    }

    @Override
    public ISpatialExtent getSpace() {
        return null;
    }

    @Override
    public ITemporalExtent getTime() {
        return this;
    }

    @Override
    public double getCoveredExtent() {
        // TODO a double that can be used to compare objects
        return 0;
    }

    //
    // @Override
    // public INamespace getNamespace() {
    // // TODO Auto-generated method stub
    // return null;
    // }
    //
    // @Override
    // public IConcept getDirectType() {
    // return Time.TIME_DOMAIN;
    // }
    //
    // @Override
    // public boolean is(Object other) {
    // // TODO Auto-generated method stub
    // return false;
    // }

    @Override
    public IMetadata getMetadata() {
        return null;
    }

    @Override
    public long getMultiplicity() {
        return getValueCount();
    }

    @Override
    public IExtent union(IExtent other) throws KlabException {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public boolean contains(IExtent o) throws KlabException {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean overlaps(IExtent o) throws KlabException {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean intersects(IExtent o) throws KlabException {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public ITopologicallyComparable union(ITopologicallyComparable other)
            throws KlabException {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public ITopologicallyComparable intersection(ITopologicallyComparable other)
            throws KlabException {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public IScale getScale() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public Object getValue(int index) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public Iterator iterator(Index index) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public int[] getDimensionSizes() {
        return new int[] { (int) getMultiplicity() };
    }

    @Override
    public int[] getDimensionOffsets(int linearOffset, boolean rowFirst) {
        return new int[] { linearOffset };
    }

    // @Override
    // public Class getDataClass() {
    // // TODO Auto-generated method stub
    // return null;
    // }

    // @Override
    // public BitSet getMask() {
    // // TODO Auto-generated method stub
    // return null;
    // }

    @Override
    public ITemporalExtent getExtent() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public ITimeDuration getStep() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public IStorage getStorage() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public int locate(Locator locator) {
        // TODO Auto-generated method stub
        return -1;
    }

    @Override
    public Mediator getMediator(IExtent extent, IObservableSemantics observable, IConcept trait) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public boolean isConstant() {
        return getMultiplicity() == 1;
    }

    @Override
    public IDirectObservation getContextObservation() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public boolean isDynamic() {
        return getMultiplicity() > 1;
    }

    @Override
    public void addChangeListener(ChangeListener listener) {
        // TODO Auto-generated method stub
        
    }

}