#ifndef PROBLEM_HH
#define PROBLEM_HH

#include "glob.hh"
#include "plist.hh"
#include "varray.hh"
#include "vector.hh"
#include "interval.hh"

/// helper struct for #Spacing_problem#
struct Colinfo {
    PCol const *pcol_;
    Real const * fixpos;
    Interval width;
    
    /* *************** */
    Colinfo();
    void operator=(Colinfo const&);
    Colinfo(Colinfo const&);
    ~Colinfo();
    Colinfo(PCol const *,Real const *);
    void print() const;
    bool fixed() const { return fixpos;}
    Real fixed_position()const { return *fixpos; }
    Real minright() const { return width.right; }
    Real minleft() const { return -width.left; }
};


/** the problem, given by the columns (which include constraints) and
    intercolumn spacing. The problem is:

    Generate a spacing which
    \begin{itemize}
    \item
    Satisfies spacing constraints (notes can't be printed through each other)
    \item
    Looks good, ie tries to conform to  an ideal spacing as much as possible.
    \end{itemize}
    This is converted by regarding idealspacing as "springs" attached
    to columns. The equilibrium of one spring is the ideal
    distance. The columns have a size, this imposes "hard" constraints
    on the distances. This transforms the problem into a quadratic
    programming problem with linear constraints.

    The quality is given by the total potential energy in the
    springs. The lower the energy, the better the configuration.
*/
class Spacing_problem {
    Array<Idealspacing const *> ideals;
    Array<Colinfo> cols;

    /// the index of #c# in #cols#
    int col_id(PCol const *c) const;

    /// generate an (nonoptimal) solution
    Vector find_initial_solution() const;

    /// check if problem is too tight
    bool check_feasible() const;

    /// does #this# contain the column #w#? 
    bool contains(PCol const *w);

    /// make the energy function
    void make_matrices(Matrix &quad, Vector &lin,Real&) const;

    /// generate the LP constraints
    void make_constraints(Mixed_qp& lp) const;

public:
    /** solve the spacing problem
      
      @return the column positions, and the energy (last element)

      */
    Array<Real> solve() const;

    
    /**
       add a idealspacing to the problem.
      
    One pair of columns can have no, one or more idealspacings,
    since they can be "summed" if the columns to which #i# refers are
    not in this problem, the spacing is ignored.
    */
    void add_ideal(Idealspacing const *i);
    
    
    /** add a col to the problem. columns have to be added left to right. The column contains
      info on it's minimum width.
    */
    void add_column(PCol const *, bool fixed=false, Real fixpos=0.0);
 


    bool check_constraints(Vector v) const;

    Vector try_initial_solution() const;
    void OK() const;
    void print() const;
    void print_ideal(Idealspacing const *)const;
};


#endif
