package Locomotive;
use strict;
use overload
    '""' => \&id,
    '0+' => \&id;
1;

sub new {
    my $class = shift;
    my($interface, $id) = @_;
    my $self = {
        interface => $interface,
        id => $id,
        speed => 0,
        direction => 0,
        f0 => 0,
        f1 => 0,
        f2 => 0,
        f3 => 0,
        f4 => 0,
    };
    bless $self, $class;
    $self->updateEngine();
    $self->updateFunctions();
    return $self;
}

sub id {
    my $self = shift;
    return $self->{id};
}

sub updateEngine {
    my $self = shift;
    $self->{interface}->engine($self->{id}, $self->{speed}, $self->{f0});
}

sub updateFunctions {
    my $self = shift;
    $self->{interface}->functions($self->{id}, $self->{f1}, $self->{f2}, $self->{f3}, $self->{f4});
}

sub invert {
    my $self = shift;
    $self->{direction} = not $self->{direction};
    $self->{speed} = 0;
    if ($self->{track}) {
        $self->{link} = $self->{track}->invert($self->{link});
    }
    $self->{interface}->invert($self->{id}, $self->{f0});
    return $self->{direction};
}

sub direction {
    my $self = shift;
    if (@_) {
        my $direction = $_[0] ? 1 : 0;
        if ($direction != $self->{direction}) {
            $self->invert();
        } else {
            # we have to be consistent, so
            # this function always stops the train
            $self->speed(0);
        }
    }
    return $self->{direction};
}

sub speed {
    my $self = shift;
    if (@_) {
        my $speed = $_[0];
        $speed = 0 if $speed < 0;
        $speed = 14 if $speed > 14;
        $self->{speed} = $speed;
        $self->updateEngine();
    }
    return $self->{speed};
}

sub stop {
    my $self = shift;
    return $self->speed(0);
}

sub f0 {
    my $self = shift;
    if (@_) {
        $self->{f0} = $_[0] ? 1 : 0;
        $self->updateEngine();
    }
    return $self->{f0};
}

sub f1 {
    my $self = shift;
    if (@_) {
        $self->{f1} = $_[0] ? 1 : 0;
        $self->updateFunctions();
    }
    return $self->{f1};
}

sub f2 {
    my $self = shift;
    if (@_) {
        $self->{f2} = $_[0] ? 1 : 0;
        $self->updateFunctions();
    }
    return $self->{f2};
}

sub f3 {
    my $self = shift;
    if (@_) {
        $self->{f3} = $_[0] ? 1 : 0;
        $self->updateFunctions();
    }
    return $self->{f3};
}

sub f4 {
    my $self = shift;
    if (@_) {
        $self->{f4} = $_[0] ? 1 : 0;
        $self->updateFunctions();
    }
    return $self->{f4};
}

sub functions {
    my $self = shift;
    if ($self->{f0} != ($_[0] ? 1 : 0)) {
        $self->{f0} = $_[0] ? 1 : 0;
        $self->updateEngine();
    }
    $self->{f1} = $_[1] ? 1 : 0;
    $self->{f2} = $_[2] ? 1 : 0;
    $self->{f3} = $_[3] ? 1 : 0;
    $self->{f4} = $_[4] ? 1 : 0;
    $self->updateFunctions();
}
