/*
  By Sandro Hawke (sandro@w3.org)    Begun March 2001.

  $Id: main.cc,v 1.4 2001/05/21 20:15:35 sandro Exp $

  ToDo:
     clean up options for output format
     some quad output formats
     pass in top-level context name
     fix up handling of vocabulary
*/

#include "parser.h"

#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <strstream>
#include <fstream>
#include <stdio.h>

char* vocab[] =
{
  "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
  "http://www.daml.org/2001/03/daml+oil#equivalentTo",
  "http://www.daml.org/2001/03/daml+oil#first",
  "http://www.daml.org/2001/03/daml+oil#rest",
  "http://www.daml.org/2001/03/daml+oil#nil",
  "http://www.w3.org/1999/02/22-rdf-syntax-ns#subject",
  "http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate",
  "http://www.w3.org/1999/02/22-rdf-syntax-ns#object",
  "http://www.w3.org/2001/04/18/set#enumeration",
  "http://www.w3.org/2000/10/logic#forSome"
};

char* genid_prefix="genid:";
bool flag_anons = false;
bool parse_as_condition = false;
bool do_arc = true;
int arc = 1;
class FlatN3Writer : public TupleStream {
public:
  virtual void write(string subject, string property, string value) {
    cout << "<" << subject << "> ";
    cout << "<" << property << "> ";
    cout << "<" << value << ">." << endl;
  }
};

class WSL_Writer : public TupleStream {
public:
  virtual void write(string subject, string property, string value) {
    cout << subject << " ";
    cout << property << " ";
    cout << value << endl;
  }
};

class PrologTripleWriter : public TupleStream {
public:
  virtual void write(string subject, string property, string value) {
    cout << "triple(";
    cout << "'" << subject << "',";
    cout << "'" << property << "',";
    cout << "'" << value << "')." << endl;
  }
};

class PrologPropertyTripleWriter : public TupleStream {
public:
  virtual void write(string subject, string property, string value) {
    cout << "property(";
    cout << "'" << subject << "',";
    cout << "'" << property << "',";
    cout << "'" << value << "')." << endl;
  }
};

class PrologQuadWriter : public TupleStream {
string streamIdent;
public:
  PrologQuadWriter(string s) : streamIdent(s) { };
  virtual void write(string subject, string property, string value) {
    cout << "says(global('";
    cout << streamIdent;
    cout << "'),";
    cout << "global('" << subject << "'),";
    cout << "global('" << property << "'),";
    cout << "global('" << value << "'))." << endl;
  }
  virtual ~PrologQuadWriter() { }
};

class DOTWriter : public TupleStream {
public:
  DOTWriter() {
    cout << "digraph anon {";
    cout << "   size=\"10,7.5\";";
    cout << "   center=true;";
    cout << "   node [shape=plaintext];";
    //    cout << "   ranksep = \"0.3\";";
    cout << "   order = out;";
    cout << "\n";
  }
  virtual void write(string subject, string property, string value) {
    arc++;
    cout << "\"" << subject << "\" [ label=\"XXX\" ];";
    cout << "\"" << value << "\" [ label=\"XXX\" ];";
    cout << "\"" << subject << "\"->";
    if (do_arc) cout << "\"_arc_" << arc << "\"->";
    cout << "\"" << value << "\" ";
    cout << (do_arc? ";\n" : "[");
    //if (property==vocab[AN_INSTANCE]) {
    //  cout << "color=blue, style=dotted, label=\"type\"";
    //} else {
      //cout << "label=\"" << property << "\"";
    //cout << "label=\"" << "foobar" << "\"";
    //}
    cout << "\"_arc_" << arc << "\" [ label=\"" << "foobar" << "\"";
    cout << "];" << endl;
  }
  virtual void close() {
    cout << "}\n";
  }
};


/*
class RDF_Writer : public TupleStream {
public:
  virtual void write(string subject, string property, string value) {
    cout << "<" << subject << "> ";
    cout << "<" << property << "> ";
    cout << "<" << value << ">." << endl;
  }
};
*/

int main(int argc, char** argv) 
{

  TupleStream* triple_stream = new FlatN3Writer;

  bool skip_stdin = false;

  int c;
  int option_index = 0;
  Symbol* result;

  while (1) {

    static struct option long_options[] =
    {
      {"node", 1, 0, 'n'},
      {"expression", 1, 0, 'e'},
      {"focus", 1, 0, 'n'},   // synonym for node
      {"file", 1, 0, 'f'},
      {"timeout", 1, 0, 't'},
      {"maxtime", 1, 0, 't'},  // syn for timeout
      {"html", 0, 0, 'h'},
      {"help", 0, 0, '?'},
      {"maxdepth", 1, 0, 'd'},
      {"returnfile", 1, 0, 'r'},
      {"resultfile", 1, 0, 'r'},
      {"Xprologstatements", 1, 0, 's'},
      {"Xprologmodel", 1, 0, 'm'},
      {"prologproperty", 0, 0, 'p'},
      {"genidprefix", 1, 0, 'g'},
      {"condition", 0, 0, 'c'},
      {"forsome", 0, 0, 'F'},
      {"graphviz", 0, 0, 'v'},
      {0, 0, 0, 0}
    };

    c = getopt_long (argc, argv, "Fcg:pwsmve:f:n:t:hd:r:?",
		     long_options, &option_index);

    if (c == -1) break;

    switch (c) {

    case 'F':
      flag_anons = true;
      break;
  
    case 'g':
      genid_prefix = optarg;
      break;

    case 'c':
      parse_as_condition = true;
      break;

    case 's':
      delete triple_stream;
      triple_stream = new PrologTripleWriter;
      break;

    case 'p':
      delete triple_stream;
      triple_stream = new PrologPropertyTripleWriter;
      break;

    case 'v':
      delete triple_stream;
      triple_stream = new DOTWriter;
      break;

    case 'w':
      delete triple_stream;
      triple_stream = new WSL_Writer;
      break;

    case 'f':
      result = parse_file(*triple_stream, optarg);
      if (result == 0) {
	cout << "Parsing file \"" << optarg << "\" failed.\n";
	exit(1);
      } else {
	// cout << "READ CONTENTS OF FILE " << optarg << endl;
      }
      break;

    case 'e':
      result = parse(*triple_stream, optarg);
      if (result == 0) {
	cout << "Expression parse failed.\n";
	cout << "was: \"" << optarg << "\"" << endl;
	exit(1);
      }
      break;

/*
    case 'n':
      node_focus = TreeLocation(optarg);
      cgi_state->set("node", optarg);
      do_focus = true;
      break;

    case 't':
      char* endptr;
      timeout=strtod(optarg,  &endptr);
      if (endptr == optarg || timeout < 0.00) {
	cout << "invalid timeout value\n";
	exit(0);
      }
      cgi_state->set("timeout", optarg);
      break;

    case 'h':
      use_html = true;
      break;

    case 'd':
      // set max depth?
      // 
      break;

    case 'r':
      // XXX   SECURITY CHECK OPTARG
      result_out.open(optarg);
      query = new WriteResultQuery(result_out);
      writing_result_out = true;
      break;
*/
    case ':':
      cout << "missing arguments\n";
      break;

    case '?':
      cout << "usage: [flags] [files]\n\n";
      cout << "  flags:  -F   --forsome    mark genid terms with a forsome property\n";
      cout << "          -c   --condition  parse inputs as a condition (pattern)\n";
      cout << "          -g   --genidprefix set the genid prefix\n";
      cout << "          -p   --prolog      output prolog\n";
      cout << "          -f                 name input file\n";
      cout << "          -e                 expression on command line\n";
      return 1;
      break;

    default:
      printf ("?? getopt returned character code %c %d ??\n", c, c);
    }
  }

  //  cout << "Argc: " << argc << "  Option Index: " << optind << endl;

  while (argc > optind) {
    skip_stdin=true;
    result = parse_file(*triple_stream, argv[optind]);
    if (result == 0) {
      cout << "Parsing file \"" << argv[optind] << "\" failed.\n";
      exit(1);
    } else {
      // cout << "READ CONTENTS OF FILE " << optarg << endl;
    }
    optind++;
  }


  if (!skip_stdin) parse_stdin(*triple_stream);

  triple_stream->close();
}
