/*****************************************************************************
 *  FUNCTIONS                                                                *
 *                                                                           *
 ****************************************************************************/
#include "table.h"

/*****************************************************************************
 *  TABLE *topen( char *fname, char *mode )                                  *
 *    Opens table in external file "fname" with access mode "mode".          *
 *    Meaning of mode is as in fopen.                                        *
 *    Allocates and initializes TABLE structure.                             *
 *    Returns pointer to TABLE if successful.                                *
 *    Returns NULL if allocate fails.                                        *
 *    Does essentially no error checking.                                    *
 *                                                                           *
 ****************************************************************************/

TABLE *topen( char *fname, char *mode )
{
  int i;
  TABLE *t = (TABLE *) malloc( sizeof( TABLE ) );

  if ( t != NULL )
    {
      strcpy( t->name, fname );
      t->valid = FALSE;
      t->file = fopen( fname, mode);
      if ( t->file != NULL && *mode == 'r')
        {
          fscanf(t->file,"%i", &(t->arity));
          for (i = 0; i < t->arity; i += 1)
            {
              fscanf( t->file, "%s", t->attributes[i] );
            }              
        }
    }

  return t;
}

/*****************************************************************************
 *  TABLE *tcreate( char *fname, int arity, TUPLE attributes )               *
 *    Creates and opens new external table "fname" with arity "arity" and    * 
 *       attribute names "attributes".                                       *
 *    If fname is null it uses a new unique filename of form "TabXXXXXX".    *
 *    File is opened "w+"---read/write---and truncated if it exists.         *
 *    Returns pointer to TABLE structure or NULL if something failed.        *
 *    Does essentially no error checking.                                    *
 *                                                                           *
 ****************************************************************************/

TABLE *tcreate( char *fname, int ar, TUPLE atr )
{
  char *tname = fname;
  char tmplt[] = "TabXXXXXX";
  int i;
  TABLE *t = (TABLE *) malloc( sizeof( TABLE ) );

  printf("Create table |%s|\n", fname);

  if ( t != NULL )
    {
      if ( *tname == '\0' )
        {
        tname = (char *) mktemp( tmplt );
        printf("   as %s\n",tname);
        }
      
      strcpy( t->name, tname );
      t->valid = FALSE;
      t->file = fopen( tname, "w+");
      if ( t->file != NULL )
        {
          t->arity = ar;
          fprintf(t->file,"%i\n", ar);
          for (i = 0; i < ar; i += 1)
            {
              strcpy( t->attributes[i], atr[i] ); 
              fprintf( t->file, "%s ", t->attributes[i] );
            }              
          fputc( '\n', t->file);
        }
      else printf("File open failed\n");
    }
  
  showTblStr( t );
  
  return t;
}

/*****************************************************************************
 *  int tclose( TABLE *t)                                                    *
 *    Closes file associated with *t and frees t.                            *
 *    Returns status from fclose.                                            *
 *                                                                           *
 ****************************************************************************/

int tclose( TABLE *t )
{
  int status;
  
  if ( t != NULL && ( status = fclose( t->file ) ) == 0 )
    free( t );
  
  return status;
}


/*****************************************************************************
 *  int tdispose( TABLE *t)                                                  *
 *    Closes and deletes file associated with *t and frees t.                *
 *    Returns status from fclose.                                            *
 *                                                                           *
 ****************************************************************************/

int tdispose( TABLE *t )
{
  int status;

    if ( t != NULL && ( status = fclose( t->file ) ) == 0 )
      {
        remove( t->name );
        free( t );
      }

  return status;
}


/*****************************************************************************
 * int tread( TABLE *t )                                                     *
 *   Reads next tuple of t into current.                                     *
 *   Returns 1 if successful.                                                *
 *   Returns 0 if <eof> prior to end of tuple                                *
 *   Returns negative number if error on read                                *
 *                                                                           *
 ****************************************************************************/

int tread( TABLE *t )
{
  int i;
  int status;

  if ( t != NULL )
    {
      status = 1;
      t->valid = FALSE;
      for ( i=0; status == 1 && i < t->arity ; i += 1 )
        {
          status = fscanf( t->file, "%s", t->current[i] );
        }
      
      if ( status != EOF ) 
        t->valid = TRUE;
      
      return status;
    }
  else return 0;
}
  
  
/*****************************************************************************
 * int twrite( TABLE *t )                                                    *
 *   Writes current tuple of t.                                              *
 *   Returns 1 if successful.                                                *
 *   Any other return value signifies failure.                               *
 *                                                                           *
 ****************************************************************************/

int twrite( TABLE *t )
{
  int i;
  int status;

  if ( t != NULL )
    {
      status = 1;
      for ( i=0; status > 0 && i < t->arity ; i += 1 )
        {
          status = fprintf( t->file, "%s ", t->current[i] );
        }
      if ( status > 0 )
        status = fputc( '\n', t->file );
      
      return status;
    }
  else return 0;
}


/*****************************************************************************
 * void trewind( TABLE *t )                                                  *
 *  Reposition file associated with t to before first tuple.                 *
 *                                                                           *
 ****************************************************************************/
  
void trewind( TABLE *t)
{
  int i;

  if ( t != NULL )
    {
      rewind( t->file );
/*       i = fseek( t->file, 0L, SEEK_SET ); */

      fscanf(t->file,"%i", &(t->arity));
      for (i = 0; i < t->arity; i += 1)
                 fscanf( t->file, "%s", t->attributes[i] );

      t->valid = FALSE;
    }
}


/*****************************************************************************
 * void showTblStr( TABLE * t )                                              *
 *   Dump TABLE structure to stdout                                          *
 *                                                                           *
 ****************************************************************************/

void showTblStr( TABLE *t )
{
  int i;

  if ( t != NULL )
    {
      printf("TableStr: %i (%s), arity: %i\nAttributes: ", t, t->name, t->arity);
      for (i = 0; i < t->arity; i += 1)
        {
          printf( "|%s| ", t->attributes[i] );
        }
      if ( t->valid )
        {
          printf( "\nCurrent values: " );
          for (i = 0; i < t->arity; i += 1)
            {
              printf( "|%s| ", t->current[i] );
            }
          putchar( '\n' );
        }
      else
        printf( "\nNo current values\n");
    }
  else printf( "No such table\n");
}


/*****************************************************************************
 *  void showTable( TABLE * )                                                *
 *    Dump entire table (all tuples) to stdout                               *
 *                                                                           *
 ****************************************************************************/

void showTable( TABLE *t )
{
  int rstatus, i;

  if ( t != NULL )
    {
      trewind( t );
      printf("Table: %i (%s), arity: %i\nAttributes: ", t, t->name, t->arity);
      for (i = 0; i < t->arity; i += 1)
        {
          printf( "|%s| ", t->attributes[i] );
        }
      putchar('\n');

      while ( (rstatus = tread( t )) == 1 )
        {
          printf( "Tuple:: ");
          for ( i=0; i < t->arity ; i += 1 )
            printf( "%s:%s ", t->attributes[i], 
                    t->current[i]);
          putchar('\n');
        }
    }
  else printf( "No such table\n");
}



/*****************************************************************************
 *  int cmpTuple( TUPLE left, TUPLE right, int arity )                       *
 *    Returns 0 if first arity attributes of tuples are equal                *
 *            < 0 if first unequal attribute in left tuple is < right        *
 *            > 0 if first unequal attribute in left tuple is > right        *
 *                                                                           *
 ****************************************************************************/

int cmpTuple( TUPLE tpll, TUPLE tplr, int arity)
{
    int comp = 0;
    int i;
      
    i = 0;
    while ( i < arity && comp == 0 )
      {
        comp = strcmp( tpll[i], tplr[i]);
        i += 1;
      }

    return comp;
}


/*****************************************************************************
 *  Boolean matchTuple( TUPLE tup, TUPLE pat, int arity )                    *
 *   Compares tup and pat for equality of attributes                         *
 *   Attributes of pat which are null strings are treated as Do-Not-Care.    *
 *                                                                           *
 ****************************************************************************/

Boolean matchTuple( TUPLE tpl, TUPLE pat, int arity)
{
    Boolean match = TRUE;
    int i;
      
    for ( i = 0; i < arity && match; i += 1)
      {
        match = match && 
          ( (*(pat[i]) == '\0') || 
              (strcmp( tpl[i], pat[i]) == 0) );
      }
    return match;
}


/*****************************************************************************
 *  void moveTuple( TUPLE to, TUPLE from, int arity )                        *
 *   Moves tuple from to tuple to                                            *
 *                                                                           *
 ****************************************************************************/

void moveTuple( TUPLE to, TUPLE from, int arity )
{
    int i;
  
    for ( i = 0; i < arity; i += 1)
        strcpy( to[i], from[i] );
}


/*****************************************************************************
 *  int projTuple( TUPLE to, TUPLE from, int arity, TUPLEBOOL select )       *
 *    Projects those attributes of from for which select it TRUE into to     *
 *    Returns arity of to                                                    *
 *                                                                           *
 ****************************************************************************/

int projTuple( TUPLE to, TUPLE from, int to_arity, char select[MAXARITY] )
{
	int i;
	int from_arity;
	
	for ( i=0; i < to_arity; i++ )
		{
			if ( select[i] == '1' )
				{
					strcpy( from[from_arity], to[i] );
					from_arity++;
				}
		}
	return from_arity;
}


/*****************************************************************************
 * TABLE *restrict( TABLE *tin, TUPLE cond )                                 *
 *  Writes those tuples of tin in with attributes matching cond (in the      *
 *     matchTuple sense) to the file associated with the TABLE it returns.   *
 *  This version would create a new temporary table.                         *
 *  Other signatures you might consider would take a pointer to the output   *
 *     TABLE or a string with the filename of the output table as another    *
 *     argument.                                                             *
 *                                                                           *
 ****************************************************************************/

TABLE *restrict( TABLE *tin, TUPLE cond)
{
	int i;
	int match = 0;
	TABLE *temp;
	
	temp = (TABLE *) malloc( sizeof( TABLE ) );
	temp = tcreate( "restrict.dat", tin->arity, tin->attributes);
	
	while ( tread( tin ) != EOF )
		{
			moveTuple( temp->current, tin->current, tin->arity );
			for ( i = 0; i < tin->arity; i++ )
				{
					match = cmpTuple( cond, tin->current, i);
					if (match == 0)
						twrite ( temp );
				}
		}
	return temp;
}


/*****************************************************************************
 * TABLE *projm( TABLE * tin, TUPLEBOOL select )                             *
 *   Writes the projection of the tuples of tin (without removing duplicates)*
 *     to the file associate with the TABLE it returns.                      *
 *   Otherwise similar to restrict.                                          *
 *                                                                           *
 ****************************************************************************/

TABLE *projm( TABLE *tin, TUPLEBOOL select)
{
	int i;
	int match = 0;
	TABLE *temp;

	temp = (TABLE *) malloc( sizeof( TABLE ) );
	temp = tcreate( "projm.dat", tin->arity, tin->attributes );
	for ( i = 0; i < tin->arity; i++ )
		if ( select[i] == 'T' )
			/* print just that column */
				

	return temp;
}


/*****************************************************************************
 * TABLE *unique( TABLE *tin )                                               *
 *   Copies tin to the output table removing duplicates.                     *
 *                                                                           *
 ****************************************************************************/

TABLE *unique( TABLE *tin )
{
	int i = 0;
	int dup = 0;
	TABLE *tout;
	
	tout = (TABLE *) malloc( sizeof( TABLE ) );
	tout = tcreate( "unique.dat", tin->arity, tin->attributes );
	
	tread(tin);
	moveTuple( tout->current, tin->current, tin->arity );
	twrite(tout);
	
	trewind(tout);
	while ( tread ( tin ) != EOF )
		{
			while ( tread ( tout ) != EOF )
				dup = ( dup + matchTuple( tin->current, tout->current, tin->arity ) );
			if ( !dup )
				{
					moveTuple( tout->current, tin->current, tin->arity );
					twrite ( tout );
				}
			trewind ( tout );
		}
	return tout;
}


/*****************************************************************************
 * TABLE *proj( TABLE * tin, TUPLEBOOL select )                              *
 *           etc.                                                            *
 *                                                                           *
 ****************************************************************************/

TABLE *proj ( TABLE *tin, TUPLEBOOL select)
{

}


/*****************************************************************************
 *  TABLE *join( TABLE * touter, TABLE * tinner, TUPLEINT cols )             *
 *    Join touter and tinner and write result to TABLE                       *
 *    A pair of tuples is joined iff for all i in which col[i] != 0          *
 *      the ith attribute of the outer tuple equals the col[i]th attribute   *
 *      of the inner tuple                                                   *
 *                                                                           *
 ****************************************************************************/

TABLE *join( TABLE *touter, TABLE *tinner, TUPLEINT cols )
{
	int i, j;
	int tout_arity = touter->arity;
	TABLE *tout;
	
	tout = (TABLE *) malloc( sizeof( TABLE ) );
	
	/* copy touter attributes to tout */
	for ( i = 0; i < touter->arity; i++ )
		strcpy ( tout->attributes[i], touter->attributes[i] );
		
	/* copy tright attributes to tout that do not exist already */
	for ( i = 0; i < tinner->arity; i++ )
		for ( j = 0; j < tout->arity; j++ )
			if ( strcmp ( tout->attributes[j], tinner->attributes[i] ) != 0 )
				{
					strcpy ( tout->attributes[tout_arity + 1], tinner->attributes[i] );
					tout_arity++;
				}
	tout = tcreate( "join.dat", tout_arity, tout->attributes );
	
	/* write all of touter that is not in tinner to tout */
	while ( tread ( touter ) != EOF )
			for ( i = 0; i < touter->arity; i++ )
					for ( j = 0; j < tinner->arity; j++ )
						if ( strcmp ( touter->current[i], tinner->current[j] ) == 0 )
							twrite ( touter );
	
	/*write all of tinner that has not been put in tout */
	while ( tread ( tinner ) != EOF )
			for ( i = 0; i < tout->arity; i++ )
					for ( j = 0; j < tinner->arity; j++ )
						if ( strcmp ( tout->current[i], tinner->current[j] ) == 0 )
							twrite ( tinner );
	return tout;
}


/*****************************************************************************
 *  TABLE *union( TABLE * tleft, TABLE * tright )                            *
 *    TABLE gets the union of tleft and tright                               *
 *                                                                           *
 ****************************************************************************/

TABLE *Union( TABLE *tleft, TABLE *tright )
{
	int i, j;
	int match = 0;
	int tout_arity = tleft->arity;
	TABLE *tout;
		
	tout = (TABLE *) malloc( sizeof( TABLE ) );
	
	/* copy tleft attributes to tout */
	for ( i = 0; i < tleft->arity; i++ )
			strcpy ( tout->attributes[i], tleft->attributes[i] );

	/* copy tright attributes to tout that do not exist already */	
	for ( i = 0; i < tright->arity; i++ )
		for ( j = 0; j < tout->arity; j++ )
			if ( strcmp ( tout->attributes[j], tright->attributes[i] ) != 0 )
				{
					strcpy ( tout->attributes[tout_arity + 1], tright->attributes[i] );
					tout_arity++;
				}
	tout = tcreate( "union.dat", tout_arity, tout->attributes );
	
	/* first write tleft to tout then compare and write any from tleft that do
			not exist already in tout */
	while ( tread ( tleft ) != EOF )
		{
			moveTuple ( tout->current, tleft->current, tleft->arity );
			twrite ( tout );
		}
	
	while ( tread ( tright ) != EOF )
		{
			moveTuple ( tout->current, tright->current, tright->arity );
			for ( i = 0; i < tout->arity; i++ )
				{
					match = cmpTuple( tout->current, tright->current, i);
					if (match = 0)
						twrite ( tout );
				}
		}
	return tout;
}


/* end of table.c */

