// We include what we need for the test
#include <gatb/gatb_core.hpp>

#include <queue>
#include <stack>
#include <map>
using namespace std;

#define DEBUG(a)  //a
#define INFO(a)   //a

/********************************************************************************/

const char* STR_NODE_TYPE = "-type";

/********************************************************************************/
class CustomTool : public Tool
{
public:

    // Constructor
    CustomTool () : Tool ("DotGenerator")
    {
        getParser()->push_front (new OptionOneParam (STR_URI_INPUT,  "graph file", true ));
        getParser()->push_front (new OptionOneParam (STR_URI_OUTPUT, "dot file",  false ));
        getParser()->push_front (new OptionOneParam (STR_NODE_TYPE,  "node type (0: all,  1:branching)", false, "1" ));
    }

    template<typename NodeType>
    void process (const char* name)
    {
        string outputFile = getInput()->get(STR_URI_OUTPUT) ?
            getInput()->getStr(STR_URI_OUTPUT) :
            (System::file().getBaseName(getInput()->getStr(STR_URI_INPUT)) + ".dot");

        FILE* output = fopen (outputFile.c_str(), "w");
        if (output != NULL)
        {
            fprintf (output, "digraph %s  {\n", name);

            // We load the graph
            Graph graph = Graph::load (getInput()->getStr(STR_URI_INPUT));

            map<Node, u_int64_t> mapping;
            u_int64_t count = 0;
            Graph::Iterator<NodeType> it = graph.iterator<NodeType> ();
            for (it.first(); !it.isDone(); it.next())  { mapping[it.item()] = count++; }

            for (it.first(); !it.isDone(); it.next())
            {
                NodeType current = it.item();

                Graph::Vector<NodeType> neighbors = graph.neighbors<NodeType> (current.kmer);

                for (size_t i=0; i<neighbors.size(); i++)
                {
                    fprintf (output, "%s -> %s;\n", graph.toString(current.kmer).c_str(), graph.toString(neighbors[i].kmer).c_str());
                }
            }

            fprintf (output, "}\n");

            fclose (output);
        }
    }

    // Actual job done by the tool is here
    void execute ()
    {
        switch (getInput()->getInt(STR_NODE_TYPE))
        {
            case 0: process<Node>          ("all");        break;
            case 1: process<BranchingNode> ("branching");  break;
            default: break;
        }
     }
};

/********************************************************************************/
/*                                                                              */
/********************************************************************************/
int main (int argc, char* argv[])
{
    try
    {
        // We run the tool with the provided command line arguments.
        CustomTool().run (argc, argv);
    }
    catch (Exception& e)
    {
        std::cout << "EXCEPTION: " << e.getMessage() << std::endl;
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

