--- /dev/null
+/* $Id$
+
+This file is part of R²C²
+Copyright © 2010 Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <algorithm>
+#include <msp/core/except.h>
+#include "track.h"
+#include "trackiter.h"
+#include "tracktype.h"
+
+using namespace std;
+using namespace Msp;
+
+namespace R2C2 {
+
+TrackIter::TrackIter():
+ _track(0),
+ _entry(0)
+{ }
+
+TrackIter::TrackIter(Track *t, unsigned e):
+ _track(t),
+ _entry(t ? e : 0)
+{
+ if(_track && _entry>_track->get_type().get_endpoints().size())
+ throw InvalidParameterValue("Endpoint index not valid for track");
+}
+
+const TrackType::Endpoint &TrackIter::endpoint() const
+{
+ if(!_track)
+ throw InvalidState("TrackIter is null");
+
+ return _track->get_type().get_endpoint(_entry);
+}
+
+int TrackIter::get_exit(unsigned path) const
+{
+ const vector<TrackType::Endpoint> &eps = _track->get_type().get_endpoints();
+
+ // Find an endpoint that's connected to the entry and has the requested path
+ for(unsigned i=0; i<eps.size(); ++i)
+ if(i!=_entry && (eps[i].paths&(1<<path)) && (eps[i].paths&eps[_entry].paths))
+ return i;
+
+ return -1;
+}
+
+TrackIter TrackIter::next() const
+{
+ if(!_track)
+ return TrackIter();
+
+ return next(_track->get_active_path());
+}
+
+TrackIter TrackIter::next(unsigned path) const
+{
+ if(!_track)
+ return TrackIter();
+
+ int exit = get_exit(path);
+ if(exit<0)
+ return TrackIter();
+
+ TrackIter result;
+ result._track = _track->get_link(exit);
+ result._entry = (result._track ? result._track->get_endpoint_by_link(*_track) : 0);
+
+ return result;
+}
+
+TrackIter TrackIter::reverse() const
+{
+ if(!_track)
+ return TrackIter();
+
+ return reverse(_track->get_active_path());
+}
+
+TrackIter TrackIter::reverse(unsigned path) const
+{
+ if(!_track)
+ return TrackIter();
+
+ int exit = get_exit(path);
+ if(exit<0)
+ return TrackIter();
+
+ return TrackIter(_track, exit);
+}
+
+TrackIter TrackIter::flip() const
+{
+ if(!_track)
+ return TrackIter();
+
+ TrackIter result;
+ result._track = _track->get_link(_entry);
+ result._entry = (result._track ? result._track->get_endpoint_by_link(*_track) : 0);
+
+ return result;
+}
+
+Track &TrackIter::operator*() const
+{
+ if(!_track)
+ throw InvalidState("TrackIter is null");
+
+ return *_track;
+}
+
+bool TrackIter::operator==(const TrackIter &other) const
+{
+ return _track==other._track && _entry==other._entry;
+}
+
+
+TrackLoopIter::TrackLoopIter():
+ _looped(false)
+{ }
+
+TrackLoopIter::TrackLoopIter(Track *t, unsigned e):
+ TrackIter(t, e),
+ _visited(new TrackList()),
+ _last(_visited->insert(_visited->end(), track())),
+ _looped(false)
+{ }
+
+TrackLoopIter::TrackLoopIter(const TrackIter &i):
+ TrackIter(i),
+ _visited(new TrackList()),
+ _last(_visited->insert(_visited->end(), track())),
+ _looped(false)
+{ }
+
+TrackLoopIter::TrackLoopIter(const TrackIter &i, RefPtr<TrackList> v, const TrackList::iterator &l):
+ TrackIter(i),
+ _looped(false)
+{
+ if(track())
+ {
+ _visited = v;
+ _last = l;
+ _looped = (_visited && find(_visited->begin(), _last, track())!=_last);
+
+ ++_last;
+ if(_last!=_visited->end())
+ {
+ _visited = new TrackList(_visited->begin(), _last);
+ _last = _visited->end();
+ }
+ _visited->push_back(track());
+ --_last;
+ }
+}
+
+TrackLoopIter TrackLoopIter::next() const
+{
+ return TrackLoopIter(TrackIter::next(), _visited, _last);
+}
+
+TrackLoopIter TrackLoopIter::next(unsigned path) const
+{
+ return TrackLoopIter(TrackIter::next(path), _visited, _last);
+}
+
+} // namespace R2C2