class SupervisedDriver(Driver):
    def __init__(self,
                 trainee,
                 feature_transformer,
                 persist_path,
                 optimizer_params=None,
                 loss=None):
        super(SupervisedDriver, self).__init__()
        self.supervisor = MyDriver()
        self.feature_transformer = feature_transformer
        self.trainee = trainee
        self.persist_path = persist_path

        if optimizer_params is None:
            optimizer_params = {"lr": 0.001, "momentum": 0.9}

        if loss is None:
            loss = nn.MSELoss()

        # loss
        self.loss = loss

        # optimizer
        self.optimizer = optim.SGD(self.trainee.parameters(),
                                   **optimizer_params)

        self.call_number = 0

    def drive(self, state):
        self.call_number += 1

        command = self.supervisor.drive(state)

        x = self.feature_transformer.transform(state)
        y_predicted = self.trainee(x)
        y_true = Variable(
            torch.FloatTensor(
                [command.steering, command.brake, command.accelerator]))

        self.optimizer.zero_grad()
        loss = self.loss(y_predicted, y_true)
        loss.backward()

        self.optimizer.step()

        if self.call_number % 1000 == 0:
            print("Step: {}".format(self.call_number))
            print("Prediction", y_predicted)
            print("True", y_true)
            print("loss", loss)

            print()

        return command

    def on_shutdown(self):
        torch.save(self.trainee, self.persist_path)

# steeringData = SteeringTrainingData(pandas.read_csv('training-data/train_data/alpine-1.csv'))
# brakingData = BrakingTrainingData(pandas.read_csv('training-data/train_data/alpine-1.csv'))

steeringData = ExtendedSteeringData()

observations = []
driver = MyDriver()

for i in range(len(steeringData)):

    state = dataToStateExtended(steeringData[i][0])
    sample = Trainer.stateToSample(state)

    command = driver.drive(state)
    #
    # observation = {
    #     'target': (brakingData[i][1]).numpy()[0],
    #     'actual': command.brake
    # }

    observation = {
        'target': (steeringData[i][1]).numpy()[0],
        'actual': command.steering
    }

    observations.append(observation)

observations.sort(key=lambda observation: observation['target'])