#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
#include <cstdio>
#include <cstring>
#include "csv.h"
#include "st.h"

using namespace std;
using namespace csv_reader;

#ifdef NO_MAIN
#define System _System
extern int System(const string & cmd);
#else
int
System(const string & cmd)
{
   return system(cmd.c_str());
}
#endif

enum at_action {
   AT_CREATE,
   AT_QUERY,
   AT_DELETE,
   AT_USAGE,
   AT_NIL
};

class at_command {
   string the_time;
   string the_date;
   string the_cmd;
   string the_name;
   at_action action;
public:
   at_command() {
      action = AT_NIL;
   }
   void usage() {
      cout << "usage: at [ /c cmd ] [ /date MM/DD/YYYYY ] [ /time HH:MM ]" << endl;
      cout << "          [ /create | /query | /delete ] [ /name task ]" << endl;
   }
   void scan_args(int argc, char** argv) {
      for(size_t i = 1; i < argc; i++) {
         if(_stricmp(argv[i], "/c") == 0
            || _stricmp(argv[i], "/cmd") == 0) {
            if((i+1) < argc) {
               i++;
               the_cmd = argv[i];
            }
         }
         else if(_stricmp(argv[i], "/create") == 0) {
            action = AT_CREATE;
         }
         else if(_stricmp(argv[i], "/query") == 0) {
            action = AT_QUERY;
         }
         else if(_stricmp(argv[i], "/delete") == 0) {
            action = AT_DELETE;
         }
         else if(_stricmp(argv[i], "/date") == 0) {
            if((i+1) < argc) {
               i++;
               the_date = argv[i];
            }
         }
         else if(_stricmp(argv[i], "/time") == 0) {
            if((i+1) < argc) {
               i++;
               the_time = argv[i];
            }
         }
         else if(_stricmp(argv[i], "/name") == 0) {
            if((i+1) < argc) {
               i++;
               the_name = argv[i];
            }
         }
         else if(strcmp(argv[i], "/?") == 0
                 || _stricmp(argv[i], "/help") == 0) {
            action = AT_USAGE;
         }
         else {
            throw "bad command line parameter...";
         }
      }
      if(action == AT_NIL) {
         throw "/create, /query or /delete only...";
      }
   }
   void query() {
      ifstream fin("atdata.csv");
      if(fin) {
         csv_row_type row;
         string name;
         string date;
         string prog;
         while(fin >> row) {
            name = row[1];
            date = row[19] + " " + row[20];
            prog = row[8];
            if(name.find("winsh_at_") != string::npos) {
               name = name.substr(10);
               cout << name << " " << date << " " << prog << endl;
            }
         }
         fin.close();
      }
   }
   void at_create() {
      if(System("SCHTASKS /Create /tn \"winsh_at_" 
                  + the_name 
                  + "\" /tr \"" + the_cmd 
                  + "\" /sc ONCE /sd " + the_date 
                  + " /st " + the_time) != 0) {
         throw "unable to create at command...";
      }
   }
   void at_query() {
      if(System("cmd /c \"SCHTASKS /Query /fo CSV /v > atdata.csv\"") != 0) {
         throw "unable to list the at table...";
      }
      else {
         query();
      }
   }
   void at_delete() {
      if(System("SCHTASKS /Delete /tn \"winsh_at_" + the_name + "\" /f") != 0) {
         throw "unable to delete the at table entry...";
      }
   }
   void run() {
      switch(action) {
         case AT_CREATE:
            at_create();
         break;
         case AT_QUERY:
            at_query();
         break;
         case AT_DELETE:
            at_delete();
         break;
         case AT_USAGE:
            usage();
         break;
      }
   }
};

#ifdef NO_MAIN
extern "C" {
extern int at_main(int argc, char ** argv);
}
int
at_main(int argc, char ** argv)
#else
int
main(int argc, char ** argv)
#endif
{
   at_command at;
   int rc = 0;
   try {
      at.scan_args(argc,argv);
      at.run();
   }
   catch(const char* message) {
      cout << message << endl;
      at.usage();
      rc = 1;
   }
   catch(...) {
      cout << "exception..." << endl;
      rc = 1;
   }
   return rc;
}
