/* $Id$ */
// Copyright (C) 2005, International Business Machines
// Corporation and others.  All Rights Reserved.
// This code is licensed under the terms of the Eclipse Public License (EPL).

#ifndef CoinModelUseful_H
#define CoinModelUseful_H

#include <cstdlib>
#include <cmath>
#include <cassert>
#include <cfloat>
#include <cstring>
#include <cstdio>
#include <iostream>

#include "CoinTypes.hpp"
#include "CoinPragma.hpp"

/**
   This is for various structures/classes needed by CoinModel.

   CoinModelLink
   CoinModelLinkedList
   CoinModelHash
*/
/// for going through row or column

class CoinModelLink {

public:
  /**@name Constructors, destructor */
  //@{
  /** Default constructor. */
  CoinModelLink();
  /** Destructor */
  ~CoinModelLink();
  //@}

  /**@name Copy method */
  //@{
  /** The copy constructor. */
  CoinModelLink(const CoinModelLink &);
  /// =
  CoinModelLink &operator=(const CoinModelLink &);
  //@}

  /**@name Sets and gets method */
  //@{
  /// Get row
  inline int row() const
  {
    return row_;
  }
  /// Get column
  inline int column() const
  {
    return column_;
  }
  /// Get value
  inline double value() const
  {
    return value_;
  }
  /// Get value
  inline double element() const
  {
    return value_;
  }
  /// Get position
  inline CoinBigIndex position() const
  {
    return position_;
  }
  /// Get onRow
  inline bool onRow() const
  {
    return onRow_;
  }
  /// Set row
  inline void setRow(int row)
  {
    row_ = row;
  }
  /// Set column
  inline void setColumn(int column)
  {
    column_ = column;
  }
  /// Set value
  inline void setValue(double value)
  {
    value_ = value;
  }
  /// Set value
  inline void setElement(double value)
  {
    value_ = value;
  }
  /// Set position
  inline void setPosition(CoinBigIndex position)
  {
    position_ = position;
  }
  /// Set onRow
  inline void setOnRow(bool onRow)
  {
    onRow_ = onRow;
  }
  //@}

private:
  /**@name Data members */
  //@{
  /// Row
  int row_;
  /// Column
  int column_;
  /// Value as double
  double value_;
  /// Position in data
  CoinBigIndex position_;
  /// If on row chain
  bool onRow_;
  //@}
};

/// for linked lists
// for specifying triple
typedef struct {
  // top bit is nonzero if string
  // rest is row
  unsigned int row;
  //CoinModelRowIndex row;
  int column;
  double value; // If string then index into strings
} CoinModelTriple;
inline int rowInTriple(const CoinModelTriple &triple)
{
  return triple.row & 0x7fffffff;
}
inline void setRowInTriple(CoinModelTriple &triple, int iRow)
{
  triple.row = iRow | (triple.row & 0x80000000);
}
inline bool stringInTriple(const CoinModelTriple &triple)
{
  return (triple.row & 0x80000000) != 0;
}
inline void setStringInTriple(CoinModelTriple &triple, bool string)
{
  triple.row = (string ? 0x80000000 : 0) | (triple.row & 0x7fffffff);
}
inline void setRowAndStringInTriple(CoinModelTriple &triple,
  int iRow, bool string)
{
  triple.row = (string ? 0x80000000 : 0) | iRow;
}
/// for names and hashing
// for hashing
typedef struct {
  int index, next;
} CoinModelHashLink;
typedef struct {
  CoinBigIndex index, next;
} CoinModelHashLink2;

/* Function type.  */
typedef double (*func_t)(double);

/// For string evaluation
/* Data type for links in the chain of symbols.  */
struct symrec {
  char *name; /* name of symbol */
  int type; /* type of symbol: either VAR or FNCT */
  union {
    double var; /* value of a VAR */
    func_t fnctptr; /* value of a FNCT */
  } value;
  struct symrec *next; /* link field */
};

typedef struct symrec symrec;

class CoinYacc {
private:
  CoinYacc(const CoinYacc &rhs);
  CoinYacc &operator=(const CoinYacc &rhs);

public:
  CoinYacc()
    : symtable(NULL)
    , symbuf(NULL)
    , length(0)
    , unsetValue(0)
  {
  }
  ~CoinYacc()
  {
    if (length) {
      free(symbuf);
      symbuf = NULL;
    }
    symrec *s = symtable;
    while (s) {
      free(s->name);
      symtable = s;
      s = s->next;
      free(symtable);
    }
  }

public:
  symrec *symtable;
  char *symbuf;
  int length;
  double unsetValue;
};

class CoinModelHash {

public:
  /**@name Constructors, destructor */
  //@{
  /** Default constructor. */
  CoinModelHash();
  /** Destructor */
  ~CoinModelHash();
  //@}

  /**@name Copy method */
  //@{
  /** The copy constructor. */
  CoinModelHash(const CoinModelHash &);
  /// =
  CoinModelHash &operator=(const CoinModelHash &);
  //@}

  /**@name sizing (just increases) */
  //@{
  /// Resize hash (also re-hashs)
  void resize(int maxItems, bool forceReHash = false);
  /// Number of items i.e. rows if just row names
  inline int numberItems() const
  {
    return numberItems_;
  }
  /// Set number of items
  void setNumberItems(int number);
  /// Maximum number of items
  inline int maximumItems() const
  {
    return maximumItems_;
  }
  /// Names
  inline const char *const *names() const
  {
    return names_;
  }
  //@}

  /**@name hashing */
  //@{
  /// Returns index or -1
  int hash(const char *name) const;
  /// Adds to hash
  void addHash(int index, const char *name);
  /// Deletes from hash
  void deleteHash(int index);
  /// Returns name at position (or NULL)
  const char *name(int which) const;
  /// Returns non const name at position (or NULL)
  char *getName(int which) const;
  /// Sets name at position (does not create)
  void setName(int which, char *name);
  /// Validates
  void validateHash() const;

private:
  /// Returns a hash value
  int hashValue(const char *name) const;

public:
  //@}
private:
  /**@name Data members */
  //@{
  /// Names
  char **names_;
  /// hash
  CoinModelHashLink *hash_;
  /// Number of items
  int numberItems_;
  /// Maximum number of items
  int maximumItems_;
  /// Last slot looked at
  int lastSlot_;
  //@}
};
/// For int,int hashing
class CoinModelHash2 {

public:
  /**@name Constructors, destructor */
  //@{
  /** Default constructor. */
  CoinModelHash2();
  /** Destructor */
  ~CoinModelHash2();
  //@}

  /**@name Copy method */
  //@{
  /** The copy constructor. */
  CoinModelHash2(const CoinModelHash2 &);
  /// =
  CoinModelHash2 &operator=(const CoinModelHash2 &);
  //@}

  /**@name sizing (just increases) */
  //@{
  /// Resize hash (also re-hashs)
  void resize(CoinBigIndex maxItems, const CoinModelTriple *triples, bool forceReHash = false);
  /// Number of items
  inline CoinBigIndex numberItems() const
  {
    return numberItems_;
  }
  /// Set number of items
  void setNumberItems(CoinBigIndex number);
  /// Maximum number of items
  inline CoinBigIndex maximumItems() const
  {
    return maximumItems_;
  }
  //@}

  /**@name hashing */
  //@{
  /// Returns index or -1
  CoinBigIndex hash(int row, int column, const CoinModelTriple *triples) const;
  /// Adds to hash
  void addHash(CoinBigIndex index, int row, int column, const CoinModelTriple *triples);
  /// Deletes from hash
  void deleteHash(CoinBigIndex index, int row, int column);

private:
  /// Returns a hash value
  CoinBigIndex hashValue(int row, int column) const;

public:
  //@}
private:
  /**@name Data members */
  //@{
  /// hash
  CoinModelHashLink2 *hash_;
  /// Number of items
  CoinBigIndex numberItems_;
  /// Maximum number of items
  CoinBigIndex maximumItems_;
  /// Last slot looked at
  CoinBigIndex lastSlot_;
  //@}
};
class CoinModelLinkedList {

public:
  /**@name Constructors, destructor */
  //@{
  /** Default constructor. */
  CoinModelLinkedList();
  /** Destructor */
  ~CoinModelLinkedList();
  //@}

  /**@name Copy method */
  //@{
  /** The copy constructor. */
  CoinModelLinkedList(const CoinModelLinkedList &);
  /// =
  CoinModelLinkedList &operator=(const CoinModelLinkedList &);
  //@}

  /**@name sizing (just increases) */
  //@{
  /** Resize list - for row list maxMajor is maximum rows.
  */
  void resize(int maxMajor, CoinBigIndex maxElements);
  /** Create list - for row list maxMajor is maximum rows.
      type 0 row list, 1 column list
  */
  void create(int maxMajor, CoinBigIndex maxElements,
    int numberMajor, int numberMinor,
    int type,
    CoinBigIndex numberElements, const CoinModelTriple *triples);
  /// Number of major items i.e. rows if just row links
  inline int numberMajor() const
  {
    return numberMajor_;
  }
  /// Maximum number of major items i.e. rows if just row links
  inline int maximumMajor() const
  {
    return maximumMajor_;
  }
  /// Number of elements
  inline CoinBigIndex numberElements() const
  {
    return numberElements_;
  }
  /// Maximum number of elements
  inline CoinBigIndex maximumElements() const
  {
    return maximumElements_;
  }
  /// First on free chain
  inline CoinBigIndex firstFree() const
  {
    return first_[maximumMajor_];
  }
  /// Last on free chain
  inline CoinBigIndex lastFree() const
  {
    return last_[maximumMajor_];
  }
  /// First on  chain
  inline CoinBigIndex first(int which) const
  {
    return first_[which];
  }
  /// Last on  chain
  inline CoinBigIndex last(int which) const
  {
    return last_[which];
  }
  /// Next array
  inline const CoinBigIndex *next() const
  {
    return next_;
  }
  /// Previous array
  inline const CoinBigIndex *previous() const
  {
    return previous_;
  }
  //@}

  /**@name does work */
  //@{
  /** Adds to list - easy case i.e. add row to row list
      Returns where chain starts
  */
  CoinBigIndex addEasy(int majorIndex, CoinBigIndex numberOfElements, const int *indices,
    const double *elements, CoinModelTriple *triples,
    CoinModelHash2 &hash);
  /** Adds to list - hard case i.e. add row to column list
  */
  void addHard(int minorIndex, CoinBigIndex numberOfElements, const int *indices,
    const double *elements, CoinModelTriple *triples,
    CoinModelHash2 &hash);
  /** Adds to list - hard case i.e. add row to column list
      This is when elements have been added to other copy
  */
  void addHard(CoinBigIndex first, const CoinModelTriple *triples,
    CoinBigIndex firstFree, CoinBigIndex lastFree, const CoinBigIndex *nextOther);
  /** Deletes from list - same case i.e. delete row from row list
  */
  void deleteSame(int which, CoinModelTriple *triples,
    CoinModelHash2 &hash, bool zapTriples);
  /** Deletes from list - other case i.e. delete row from column list
      This is when elements have been deleted from other copy
  */
  void updateDeleted(int which, CoinModelTriple *triples,
    CoinModelLinkedList &otherList);
  /** Deletes one element from Row list
  */
  void deleteRowOne(CoinBigIndex position, CoinModelTriple *triples,
    CoinModelHash2 &hash);
  /** Update column list for one element when
      one element deleted from row copy
  */
  void updateDeletedOne(CoinBigIndex position, const CoinModelTriple *triples);
  /// Fills first,last with -1
  void fill(int first, int last);
  /** Puts in free list from other list */
  void synchronize(CoinModelLinkedList &other);
  /// Checks that links are consistent
  void validateLinks(const CoinModelTriple *triples) const;
  //@}
private:
  /**@name Data members */
  //@{
  /// Previous - maximumElements long
  CoinBigIndex *previous_;
  /// Next - maximumElements long
  CoinBigIndex *next_;
  /// First - maximumMajor+1 long (last free element chain)
  CoinBigIndex *first_;
  /// Last - maximumMajor+1 long (last free element chain)
  CoinBigIndex *last_;
  /// Number of major items i.e. rows if just row links
  int numberMajor_;
  /// Maximum number of major items i.e. rows if just row links
  int maximumMajor_;
  /// Number of elements
  CoinBigIndex numberElements_;
  /// Maximum number of elements
  CoinBigIndex maximumElements_;
  /// 0 row list, 1 column list
  int type_;
  //@}
};

#endif

/* vi: softtabstop=2 shiftwidth=2 expandtab tabstop=2
*/
