/**
 * @file DagStructure.hpp
 *
 * Created on 2010/05/25 by Anthony Nemoff
 * Last update 2010/05/28 by Anthony Nemoff
 *
 */

#include "DagStructure.hpp"

//==============================================================================
// Constructors & destructors

/**
 * Default constructor : does nothing
 */
DagStructure::DagStructure() {
  // Empty
}

/**
 * Constructor
 *
 * @param graphName Name of the graph
 * @param numberOfNodes Number of nodes in the graph
 * @param numberOfEdges Number of edges in the graph
 * @param gvContext The Graphviz context
 */
DagStructure::DagStructure(QString graphName, int numberOfNodes, int numberOfEdges, GVC_t *gvContext) :
    _graphName(graphName),
    _numberOfNodes(numberOfNodes),
    _numberOfEdges(numberOfEdges),
    _length(0),
    _layoutDone(false)
{

  _graphvizContext = gvContext;

  // Graph creation
  _graph = _agopen(graphName, AGDIGRAPHSTRICT);

  // Set graph attributes and default attribute values
  _agset(_graph, "fontname", DDV_GVFONT);
  _agset(_graph, "fontsize", "10");
  _agset(_graph, "splines", "true");

}


/**
 * Destructor
 */
DagStructure::~DagStructure() {
  // Empty
}


//==============================================================================
// Getters & setters

QString DagStructure::getGraphName() const {
  return _graphName;
}

void DagStructure::setGraphName(QString _name) {
  _graphName = _name;
}

int DagStructure::getNumberOfNodes() const {
  return _numberOfNodes;
}

void DagStructure::setNumberOfNodes(int _nodes) {
  _numberOfNodes = _nodes;
}

int DagStructure::getNumberOfEdges() const {
  return _numberOfEdges;
}

void DagStructure::setNumberOfEdges(int _edges) {
  _numberOfEdges = _edges;
}

void DagStructure::setLength(int length) {
  _length = length;
}

int DagStructure::getLength() const {
  return _length;
}

Agraph_t* DagStructure::getGraph() {
  return _graph;
}

Agnode_t* DagStructure::getGVNodeAt(int i) {
  return _nodeList[i];
}

Agedge_t* DagStructure::getGVEdgeAt(int i) {
  return _edgeList[i];
}


//==============================================================================
// Methods

/**
 * Creates the node and adds it to the nodes list.
 */
void DagStructure::addNode(int nodeIndex, QString nodeName) {

  // QString -> char * conversion
  QByteArray ba = nodeName.toLatin1();
  char* c_str = ba.data();

  // Create the node
  Agnode_t *node = agnode(_graph, c_str);
  _nodeList.append(node);

  // TODO
  // Set attributes and default values
  // Parameters : component, attr_name, attr_value, default_value
  _agset(node, "shape", "rectangle"); // node shape
  _agset(node, "color", "black"); // node shape border color
  _agset(node, "fontname", DDV_GVFONT); // font family
  _agset(node, "fontsize", "10"); // point size of label
  //_agset(node, "height", "0.3"); // node height

}


/**
 * Adds an edge between 2 nodes to the graph and stores a pointer to the edge in
 * the edge list.
 *
 * @param startNodeIndex Start node index
 * @param endNodeIndex End node index
 */
void DagStructure::addEdge(int startNodeIndex, int endNodeIndex, int edgeIndex) {

  Agnode_t *startNode = _nodeList[startNodeIndex];
  Agnode_t *endNode = _nodeList[endNodeIndex];

  Agedge_t *edge = agedge(_graph, startNode, endNode);
  _edgeList.append(edge);
  // TODO add edge value

}

/**
 * Layouts the current graph using the given Graphviz layout engine :
 * - dot : hierarchical layout
 * - nop (neato -n) : "symetrics" layouts
 * - nop2 (neato -n2) :  "symetrics" layouts
 * - twopi : radial layout (Wills)
 * - circo : circular layout
 *
 * @param _layoutEngineName The layout engine name as described in the Graphviz library guide
 */
void DagStructure::calculateLayout(QString layoutEngineName) {

  // TODO store current layout ? layout again if layout is different from current layout

  if (!_layoutDone) {

    // QString -> char * conversion
    QByteArray ba = layoutEngineName.toLatin1();
    char* c_str = ba.data();

    gvLayout(_graphvizContext, _graph, c_str);

    // TODO fix code
    // extra render with NULL pointer to calculate positions
    gvRender(_graphvizContext, _graph, "xdot", NULL);
//    if (_layoutEngineName == "dot")
//      gvRender(graphvizContext, graph, "xdot", NULL);
//    else
//      gvRender(graphvizContext, graph, c_str, NULL);

    _layoutDone = true;

  }

}

/**
 * Destroys all layout information and frees associated ressources.
 */
void DagStructure::freeGraphLayout() {

  gvFreeLayout(_graphvizContext, _graph);

}


/**
 * Renders the graph using the curring layout to a file using the given format
 * and the given file name.
 *
 * @param _format File format : ps, jpg, png, dot, plain ...
 * @param _fileName Name of the file to which the graph will be written
 * @see Graphviz library guide http://www.graphviz.org/pdf/libguide.pdf
 */
void DagStructure::renderTofile(QString fileFormat, QString fileName) {

  // QString -> char * conversion
  QByteArray ba1 = fileFormat.toLatin1();
  char* c_str1 = ba1.data();
  QByteArray ba2 = fileName.toLatin1();
  char* c_str2 = ba2.data();

  gvRenderFilename(_graphvizContext, _graph, c_str1, c_str2);

}

