/*********************************************************************
 *  Author  : Tino Weinkauf and Wiebke Koepp
 *  Init    : Tuesday, March 27, 2018 - 16:33:19
 *
 *  Project : KTH Inviwo Modules
 *
 *  License : Follows the Inviwo BSD license model
 *********************************************************************
 */

#pragma once

#include "treeordercomputation.h"
#include <random>

class TemporalTreeSimulatedAnnealing
    : public TemporalTreeOrderOptimization {
public:
    TemporalTreeSimulatedAnnealing();
    virtual ~TemporalTreeSimulatedAnnealing() = default;

public:
    // Swap two nodes in the given vector, assumes there are two
    // nodes in that vector
    void swapNodes(std::vector<size_t>& nodes);

    /// Decay the temperature
    void decayTemperature();

    /// Accept a neighbor state based on current temperature and difference in energy
    bool acceptNeighbor(double deltaEnergy) const;

    /// Neighbor Solution from the current state
    virtual void neighborSolution() = 0;

    /// Initalize everything
    virtual void initializeResources();

    /// Reset only statistic things and settings
    virtual void restart() override;

    /// Is the optimization converged
    bool isConverged() override;

    /// Do a single optimization step
    void singleStep() override;

    /// Prepare the next step (update some optimization structures)
    virtual void prepareNextStep() = 0;

    /// Run until convergence criterion is reached
    void runUntilConvergence() override;

    virtual void setLastToCurrent() = 0;

    virtual void setCurrentToLast() = 0;

    virtual void setBest() = 0;

    virtual void logProperties() override;

    void initializeLog() override;

    void logStep() override;

    /// Our main computation function (does nothing)
    virtual void process() override = 0;

    // Ports
public:
    // Properties
public:

    /// Initial temperature
    double propInitialTemperature;

    /// Minimum temperature at which we stop the optimization
    double propMinimumTemperature;

    /// Temperature decay
    double propTemperatureDecay;

    /// Number of iterations per temperature setting
    int propIterationsPerTemp;

    /// The current temperature
    double propCurrentTemperature;

    // Attributes
public:
    /// We need to access the input tree in a number of places
    std::shared_ptr<const TemporalTree> pInputTree;

    /// Current temperature
    double currentTemperature;

    /// Random distribution for sampling neighbor states
    std::uniform_real_distribution<> uniformReal{0.0, 1.0};

    /// Last state so that we can back
    OptimizationState lastState;

    /// State info: Was the last neighbor accepted
    bool lastAccepted;

    /// State info: What was the last enegery delta
    double lastDeltaEnergy;
};
