/*
  Copyright 2008 Nathan Phillip Brink
  
  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.
  
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU Affero General Public License for more details.
  
  You should have received a copy of the GNU Affero General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <stdio.h>
#include <stdlib.h>

/*
  reads stdin and writes to stdout
  reads data from http://bcs.whfreeman.com/yates2e/pages/bcs-main.asp?v=category&s=00080&n=99000&i=99080.01&o= in the "ASCII" format
 */

#define INBUF (100)
struct stringpart
{
  size_t length;
  char string[INBUF];
  struct stringpart *next;
};

void putstringpart(struct stringpart *in)
{
  in->string[INBUF-1] = '\0';
  fputs(in->string, stdout);
  if(in->next)
    putstringpart(in->next);
}

struct row
{
  struct stringpart **stringpart; /* null terminated list of strings making up this row */
  struct row *next;
};

void rowaddcol(struct row *therow)
{
  size_t length;
  //struct stringpart **newrowcontent;
  
  for(length = 0; *(therow->stringpart + length) != NULL; length ++);
  
  /* convert from index of the last element to the size, convert from < to <= */
  length += 1 + 1;
  //printf("newlength %d\n", length);

  therow->stringpart = realloc(therow->stringpart, sizeof(struct stringpart *) * length);
  *(therow->stringpart + length - 2) = malloc(sizeof(struct stringpart));
  *(therow->stringpart + length - 1) = NULL;
  
  
}


/* 1 = true, 0 = false*/
int isachar(const char const chars[], char thechar)
{
  int i = 0;
  do
    {
      if(chars[i++] == thechar)
	return 1;
    }
  while(chars[i] != '\0');
  return 0;
}

/* 1 = EOF, 2 = OEL, 0 = fine */
int readstring(struct stringpart **part)
{
  int i, j;
  char newchar;
  static const char const sepchars[] = {'\n', '\t', '\r', ' ', '\0'};
 
  do
    {

      *part = malloc(sizeof(struct stringpart));
      (*part)->next = NULL;
      i = 0;
      j = 0;
      
      /* eat extra whitespace */
      while(!feof(stdin)
	    && (j = fread(&newchar, (size_t)1, (size_t)1, stdin))
	    && isachar(sepchars, newchar)
	    )
	;
      if(j)
	{
	  /* puts("reada: "); */
/* 	  putchar(newchar); */
/* 	  puts("\n"); */
	  (*part)->string[i++] = newchar;
	}
      

      while(
	    (i < INBUF - 1)
	    && (j || !feof(stdin))
	    && (j = fread(&newchar, (size_t)1, (size_t)1, stdin))
	    && !isachar(sepchars, newchar)
	    )
	{
/* 	  puts("readb: "); */
/* 	  putchar(newchar); */
/* 	  puts("\n"); */

	  (*part)->string[i++] = newchar;
	  (*part)->length = i;
	}
      (*part)->string[i] = '\0';
      if(j && (newchar == '\n' || newchar == '\r'))
	{
	  //printf("returning 2\n");
	  return 2;
	}
      
      if(isachar(sepchars,newchar))
	{
	  //printf("returning 0\n");
	return 0;
	}
      
      if(j == 0 && feof(stdin))
	{
	  //printf("returning 1\n");
	  return 1;
	}
      
      part = &(*part)->next;
      
    }
  while(!feof(stdin)
	&& i < INBUF - 1);
  return 0;
}


int main(int argc, char *argv[])
{
 
  struct row names;
  struct row first;
  struct row *rowptr = &first;
  
size_t numcols, counter, counter2, ateof, numrows;
  int readstringreturn;
  
  
  names.stringpart = malloc(sizeof(struct stringpart *) * 2);
  *(names.stringpart + 1) = NULL;
  *names.stringpart = malloc(sizeof(struct stringpart));

  
  for(numcols = 0; (readstringreturn = readstring(names.stringpart + numcols)) != 2
	&& readstringreturn != 1; numcols ++)
    {
      //printf("numcols == %d, readstringreturna == %d;", numcols, readstringreturn);
      
/* putstringpart(*(names.stringpart + numcols)); */
/*       putchar('\n'); */
/*       for(counter = 0; counter < numcols + 1; counter ++) */
/* 	{ */
/* 	  rowptr = &first; */
	  
/* 	  puts("# name: "); */
/* 	  putstringpart(*(names.stringpart + counter)); */
/* 	  putchar('\n'); */
/* 	} */
      

      rowaddcol(&names);
    }
  //printf("numcols == %d\nreadstringreturnb == %d\n", numcols, readstringreturn);

  numcols ++;
  if(readstringreturn == 1)
    {
      //printf("more than one line of input is needed\n");
      return 1;
    }
  
  
  first.stringpart = malloc(sizeof(struct stringpart *) * (numcols + 1));
  *(first.stringpart + numcols + 1) = NULL;
  *first.stringpart = malloc(sizeof(struct stringpart));
  
  ateof = 0;
  numrows = 0;
  
  while(!ateof)
    {
      counter = 0;
      while( (readstringreturn = readstring(rowptr->stringpart + counter)) == 0)
	{
	  counter ++;
	  if(counter > numcols)
	    {
	      fprintf(stderr, "EXTRA LONG ROW\n");
	      return 1;
	    }
	}
      if(readstringreturn == 2 && numcols != (++counter))
	{
	  fprintf(stderr, "EXTRA SHORT ROW - should be %zd\n", numcols);
	  return 1;
	}
      if(readstringreturn == 1)
	ateof = 1;
      
      
      rowptr = rowptr->next = malloc(sizeof(struct row));
      rowptr->stringpart = malloc(sizeof(struct stringpart *) * numcols + 1);
      *(rowptr->stringpart + 1) = NULL;
      *rowptr->stringpart = malloc(sizeof(struct stringpart));
      
      numrows ++;
    }
  rowptr->next = NULL;
  
  fputs("# Created by ToOctave 0.0.0. Copyright 2008 Nathan Phillip Brink, licensed under the GNU Affero GPL. http://ohnopublishing.net/~ohnobinki/makeldif/\n", stdout);
  for(counter = 0; counter < numcols; counter ++)
    {
      rowptr = &first;
      
      fputs("# name: ", stdout);
      putstringpart(*(names.stringpart + counter));
      putchar('\n');
      
      printf("# type: matrix\n# rows: 1\n# columns: ");
      printf("%zd\n", numrows);
      
      for(counter2 = 0; counter2 < numrows; counter2 ++)
	{
	  putchar(' ');
	  putstringpart(*(rowptr->stringpart + counter));
	  rowptr = rowptr->next;
	}
      putchar('\n');
      
    }

  return 0;
}

