+/* $Id$
+
+This file is part of the MSP Märklin suite
+Copyright © 2010 Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <msp/core/except.h>
+#include "block.h"
+#include "blockiter.h"
+#include "route.h"
+#include "trackiter.h"
+
+using namespace std;
+using namespace Msp;
+
+namespace Marklin {
+
+BlockIter::BlockIter():
+ _block(0),
+ _entry(0)
+{ }
+
+BlockIter::BlockIter(Block *b, unsigned e):
+ _block(b),
+ _entry(b ? e : 0)
+{
+ if(_block && _entry>_block->get_endpoints().size())
+ throw InvalidParameterValue("Endpoint index not valid for block");
+}
+
+TrackIter BlockIter::track_iter() const
+{
+ if(!_block)
+ return TrackIter();
+
+ const Block::Endpoint &ep = _block->get_endpoints()[_entry];
+ return TrackIter(ep.track, ep.track_ep);
+}
+
+int BlockIter::get_exit(const Route *route) const
+{
+ const vector<Block::Endpoint> &eps = _block->get_endpoints();
+ TrackIter t_iter = track_iter();
+
+ while(t_iter)
+ {
+ if(!_block->has_track(*t_iter))
+ throw LogicError("Block traversal strayed out of the block");
+
+ int path = -1;
+ if(t_iter->get_turnout_id() && route)
+ path = route->get_turnout(t_iter->get_turnout_id());
+ if(path==-1)
+ path = t_iter->get_active_path();
+
+ TrackIter t_exit = t_iter.reverse(path);
+
+ for(unsigned i=0; i<eps.size(); ++i)
+ if(eps[i].track==t_exit.track() && eps[i].track_ep==t_exit.entry())
+ return i;
+
+ t_iter = t_iter.next(path);
+ }
+
+ return -1;
+}
+
+BlockIter BlockIter::next(const Route *route) const
+{
+ if(!_block)
+ return BlockIter();
+
+ int exit = get_exit(route);
+ if(exit<0)
+ return BlockIter();
+
+ BlockIter result;
+ result._block = _block->get_link(exit);
+ result._entry = (result._block ? result._block->get_endpoint_by_link(*_block) : 0);
+
+ return result;
+}
+
+BlockIter BlockIter::reverse(const Route *route) const
+{
+ if(!_block)
+ return BlockIter();
+
+ int exit = get_exit(route);
+ if(exit<0)
+ return BlockIter();
+
+ return BlockIter(_block, exit);
+}
+
+BlockIter BlockIter::flip() const
+{
+ if(!_block)
+ return BlockIter();
+
+ BlockIter result;
+ result._block = _block->get_link(_entry);
+ result._entry = (result._block ? result._block->get_endpoint_by_link(*_block) : 0);
+
+ return result;
+}
+
+Block &BlockIter::operator*() const
+{
+ if(!_block)
+ throw InvalidState("BlockIter is null");
+
+ return *_block;
+}
+
+bool BlockIter::operator==(const BlockIter &other) const
+{
+ return _block==other._block && _entry==other._entry;
+}
+
+} // namespace Marklin