/* ==============================================
* Simtools : The tools library used in JSynoptic
* ==============================================
*
* Project Info: http://jsynoptic.sourceforge.net/index.html
*
* This library is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation;
* either version 2.1 of the License, or (at your option) any later version.
*
* This library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* (C) Copyright 2003, by :
* Corporate:
* Astrium SAS
* EADS CRC
* Individual:
* Nicolas Brodu
*
* $Id: DataSourceCollectionAnimator.java,v 1.7 2007/10/05 09:37:49 ogor Exp $
*
* Changes
* -------
* 25-Sep-2003 : Initial public release (NB);
*
*/
package simtools.data;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Timer;
import java.util.TimerTask;
/**
* This class adds dynamical features to a DataSourceCollection. This is useful
* to replay time series, for example. It will use the underlying collection to
* provide the values, and has its own API to control how to advance the index :
* step by step, or with a timer.
*
* Note: All APIs from superclasses are also redirected, including vector.
* Collective data sources are also redirect to us. So, this wrapper should
* really be transparent. This is especially important to understand the code
* behind buffer functions also works without overloading base functions.
*
* @author Nicolas Brodu
*/
public class DataSourceCollectionAnimator extends DynamicDataSourceCollection implements DataSourceCollectionListener {
static public final String MARKER = "AnimatedCollection:";
protected DataSourceCollection target;
protected long period = 1000;
protected Timer timer;
protected boolean finished;
protected boolean autoStop;
/**
* @return true iff the underlying data source has no more values
*/
public boolean isFinished() {
return finished;
}
public DataSourceCollectionAnimator(DataSourceCollection dsc) {
if (dsc instanceof DataSourceCollectionAnimator) {
target = ((DataSourceCollectionAnimator) dsc).target;
}
target = dsc;
sourceInfo = new SourceInfo[target.size()];
for (int i = 0; i < target.size(); ++i) {
CollectiveDataSource cds = (CollectiveDataSource) target.get(i);
sourceInfo[i] = new SourceInfo();
sourceInfo[i].info = target.getInformation(i);
sourceInfo[i].kind = target.getKind(i);
cds.collection = this; // redirect to us, especially important for
// buffers
}
target.addListener(this);
}
/*
* (non-Javadoc)
*
* @see simtools.data.DynamicDataSourceCollection#getInformation()
*/
public DataInfo getInformation() {
ourInfo = DataInfo.clone(target.getInformation());
ourInfo.id = MARKER + ourInfo.id;
return ourInfo;
}
/** Increase current index */
public void step() throws DataException {
try {
for (int i = 0; i < target.size(); ++i) {
switch (sourceInfo[i].kind) {
// / case ValueProvider.TypeProvider:
// super.setTypeValue(i,target.getTypeValue(i,lastIndex+1));
// ------ START of perl-generated corresponding code --------
case ValueProvider.ByteProvider:
super.setByteValue(i, target.getByteValue(i, lastIndex + 1));
case ValueProvider.ShortProvider:
super.setShortValue(i, target.getShortValue(i, lastIndex + 1));
case ValueProvider.IntegerProvider:
super.setIntegerValue(i, target.getIntegerValue(i, lastIndex + 1));
case ValueProvider.LongProvider:
super.setLongValue(i, target.getLongValue(i, lastIndex + 1));
case ValueProvider.FloatProvider:
super.setFloatValue(i, target.getFloatValue(i, lastIndex + 1));
case ValueProvider.DoubleProvider:
super.setDoubleValue(i, target.getDoubleValue(i, lastIndex + 1));
// -------- END of perl-generated corresponding code
// --------
case ValueProvider.ObjectProvider:
super.setObjectValue(i, target.getValue(i, lastIndex + 1));
}
}
finished = false;
} catch (DataException de) {
if (autoStop && (de instanceof NoSuchIndex)) {
finished = true;
}
throw de;
}
super.registerNewValues();
}
/**
* @return The current period, in milliseconds
*/
public long getPeriod() {
return period;
}
/**
* Sets a period for cyclic execution
*
* @param period,
* in milliseconds
*/
public void setPeriod(long period) {
if (isRunning()) {
stop();
this.period = period;
start();
} else {
this.period = period;
}
}
/**
* @return true is the values are beeing updated cyclically.
*/
public boolean isRunning() {
return timer != null;
}
/**
* Starts to update the values with the given period.
*/
public void start(long period) {
if (isRunning()) {
return;
}
this.period = period;
start();
}
/**
* Starts to update the values with the previously set period. Default is 1
* second.
*/
public void start() {
if (isRunning()) {
return;
}
timer = new Timer(true); // do not block the application on exit
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
try {
step();
} catch (DataException e) {
if (autoStop && (e instanceof NoSuchIndex)) {
stop(); // Exits gracefully when there is no more data
}
}
}
}, 0, period);
}
/**
* Stop to update the values. This method is automatically called when there
* is no more data in the underlying data source, if this option is chosen.
*/
public void stop() {
if (!isRunning()) {
return;
}
timer.cancel();
timer = null;
}
/**
* Resets the source. Next call to step will show the first source element.
*/
public void reset() {
synchronized (this) {
if (buffers != null) {
for (int i = 0; i < buffers.length; ++i) {
if (buffers[i] != null) {
buffers[i].clear();
}
}
}
this.lastIndex = -1;
finished = false;
}
for (int i = 0; i < size(); ++i) {
DataSource ds = (DataSource) get(i);
ds.notifyListenersForIndexRangeChange(getStartIndex(i), getLastIndex(i));
}
}
/**
* @return Returns the autoStop.
*/
public boolean isAutoStop() {
return autoStop;
}
/**
* @param autoStop
* The autoStop to set.
*/
public void setAutoStop(boolean autoStop) {
this.autoStop = autoStop;
}
protected DataSource createDataSource(DataInfo info, int kind) {
throw new java.lang.UnsupportedOperationException();
}
protected DataSource createDataSource(DataInfo info) {
throw new java.lang.UnsupportedOperationException();
}
// We listen to our target
// And propagate the changes together with our own listeners
public void DataSourceCollectionInfoChanged(DataSourceCollection dsc, DataInfo newInfo) {
notifyListenersForInfoChange(newInfo);
}
public void DataSourceCollectionDataSourceAdded(DataSourceCollection dsc, DataSource ds) {
// Ouch, quite Bad!!!
throw new java.lang.UnsupportedOperationException();
}
public void DataSourceCollectionDataSourceRemoved(DataSourceCollection dsc, DataSource ds) {
// Ouch, quite Bad!!!
throw new java.lang.UnsupportedOperationException();
}
public void DataSourceCollectionRemoved(DataSourceCollection dsc) {
}
// Keep this one, not necessary but very slighly more performant like that
// (Vector API extension)
public DataSource get(String id) {
return target.get(id);
}
// Vector overload
public synchronized void copyInto(Object[] anArray) {
target.copyInto(anArray);
}
public synchronized void trimToSize() {
target.trimToSize();
}
public synchronized void ensureCapacity(int minCapacity) {
target.ensureCapacity(minCapacity);
}
public synchronized void setSize(int newSize) {
target.setSize(newSize);
}
public synchronized int capacity() {
return target.capacity();
}
public synchronized int size() {
return target.size();
}
public synchronized boolean isEmpty() {
return target.isEmpty();
}
public Enumeration elements() {
return target.elements();
}
public boolean contains(Object elem) {
return target.contains(elem);
}
public int indexOf(Object elem) {
return target.indexOf(elem);
}
public synchronized int indexOf(Object elem, int index) {
return target.indexOf(elem, index);
}
public synchronized int lastIndexOf(Object elem) {
return target.lastIndexOf(elem);
}
public synchronized int lastIndexOf(Object elem, int index) {
return target.lastIndexOf(elem, index);
}
public synchronized Object elementAt(int index) {
return target.elementAt(index);
}
public synchronized Object firstElement() {
return target.firstElement();
}
public synchronized Object lastElement() {
return target.lastElement();
}
public synchronized void setElementAt(Object obj, int index) {
target.setElementAt(obj, index);
}
public synchronized void removeElementAt(int index) {
target.removeElementAt(index);
}
public synchronized void insertElementAt(Object obj, int index) {
target.insertElementAt(obj, index);
}
public synchronized void addElement(Object obj) {
target.addElement(obj);
}
public synchronized boolean removeElement(Object obj) {
return target.removeElement(obj);
}
public synchronized void removeAllElements() {
target.removeAllElements();
}
public synchronized Object clone() {
return target.clone();
}
public synchronized Object[] toArray() {
return target.toArray();
}
public synchronized Object[] toArray(Object[] a) {
return target.toArray(a);
}
public synchronized Object get(int index) {
return target.get(index);
}
public synchronized Object set(int index, Object element) {
return target.set(index, element);
}
public synchronized boolean add(Object o) {
return target.add(o);
}
public boolean remove(Object o) {
return target.remove(o);
}
public void add(int index, Object element) {
target.add(index, element);
}
public synchronized Object remove(int index) {
return target.remove(index);
}
public void clear() {
target.clear();
}
public synchronized boolean containsAll(Collection c) {
return target.containsAll(c);
}
public synchronized boolean addAll(Collection c) {
return target.addAll(c);
}
public synchronized boolean removeAll(Collection c) {
return target.removeAll(c);
}
public synchronized boolean retainAll(Collection c) {
return target.retainAll(c);
}
public synchronized boolean addAll(int index, Collection c) {
return target.addAll(index, c);
}
public synchronized boolean equals(Object o) {
return target.equals(o);
}
public synchronized int hashCode() {
return target.hashCode();
}
public synchronized String toString() {
return target.toString();
}
public synchronized List subList(int fromIndex, int toIndex) {
return target.subList(fromIndex, toIndex);
}
public Iterator iterator() {
return target.iterator();
}
public ListIterator listIterator() {
return target.listIterator();
}
public ListIterator listIterator(int index) {
return target.listIterator(index);
}
/**
* @return
*/
public DataSourceCollection getTargetCollection() {
return target;
}
}