/**
 * @file DigDagData.hpp
 *
 * Created on 2010/05/18 by Anthony Nemoff
 * Last update 2010/07/20 by Anthony Nemoff
 *
 */

#ifndef DIGDAGDATA_HPP
#define DIGDAGDATA_HPP

#include "../Common.hpp"
#include "DagPattern.hpp"
#include "InputDag.hpp"

#include <QFile>
#include <QFileInfo>
#include <QMap>
#include <QMultiMap>

/**
 * This class represents the contents of a DigDagFile :
 * - file header information
 * - pattern DAGs list
 * - input DAGs list
 * - etc.
 *
 * Its main purpose is to load and parse a DigDagFile, and to give acces to
 * the information.
 * Data is not loaded all at once because of the possible huge size of results.
 * The DigDagData provides methods to load patterns on demand.
 */
class DigDagData {

public:

  //////////////////////////////////////////////////////////////////////////////
  // CONSTRUCTORS & DESTRUCTOR

  /**
   * Default constructor.
   */
  DigDagData();

  /**
   * Destructor
   */
  ~DigDagData();


  //////////////////////////////////////////////////////////////////////////////
  // GETTERS & SETTERS

  /**
   * Returns the file name
   *
   * @return The file name
   */
  inline QString getFileName() const {
    return QFileInfo(_file).fileName();
  }

  /**
   * Returns the absolute file path with file name.
   *
   * @return The absolute file path with file name.
   */
  inline QString getAbsoluteFilePath() const {
    return QFileInfo(_file).absoluteFilePath();
  }

  /**
   * Returns the command line string.
   *
   * @return The command line string
   */
  inline QString getCommandLine() const {
    return _commandLine;
  }

  /**
   * Returns the input folder name which contains all the input DAGs that were readed with DigDag.
   *
   * @return The input folder name
   */
  inline QString getInputFolder() const {
    return _inputFolder;
  }

  inline int getNumberOfInputDags() const {
    return _numberOfInputDags;
  }

  inline int getMinSupport() const {
    return _minSupport;
  }

  inline int getEPThreshold() const {
    return _edgePruningThreshold;
  }

  // TODO remove inline -> create normal functions
  /**
   * Returns
   *
   * @return
   */
  inline int getNumberOfDagPatterns() const {
    return _numberOfDagPatterns;
  }

  inline int getMinDagSupport() const {
    return _minDagSupport;
  }

  inline int getMaxDagSupport() const {
    return _maxDagSupport;
  }

  inline int getMinDagSize() const {
    return _minDagSize;
  }

  inline int getMaxDagSize() const {
    return _maxDagSize;
  }

  inline int getMinDagLength() const {
    return _minDagLength;
  }

  inline int getMaxDagLength() const {
    return _maxDagLength;
  }

  /**
   * Returns
   *
   * @param index Index of the input file in the map
   * @return The file name at the given index
   */
  inline QString getInputFileNameAt(int index) const {
    return _inputDagsMap[index];
  }

  inline QMap<int, QString>* getInputDagsMap() {
    return &_inputDagsMap;
  }

  QList<DagPattern*>* getPatternsList();

  QList<InputDag*>* getInputDagsList();


  // Methods

  /**
   * Opens the given file.
   *
   * @param fileName The file name
   */
  int openFile(QString fileName);

  /**
   * Reads and parses the input data file.
   * Loads the header information, the input dags list, loads partially the
   * patterns (TID-List is not loaded).
   *
   * @return Sucess code
   */
  int readFile();

  void closeFile();

  void createGraphvizContext();

  /**
   * Frees Graphviz context and closes output files.
   *
   * @return Number of errors
   */
  int freeGraphvizContext();

  bool loadInputDag(int index);

  /**
   * Loads completely a DAG pattern : the full DAG structure and the TID list.
   * Data is then used to build the Graphviz graph structures.
   */
  void loadDagPattern(int patternNumber);

  void layoutDagStructure(DagStructure *dagStructure, QString layoutAlgorithm);

  // XXX const char* is better!
  void renderToFileDagPattern(int patternNumber, QString format, QString fileName);


private:

  //////////////////////////////////////////////////////////////////////////////
  // METHODS

  QString readLine();

  QString extractValue(QString line);

  bool findSection(QString sectionName);

  void parseHeader();

  void parseInputDags();

  void initInputDag(int index, QString dafFileName);

  void parseInputDagStructure(int index);

  void parsePatterns();

  void initDagPattern(int index);

  void parseDagPatternStructure(int index);

  void parseDagPatternTidList(DagPattern *pattern);

  // TODO parseNodesIndex


  //////////////////////////////////////////////////////////////////////////////
  // VARIABLES

  // --- File information
  QFile _file; /**< The input file containing the DigDag results */
  QString _currentFileVersion; /**< Current file format version */ // XXX useless member ?
  QString _commandLine; /**< DigDag command lined used to obtain the result file */
  QString _inputFolder; /**< Folder containing the input DAGs where mining was done */
  int _numberOfInputDags; /**< Number of input DAGs */
  QString _outputPrefix; /**< Output prefix of the current data file */
  int _minSupport; /**< Frequency threshold (minimum support) */
  int _edgePruningThreshold; /**< Edge pruning threshold */
  int _numberOfDagPatterns; /**< Number of DAG patterns contained */
  int _minDagSupport; /**< Minimum DAG support value found */
  int _maxDagSupport; /**< Maximum DAG support value found */
  int _minDagSize; /**< Minimum DAG size value found */
  int _maxDagSize; /**< Maximum DAG size value found */
  int _minDagLength; /**< Minimum DAG length value found */
  int _maxDagLength; /**< Maximum DAG length value found */

  // --- Data storage
  QMap<int, QString> _inputDagsMap; /**< Stores <index, filename> pairs for each input DAG file in the input folder */
  QList<DagPattern*> _patternsList; /**< List of DAG patterns */
  QList<InputDag*> _inputDagsList; /**< List of input DAGs */

  // TODO create nodes index
  //QMultiMap<QString, DagInput* > _nodesMultiMap;

  // --- Graphviz data
  GVC_t *_graphvizContext;

  // --- Parsing variables
  qint64 _filePosition; /**< Current position while reading the file */
  QString _currentLine; /**< Current line content read in the file */

  // String markers identifying the diferent file sections
  // TODO All these variables are meant to be constant, but due to initialisation problem, removing "const" is a temporary fix
  QString PARSER_VERSION;
  QString FILE_VERSION_SECTION;
  QString HEADER_SECTION_START;
  QString HEADER_SECTION_END; // XXX useless
  QString INDEX_SECTION_START;
  QString INDEX_SECTION_END; // XXX useless
  QString PATTERNS_LIST_SECTION_START;
  QString PATTERNS_LIST_SECTION_END; // XXX useless
  QString PATTERN_SECTION_START;
  QString PATTERN_SECTION_END; // XXX useless
  QString DAG_SECTION_START;
  QString DAG_SECTION_END; // XXX useless
  QString TID_LIST_SECTION_START;
  QString TID_LIST_SECTION_END; // XXX useless

};

#endif // DIGDAGDATA_HPP

