#ifndef SEARCH_H
#define SEARCH_H

#include "halton.h"
#include "pointset.h"
#include <string>
#include <vector>
#include <utility> // pair

class search {
  public:
    search(int npoints, int dim, int *p);

    // return best discrepancy, write result in file filename
    double run(int iterations);
    virtual void _run(int iterations) = 0;

  protected:
    void compute(); // compute points set
    void check(); // compute discrepancy, fill current, if current < best write solution in filename

    const int dim, npoints;
    double current, best;
    std::string filename;
    halton ha;
    pointset ps;
};

class random_search: public search {
  public:
    random_search(int dim, int npoints, int *p);
    virtual void _run(int iterations);
};

class local_search: public search {
  public:
    local_search(int dim, int npoints, int *p);
    virtual void _run(int iteartions);
    virtual bool accept(double previous, double current) = 0; // return true if we must accept this solution
  protected:
    void init(); // random initial configuration
    void random_neighbour();
    virtual void _random_neighbour();
    void undo(); // (no history : only one modification is remembered)
    virtual void _undo();
  private:
    double previous;
    // for undo :
    bool undoable;
    int i, t1, t2;
};

class random_local_search: public local_search {
  public:
    random_local_search(int dim, int npoints, int *p);
    virtual bool accept(double previous, double current);
};

// simulated annealing
class sa_local_search: public local_search {
  public:
    sa_local_search(int dim, int npoints, int *p, double lambda, double temp);
    virtual bool accept(double previous, double current);
  protected:
    const double lambda;
    double temp;
};

// mu+lambda genetic algorithm
// c : proba of making a crossover
class genetic_search: public search {
  public:
    genetic_search(int dim, int npoints, int *p, int mu, int lamda, double c);
    virtual void _run(int iteartions);
  protected:
    const int mu, lambda;
    const double c;
    std::vector<std::pair<double, std::vector<permutation>>> genes; // discrepancy / permutations
};

#endif // SEARCH_H
