// saved from url
// http://www-cs.canisius.edu/PL_TUTORIALS/C++/EXAMPLES/MRD/SRC/command.c -->
//-------------------------------- command.c -------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "expressions.h"
#include "relation.h"

extern Parseline parms;
extern void showall();
extern void show1();


void help_command()
{
	 if (strcmp (parms.word(0), "help") == 0) {
          if (parms.size() == 1) showall();
          else show1();
          return;
     }
}
/*
     SELECT

     select oldrelation newrelation field1 > value1 or field2 = field2 ...
        0        1          2         3    4   5    6    7   8    9
*/

void select_command ()
{
     char oldrelation[100];
     Speclist comps;
     Relation *oldr, *newr;

	 if (parms.word(1) == NULL)
		 throw "select_command: no filename";
     strcpy (oldrelation, parms.word(1));
     oldr = new Relation;
     oldr->load (oldrelation);

     comps.addspec (' ', parms.word(3), parms.word(4), parms.word(5));

     int wordsleft = parms.size() - 6;
     int k = 6;

     while (wordsleft > 0) {
          comps.addspec ((parms.word(k))[0], parms.word(k+1),
                         parms.word(k+2), parms.word(k+3));
          k += 4;
          wordsleft -= 4;
     }

     newr = oldr->select (comps);
     newr->save (parms.word(2));
     delete oldr;
     delete newr;
}

/*
     CROSS

     cross relation1 relation2 newrelation
       0       1         2          3
*/

void cross_command ()
{
     char rel1name[100], rel2name[100];
     Relation *rel1, *rel2, *newrel;

	 if (parms.word(1) == NULL)
		 throw "cross_command: no filename";
     strcpy (rel1name, parms.word(1));
     rel1 = new Relation;
     rel1->load (rel1name);

     strcpy (rel2name, parms.word(2));
     rel2 = new Relation;
     rel2->load (rel2name);

     newrel = rel1->cross(rel2);
     newrel->save (parms.word(3));
     delete rel1;
     delete rel2;
     delete newrel;
}

/*
     JOIN

     join relation1 field1 relation2 field2 newrelation
       0     1        2        3       4         5
*/

void join_command ()
{
     char rel1name[100], rel2name[100];
     Relation *rel1, *rel2, *newrel;
     char field1[50], field2[50];

	 if (parms.word(1) == NULL)
		 throw "join_command: no filename";
     strcpy (rel1name, parms.word(1));
     rel1 = new Relation;
     rel1->load (rel1name);

     strcpy (field1, parms.word(2));

     strcpy (rel2name, parms.word(3));
     rel2 = new Relation;
     rel2->load (rel2name);

     strcpy (field2, parms.word(4));

     newrel = rel1->ejoin(rel2, field1, field2);
     newrel->save (parms.word(5));
     delete rel1;
     delete rel2;
     delete newrel;
}

/*
     DIFF

     diff relation1 field1 relation2 field2 newrelation
       0      1        2       3       4         5
*/

void diff_command ()
{
     Relation old1, old2, *newone;

     old1.load (parms.word(1));
     old2.load (parms.word(3));

     newone = old1.difference (parms.word(2), &old2, parms.word(4));
     newone->save (parms.word(5));
     delete newone;
}

/*
     PROJECT

     project relation1 newrelation field1 field2 field3 ...
        0       1           2        3       4     5
*/

void project_command ()
{
     char fieldnames[1000];
     Relation *oldr, *newr;

     oldr = new Relation;
     oldr->load (parms.word(1));

     int wordsleft = parms.size() - 3;
     int i = 3;

     strcpy (fieldnames, "");

     while (wordsleft > 0) {
          strcat (fieldnames, parms.word(i));
          strcat (fieldnames, " ");
          i++;
          wordsleft--; 
     }

     newr = oldr->project (fieldnames);
     newr->save (parms.word(2));
     delete newr;
     delete oldr;
}

/*
     APPEND

     append relation1 relation2 newrelation
       0       1         2          3
*/

void append_command ()
{
     char rel1name[100], rel2name[100];
     Relation *rel1, *rel2;

	 if (parms.word(1) == NULL)
		 throw "append_command: no filename";
     strcpy (rel1name, parms.word(1));
     rel1 = new Relation;
     rel1->load (rel1name);

     strcpy (rel2name, parms.word(2));
     rel2 = new Relation;
     rel2->load (rel2name);

     rel1->append(rel2);
     rel1->save (parms.word(3));
     delete rel1;
     delete rel2;
}

/*
     PRINT

     print relation1
       0      1
*/

void printfields_command()
{
	 Relation *oldr;

     oldr = new Relation;
     oldr->load (parms.word(1));

     printf ("\n");
     oldr->printfields (stdout);
     
     delete oldr;
}

void print_command ()
{
     Relation *oldr;

     oldr = new Relation;
     oldr->load (parms.word(1));

     printf ("\n\n");
     oldr->printheader (stdout);

     oldr->print();
     printf ("\n\n");
     delete oldr;
}

/*
     INFO

     info relation1
       0      1
*/

void info_command ()
{
     Relation *oldr;

     oldr = new Relation;
     oldr->load (parms.word(1));

     oldr->info();
     delete oldr;
}

/*
     SORT

     sort oldrelation newrelation aord field1
       0        1          2        3    4

     aord=a or d (for ascending or descending order)
*/

void sort_command ()
{
     char oldrelation[100];
     char whichfield[50];
     Relation *oldr;
	 if (parms.word(1) == NULL)
		 throw "sort_command: no filename";
     strcpy (oldrelation, parms.word(1));
     oldr = new Relation;
     oldr->load (oldrelation);

     strcpy (whichfield, parms.word(4));

     oldr->sort(whichfield, (parms.word(3))[0] == 'a');

     oldr->save(parms.word(2));
     delete oldr;
}

/*
     STATS

     stats oldrelation newrelation field1
       0         1          2        3
*/
void stats_command () 
{ 
     char oldrelation[100];
     char whichfield[50];
     Relation *oldr, *newr;
	 if (parms.word(1) == NULL)
		 throw "stats_command: no filename";
     strcpy (oldrelation, parms.word(1));
     oldr = new Relation;
     oldr->load (oldrelation);

     strcpy (whichfield, parms.word(3));

     newr = oldr->summarystats(whichfield);

     newr->save(parms.word(2));
     delete oldr;
     delete newr;
}

/*
     NUMBER

     number oldrelation newrelation
       0         1          2       
*/

void number_command ()
{
     Relation *oldr, *newr;

     oldr = new Relation;
     oldr->load (parms.word(1));

     newr = oldr->addseqnums();

     newr->save(parms.word(2));
     delete oldr;
     delete newr;
}

/*
     UNIQUE

     unique oldrelation newrelation
        0         1          2       
*/

void unique_command ()
{
     Relation *oldr, *newr;

     oldr = new Relation;
     oldr->load (parms.word(1));

     newr = oldr->copy();
     newr->unique();

     newr->save(parms.word(2));
     delete oldr;
     delete newr;
}

/*
     ADDRECORD

     addrecord relation newrecord
         0        1         2
*/

static void add_command ()
{
     Relation current;
     current.load (parms.word(1));
	 
	 Parseline newrecord;

	 for (int i = 2; i < parms.size(); i++) {
		 newrecord.addword(parms.word(i));
	 }

     current.addrecord(&newrecord);
     current.save (parms.word(1));
}

/*
     CHANGEVALUE

     changevalue relation recnum fieldname newvalue
          0          1       2       3        4
*/

static void change_command ()
{
     Relation current;
     current.load (parms.word(1));

     int recnum = atoi(parms.word(2));

     if (recnum >= current.numrecords) {
          printf ("Not that many records!\n");
          return;
     }

     current.setcurrent(recnum);
     current.setvalue (parms.word(3), parms.word(4));
     current.save (parms.word(1));
}

/*
    RENAMEFIELD

     renamefield relation fieldname newname
         0          1        2        3
*/

void rename_field_command ()
{
     Relation current;
     current.load (parms.word(1));

     if (current.findfield(parms.word(2)) == -1) {
          printf ("No such field!\n");
          return;
     }

     if (current.findfield(parms.word(3)) != -1) {
          printf ("There is already a field with this name!\n");
          return;
     }

     current.changefieldname (parms.word(2), parms.word(3));
     current.save (parms.word(1));
}

/*
     CHANGEWIDTH

     changewidth relation fieldname newwidth
          0          1        2        3
*/

void change_printwidth_command()
{
     Relation current;
     char fieldname[50];

     current.load (parms.word(1));

     strcpy (fieldname, parms.word(2));

     if (current.findfield(fieldname) == -1) {
          printf ("No such field!\n");
          return;
     }

     current.changefieldwidth(fieldname, atoi(parms.word(3)));
     current.save (parms.word(1));
}

/*
     DELETERECORD

     deleterecord relation recnum
         0           1       2
*/

static void del_command ()
{
     Relation current;
     current.load(parms.word(1));
     current.delrecord (atoi(parms.word(2)));
     current.save(parms.word(1));
}

/*
     ADDFIELD 

     addfield relation fieldname datatype printwidth defaultvalue
        0        1         2         3         4          5
*/

static void addfield_command ()
{
     Relation current;
     current.load (parms.word(1));

     char fieldname[50], datatype;

     strcpy (fieldname, parms.word(2));

     int width = atoi(parms.word(4));

     datatype = (parms.word(3))[0];

     current.addfield (fieldname, current.numfields, datatype, width);

     char defaultvalue[100];
     strcpy (defaultvalue, parms.word(5));

     for (int i=0; i<current.numrecords; i++)
          current.addfieldvalue (parms.word(2), i, defaultvalue);

     current.save (parms.word(1));
}

//  The following is very tricky.  The Parseline class allows a lookup
//  function to be passed in as a parameter, but it can only have a
//  single parameter, a character string, so we cannot also have a Relation
//  parameter.  Thus, this HAS to be a global variable.

Relation *xcurrent;

static double mylookup (char *fieldname)
{
     if (xcurrent->findfield (fieldname) == -1) {
           printf ("No such field: %s\n", fieldname);
           return 0.0;
     }
     return xcurrent->getvalueD (fieldname);
}

/*
     CALCFIELD

     calcfield oldrelation fieldname "arithmetic expression"
       0        1        2               3
*/

static void calcfield_command () 
{
     xcurrent = new Relation;
     xcurrent->load (parms.word(1));

     char fieldname[100];
     strcpy (fieldname, parms.word(2));

     if (xcurrent->findfield(fieldname) == -1) {
           printf ("No such field.\n");
           return;
     }

     char expression[2000];
     strcpy (expression, parms.word(3));
     Arithparser ap;
     
     /*  Now go through the relation and change each field */

     xcurrent->setcurrent (0);   /* rewind */
     while (1) {
          double newvalue = ap.parse (expression, mylookup);
          xcurrent->setvalue (fieldname, newvalue);
          if (xcurrent->atend()) break;
          xcurrent->advance();
     }

     xcurrent->save (parms.word(1));
     delete xcurrent;
}

/*
     RETYPE

     retype oldrelation field1 field2
       0        1          2      3 
*/

static void retype_field_command () 
{
     Relation current;
     current.load (parms.word(1));

     char field1[100], field2[100];
     strcpy (field1, parms.word(2));
     strcpy (field2, parms.word(3));

     if (current.findfield(field1) == -1) {
           printf ("No such field as %s\n", field1);
           return;
     }
     if (current.findfield(field2) == -1) {
           printf ("No such field as %s\n", field2);
           return;
     }

     char type1 = current.getfieldtype(field1);
     char type2 = current.getfieldtype(field2);

     if (type1 == type2) {
          printf ("These are the same type.  No conversion necessary.\n");
          return;
     }

     /*  Now go through the relation and put into field2 the value
         of field1 converted to the new type */

     current.setcurrent (0);   /* rewind */

     if (type1 == 'c' && type2 == 'd') {
          while (1) {
               double newvalue = atof (current.getvalueC(field1));
               current.setvalue (field2, newvalue);
               if (current.atend()) break;
               current.advance();
          }
     }
     else if (type1 == 'c' && type2 == 'i') {
          while (1) {
               int newvalue = atoi (current.getvalueC(field1));
               current.setvalue (field2, newvalue);
               if (current.atend()) break;
               current.advance();
          }
     }
     else if (type1 == 'd' && type2 == 'i') {
          while (1) {
               int newvalue = int(current.getvalueD(field1));
               current.setvalue (field2, newvalue);
               if (current.atend()) break;
               current.advance();
          }
     }
     else if (type1 == 'd' && type2 == 'c') {
          while (1) {
               char newvalue[100];
               sprintf (newvalue, "%15.6f", current.getvalueD(field1));
               current.setvalue (field2, newvalue);
               if (current.atend()) break;
               current.advance();
          }
     }
     else if (type1 == 'i' && type2 == 'd') {
          while (1) {
               double newvalue = double (current.getvalueI(field1));
               current.setvalue (field2, newvalue);
               if (current.atend()) break;
               current.advance();
          }
     }
     else if (type1 == 'i' && type2 == 'c') {
          while (1) {
               char newvalue[100];
               sprintf (newvalue, "%d", current.getvalueI(field1));
               current.setvalue (field2, newvalue);
               if (current.atend()) break;
               current.advance();
          }
     }

     current.save (parms.word(1));
}

void mrdcommand (char *line)
{
     parms.set(line);

     if (strcmp (parms.word(0), "select") == 0)
           select_command ();

     else if (strcmp (parms.word(0), "project") == 0)
           project_command ();

     else if (strcmp (parms.word(0), "cross") == 0)
           cross_command ();

     else if (strcmp (parms.word(0), "join") == 0)
           join_command ();

     else if (strcmp (parms.word(0), "diff") == 0)
           diff_command ();

     else if (strcmp (parms.word(0), "append") == 0)
           append_command ();

     else if (strcmp (parms.word(0), "print") == 0) {
           print_command ();
	 }

	 else if (strcmp (parms.word(0), "printfields") == 0)
           printfields_command ();

     else if (strcmp (parms.word(0), "sort") == 0)
           sort_command ();

     else if (strcmp (parms.word(0), "stats") == 0)
           stats_command ();

     else if (strcmp (parms.word(0), "number") == 0)
           number_command ();

     else if (strcmp (parms.word(0), "unique") == 0)
           unique_command ();

     else if (strcmp (parms.word(0), "addrecord") == 0)
           add_command ();

     else if (strcmp (parms.word(0), "changevalue") == 0)
           change_command ();

     else if (strcmp (parms.word(0), "renamefield") == 0)
           rename_field_command ();

     else if (strcmp (parms.word(0), "changewidth") == 0)
           change_printwidth_command ();

     else if (strcmp (parms.word(0), "deleterecord") == 0)
           del_command ();

     else if (strcmp (parms.word(0), "addfield") == 0)
           addfield_command ();

     else if (strcmp (parms.word(0), "calcfield") == 0)
           calcfield_command ();

     else if (strcmp (parms.word(0), "retype") == 0)
           retype_field_command ();

     else if (strcmp (parms.word(0), "info") == 0)
           info_command ();

	 else if (strcmp (parms.word(0), "help") == 0)
		   help_command();

     else  printf ("Unrecognized command!\n");
}
