+/* $Id$
+
+This file is part of the MSP Märklin suite
+Copyright © 2010 Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include "aicontrol.h"
+#include "catalogue.h"
+#include "layout.h"
+#include "train.h"
+
+using namespace std;
+using namespace Msp;
+
+namespace Marklin {
+
+AIControl::AIControl(Train &t, ControlModel *n):
+ train(t),
+ next_model(n),
+ target_speed(TrainControl::continuous("speed", -1000, 1000)),
+ blocked(false)
+{
+ target_speed.set(0);
+
+ train.signal_arrived.connect(sigc::mem_fun(this, &AIControl::arrived));
+}
+
+AIControl::~AIControl()
+{
+ delete next_model;
+}
+
+void AIControl::set_control(const string &n, float v)
+{
+ if(n=="speed")
+ {
+ if(v && !train.is_active())
+ train.set_active(true);
+
+ target_speed.set(v);
+ if(!blocked)
+ next_model->set_control("speed", target_speed.value);
+ }
+ else
+ next_model->set_control(n, v);
+}
+
+const TrainControl &AIControl::get_control(const string &n) const
+{
+ if(n=="speed")
+ return target_speed;
+ else
+ return next_model->get_control(n);
+}
+
+float AIControl::get_speed() const
+{
+ return next_model->get_speed();
+}
+
+float AIControl::get_braking_distance() const
+{
+ return next_model->get_braking_distance();
+}
+
+void AIControl::tick(const Time::TimeDelta &dt)
+{
+ float rsv_dist = train.get_reserved_distance();
+ float brake_dist = next_model->get_braking_distance()*1.15;
+ float margin = 25*train.get_layout().get_catalogue().get_scale();
+ if(!blocked && rsv_dist<brake_dist+margin)
+ {
+ blocked = true;
+ next_model->set_control("speed", 0);
+ }
+ else if(blocked && rsv_dist>brake_dist+margin*3)
+ {
+ blocked = false;
+ next_model->set_control("speed", target_speed.value);
+ }
+
+ next_model->tick(dt);
+
+ if(!target_speed.value && !next_model->get_speed() && train.is_active())
+ train.set_active(false);
+}
+
+void AIControl::arrived()
+{
+ set_control("speed", 0);
+}
+
+} // namespace Marklin