+#include <msp/strings/format.h>
+#include "blockiter.h"
+#include "route.h"
+#include "track.h"
+#include "tracktype.h"
+#include "trackoffsetiter.h"
+
+using namespace std;
+using namespace Msp;
+
+namespace R2C2 {
+
+incompatible_path::incompatible_path(unsigned a, unsigned e):
+ logic_error(format("got %d, but %d already set", a, e))
+{ }
+
+
+TrackOffsetIter::TrackOffsetIter():
+ _offset(0),
+ _path(0)
+{ }
+
+TrackOffsetIter::TrackOffsetIter(Track *t, unsigned e, float o):
+ _track(t, e),
+ _offset(_track ? o : 0),
+ _path((_track && _offset) ? _track->get_active_path() : -1)
+{ }
+
+TrackOffsetIter::TrackOffsetIter(Track *t, unsigned e, unsigned p, float o):
+ _track(t, e),
+ _offset(o),
+ _path(p)
+{ }
+
+TrackOffsetIter::TrackOffsetIter(const TrackIter &t, float o):
+ _track(t),
+ _offset(_track ? o : 0),
+ _path((_track && _offset) ? _track->get_active_path() : -1)
+{ }
+
+TrackOffsetIter::TrackOffsetIter(const TrackIter &t, unsigned p, float o):
+ _track(t),
+ _offset(o),
+ _path(p)
+{ }
+
+BlockIter TrackOffsetIter::block_iter() const
+{
+ return _track.block_iter();
+}
+
+TrackPoint TrackOffsetIter::point() const
+{
+ if(!_track)
+ return TrackPoint();
+
+ if(_path>=0)
+ return _track->get_point(_track.entry(), _path, _offset);
+ else
+ return _track->get_point(_track.entry(), _offset);
+}
+
+TrackOffsetIter TrackOffsetIter::next() const
+{
+ if(_path>=0)
+ return _track.next(_path);
+ else
+ return _track.next();
+}
+
+TrackOffsetIter TrackOffsetIter::next(unsigned p) const
+{
+ if(_path>=0 && static_cast<unsigned>(_path)!=p)
+ throw incompatible_path(_path, p);
+
+ return _track.next(p);
+}
+
+TrackOffsetIter TrackOffsetIter::advance(float d, const Route *r) const
+{
+ if(!_track)
+ return TrackOffsetIter();
+
+ if(d<0)
+ return reverse().advance(-d, r).reverse();
+
+ TrackIter t = _track;
+ int p = _path;
+ float o = _offset+d;
+
+ while(t)
+ {
+ if(p<0)
+ {
+ if(r)
+ if(unsigned tid = t->get_turnout_id())
+ p = r->get_turnout(tid);
+ if(p<0)
+ p = t->get_active_path();
+ }
+
+ float length = t->get_type().get_path_length(p);
+ if(o<length)
+ return TrackOffsetIter(t, p, o);
+
+ o -= length;
+ t = t.next(p);
+ p = -1;
+ }
+
+ return TrackOffsetIter();
+}
+
+TrackOffsetIter TrackOffsetIter::reverse() const
+{
+ if(!_track)
+ return TrackOffsetIter();
+
+ int p = (_path>=0 ? _path : _track->get_active_path());
+ TrackIter t = _track.reverse(p);
+ float o = t->get_type().get_path_length(p)-_offset;
+
+ return TrackOffsetIter(t, p, o);
+}
+
+bool TrackOffsetIter::operator==(const TrackOffsetIter &other) const
+{
+ return _track==other._track && _offset==other._offset && _path==other._path;
+}
+
+} // namespaec R2C2