#include <stdio.h>
#include <string.h>
#include "../../pnheaders/pns.h"
#include "../MemoryManager.h"

/*Input descriptor string syntax:
TYPE Name, TYPE Name,...
name = any string without whitespace.
TYPE = one of:
	matrix				A matrix.
	indexarray		An array of indexes (treated like an integer array).
	arrayi				An array of integers stored as a pointer.	
	arrayd				An array of doubles stored as a pointer.
	arraya				An array of arrays of integers.
	int						An integer.
	double				A double.
	string				A pointer to characters. Reads a single line.
	
Output descriptor string syntax is the same as for the input descriptor except 
that non-count array types are invalid and there is one additional type, 
indexarrayc, which is stored like an arrayic but displayed as a row of X's, one 
in each tab-separated column corresponding to an index stored in the array.
*/

typedef struct Parameter
{
	char* Name;
	char* Type;
	int Start;
} Parameter;

static int ParseDescription(MemoryManager* memory, char* DataDescription, Parameter** Param, int* Items);
static int FindParameter(char* Name, Parameter* Param, int ParamCount);
static matrix ReadMatrix(FILE* file);
static double* ReadDblArray(FILE* file, int* length);
static int* ReadIntArray(FILE* file, int* length);
static void TrimWhitespace(char* string);
static void Help(char* helpstring, Parameter* Param, int ParamCount);
int ParseStructure(FILE *file, char* DataDescription, int** FilledMask, MemoryManager* Memory, ...)
{
	MemoryManager memory;
	Parameter *Param;
	int ParamCount, i, PID;
	int* ParamsAssigned;
	char Token[64], Line[128];
	char *LineStart;
	va_list pointers;
	void** Data;
	
	int Int, Length, DataLength;
	
	memory = CreateMemoryManager(20, 20, 0, 0);
	
	/*Parse the data description string. The parser returns the number of pieces of data that
	can be looked for. If this is 0, return now.*/
	if (! (ParamCount = ParseDescription(&memory, DataDescription, &Param, &DataLength)))
	{
		return 0;
	}
	/*Get the addresses in which to put the data. Data will be passed as pointers.*/
	Data = mcalloc(&memory, DataLength, sizeof(void*));
	va_start(pointers, Memory);
	for (i = 0; i < DataLength; i++)
	{
		Data[i] = va_arg(pointers, void*);		
	}
	va_end(pointers);	

	/*If we have been passed a mask to record what is and isn't filled, allocate
	storage space externally.*/
	if (FilledMask)
	{
		(*FilledMask) = mcalloc(Memory, ParamCount, sizeof(int));
		ParamsAssigned = *FilledMask;
	}
	else
	{
		/*Otherwise, allocate the storage space internally so it will be cleared at 
		the end of the parse.*/
		ParamsAssigned = mcalloc(&memory, ParamCount, sizeof(int));
	}
	
	while (1)
	{		
		/*Read a token. If we have reached end of file return 0.*/
		if (fscanf(file, "%s", Token) == EOF)
		{
			FreeMemory(&memory);
			return 0;
		}
		/*If it is the problem-end keyword return 1.*/
		else if (! strcmp(Token, "done"))
		{
			FreeMemory(&memory);
			return 1;
		}
		/*If it is the file-end keyword return 0.*/
		else if (! strcmp(Token, "quit"))
		{
			FreeMemory(&memory);
			return 0;
		}
		/*If it is a request to echo a line to the screen, read the line, move past
		any leading whitespace, and print to the screen.*/
		else if (! strcmp(Token, "echo"))
		{
			fgets(Line, 128, file);
			LineStart = Line;
			TrimWhitespace(Line);
			printf("%s\n", LineStart);
		}
		/*If it is a line comment read the remainder of the line and do nothing.*/
		else if (! strcmp(Token, "rem"))
		{
			fgets(Line, 128, file);
		}
		/*If it is a request for help, read the rest of the line and show the help.*/
		else if (! strcmp(Token, "help"))
		{
			fgets(Line, 128, file);
			TrimWhitespace(Line);
			Help(Line, Param, ParamCount);
		}
		/*Otherwise try to parse it as a user-defined token.*/
		else
		{
			/*Get the ID (index in the parameter array) of the parameter to which
			the token corresponds. FindParameter will return -1 if it cannot find
			a parameter with the given name.*/
			if ((PID = FindParameter(Token, Param, ParamCount)) >= 0)
			{
				/*If the parameter has already been assigned it is a fatal error. Fail.*/
				if (ParamsAssigned[PID])
				{
					FreeMemory(&memory);
					merror(0, "PARSE: Parameter defined twice. Failing.");
					return 0;
				}
				/*If the parameter is a matrix, read using the readmatrix function.
				ReadMatrix will return an empty matrix in case of failure. Such an error
				is fatal.*/
				if (! strcmp(Param[PID].Type, "matrix"))
				{
					*((matrix*)Data[Param[PID].Start]) = ReadMatrix(file);
					if (! NumberOfRows(*((matrix*)Data[Param[PID].Start])))
					{
						FreeMemory(&memory);
						merror(0, "PARSESTRUCTURE: There was an error reading a matrix.");
						return 0;
					}
					ManageMatrix(Memory, (matrix*)Data[Param[PID].Start]);
				}
				/*If it is an int array read that. There are two members of the
				variable-length parameter list for each array; the first is the pointer
				to the array pointer and the second is a pointer to an int to hold the
				array length.*/
				else if (! (strcmp(Param[PID].Type, "arrayi") && strcmp(Param[PID].Type, "indexarray")))
				{
					*((int**) Data[Param[PID].Start]) = ReadIntArray(file, &Length);
					*((int*) Data[Param[PID].Start + 1]) = Length;
					ManageMemory(Memory, *((void**) Data[Param[PID].Start]));
				}
				/*Array of doubles..*/
				else if (! strcmp(Param[PID].Type, "arrayd"))
				{
					*((double**) Data[Param[PID].Start]) = ReadDblArray(file, &Length);
					*((int*) Data[Param[PID].Start + 1]) = Length;
					ManageMemory(Memory, *((void**) Data[Param[PID].Start]));
				}
				/*Array of arrays of integers*/
				else if (! strcmp(Param[PID].Type, "arraya"))
				{
					/*ReadArrayA takes as its third parameter a pointer to the array
					pointer destined to hold the array of arrays, as its fourth parameter
					a pointer to the array pointer destined to hold a count of the number
					of elements in each subarray, and as its fifth parameter a pointer to
					the number of arrays.*/
					if (! ReadArrayA(file, Memory, (int***) Data[Param[PID].Start], (int**) Data[Param[PID].Start + 1], (int*) Data[Param[PID].Start + 2]))
					{
						FreeMemory(&memory);
						merror(0, "PARSESTRUCTURE: There was an error reading an array of arrays");
						return 0;
					}
				}
				/*A single integer.*/
				else if (! strcmp(Param[PID].Type, "int"))
				{
					fscanf(file, "%d", ((int*) Data[Param[PID].Start]));
				}
				/*A single double.*/
				else if (! strcmp(Param[PID].Type, "double"))
				{
					fscanf(file, "%lf", ((double*) Data[Param[PID].Start]));
				}
				/*A string. Read the remainder of the line. Note that this assumes that
				the corresponding pointer in the variable-length parameter list is
				a pre-allocated pointer to a char array of at least length 128.*/
				else if (! strcmp(Param[PID].Type, "string"))
				{
					fgets(((char*) Data[Param[PID].Start]), 128, file);
					/*Trim leading and trailing whitespace.*/
					TrimWhitespace((char*) Data[Param[PID].Start]);
				}
				else
				{
					/*If we get here it means that somehow the Type string of the
					parameter array was mis-set. Fail due to internal error.*/
					FreeMemory(&memory);
					merror(0, "PARSE: Internal Error");
					return 0;
				}
				ParamsAssigned[PID] = 1;
			}
			else
			{
				/*If we get here, it means that FindParam could not find a parameter
				with the name given. Warn about the unrecognized token and continue.*/
				printf("Warning: Unrecognized Token '%s'\n", Token);
			}
		}
	}
}

void DisplayStructure(char* DataDescription, int* Mask, ...)
{	
	int i, j, k, MarkWidth, DataLength, ParamCount;
	Parameter* Params;
	va_list args;
	va_start(args, Mask);
	MemoryManager memory;
	
	matrix* Matrix;
	int** IntAP;
	int* IntP;
	int Int, Length;
	double* DblP;
	double Dbl;
	char* string;
	
	memory = CreateMemoryManager(10, 10, 0, 0);
	
	/*Parse the data description and get a parameter type array.*/
	if (! (ParamCount = ParseDescription(&memory, DataDescription, &Params, &DataLength)))
	{
		merror(0, "DISPLAYDATA: Bad Data Description");
		return;
	}
	/*Iterate through the parameters. Since the variable-length parameter list
	is given in the same order as the parameters, we can just read it one
	parameter at a time.*/
	for (i = 0; i < ParamCount; i++)
	{
		if (! strcmp(Params[i].Type, "matrix"))
		{			
			Matrix = va_arg(args, matrix*);
			/*If the matrix is zero-sized don't show it.*/
			if ((Mask ? Mask[i] : 1) && NumberOfRows(*Matrix) && NumberOfColumns(*Matrix))
			{
				ShowMatrix(Matrix, Params[i].Name);
			}
		}
		else if (! strcmp(Params[i].Type, "arrayi"))
		{
			IntP = va_arg(args, int*);
			Length = va_arg(args, int);
			/*Print the name of the array and then all its elements after it on one
			line.*/
			if (Mask ? Mask[i] : 1)
			{
				printf("%s:\t", Params[i].Name);
				for (j = 0; j < Length; j++)
				{
					printf("%d\t", IntP[j]);
				}
				printf("\n");
			}
		}
		else if (! strcmp(Params[i].Type, "indexarray"))
		{
			/*An indexarray is stored like a normal integer array except for a third
			element in the variable parameter list. It is displayed differently as
			well. The indexarray represents a variable-length array of column
			indices. When it is displayed, rather than showing the indices, the
			columns corresponding the indices are marked in stdout with an X. Columns
			without a corresponding index entry are left blank. Columns are separated
			by tabs; the display is intended to be compatible with matrix display,
			which also separates columns with tabs*/
			IntP = va_arg(args, int*);
			Length = va_arg(args, int);
			/*The third parameter is another integer representing the total number
			of columns in the matrix. This is used so that the list name can be
			printed not immediately after the last index mark but instead to the right
			of the last column of the matrix.*/
			MarkWidth = va_arg(args, int);
			if (Mask ? Mask[i] : 1)
			{				
				for (j = 0; j < MarkWidth; j++)
				{
					for (k = 0; k < Length; k++)
					{
						if (IntP[k] == j)
						{
							printf("X");
							break;
						}
					}
					printf("\t");
				}
				printf("%s\n", Params[i].Name);
			}
		}		
		else if (! strcmp(Params[i].Type, "arrayd"))
		{
			/*The first parameter is the array pointer and the second is the array
			length.*/
			DblP = va_arg(args, double*);			
			Length = va_arg(args, int);
			if (Mask ? Mask[i] : 1)
			{
				printf("%s:\t", Params[i].Name);
				for (j = 0; j < Length; j++)
				{
					printf("%lf\t", DblP[j]);
				}
				printf("\n");
			}
		}
		else if (! strcmp(Params[i].Type, "arraya"))
		{
			/*The first parameter is the pointer to the array of arrays, the second
			to the array of counts, and the third to the count of arrays.*/
			IntAP = va_arg(args, int**);
			IntP = va_arg(args, int*);
			Length = va_arg(args, int);
			/*Display only if the array is nonzero*/
			if ((Mask ? Mask[i] : 1) && IntAP && IntP && Length)
			{
				printf("%s: %d subarrays:\n", Params[i].Name, Length);
				for (j = 0; j < Length; j++)
				{
					printf("%s %d:\t", Params[i].Name, j);
					for (k = 0; k < IntP[j]; k++)
					{
						printf("%d\t", IntAP[j][k]);
					}
					printf("\n");
				}
			}
		}
		else if (! strcmp(Params[i].Type, "int"))
		{
			Int = va_arg(args, int);
			if (Mask ? Mask[i] : 1)
			{
				printf("%s: %d\n", Params[i].Name, Int);
			}
		}
		else if (! strcmp(Params[i].Type, "double"))
		{
			Dbl = va_arg(args, double);
			if (Mask ? Mask[i] : 1)
			{
				printf("%s: %lf\n", Params[i].Type, Dbl);
			}
		}
		else if (! strcmp(Params[i].Type, "string"))
		{
			string = va_arg(args, char*);
			if (Mask ? Mask[i] : 1)
			{
				printf("%s: %s\n", Params[i].Name, string);
			}
		}
		else
		{
			/*If we get here it means that the parameter type name was invalid.*/
			merror(0, "DISPLAYDATA: Data Description Error");
			va_end(args);
			return;
		}
	}
	va_end(args);
	FreeMemory(&memory);
}

int* ReadIntArray(FILE* file, int* length)
{
	int* ret;
	int i;
	/*Return a null pointer in case of failure to read the array length.*/
	if (! fscanf(file, "%d", length))
	{
		return 0;
	}
	/*Allocate array space, read the array elements, and return. If an error
	occurs free the allocated space and return a null pointer.*/
	ret = tcalloc(*length, sizeof(int));
	for (i = 0; i < *length; i++)
	{
		if (! fscanf(file, "%d", ret + i))
		{
			free(ret);
			return 0;
		}
	}
	return ret;
}
		
double* ReadDblArray(FILE* file, int* length)
{
	double* ret;
	int i;
	/*Return a null pointer in case of failure to read the array length.*/
	if (! fscanf(file, "%d", length))
	{
		return 0;
	}
	/*Allocate array space, read the array elements, and return. If an error
	occurs free the allocated space and return a null pointer.*/
	ret = tcalloc(*length, sizeof(double));
	for (i = 0; i < *length; i++)
	{
		if (! fscanf(file, "%lf", ret + i))
		{
			free(ret);
			return 0;
		}
	}
	return ret;
}

matrix ReadMatrix(FILE* file)
{
	int* data;
	int rows, cols, i;
	matrix Ret;
	/*Zero the matrix initially. An empty matrix will be the rror return value.*/
	AllocateMatrix(&Ret, 0, 0);
	
	/*Read matrix size.*/
	if (fscanf(file, "%d %d", &rows, &cols) != 2)
	{
		return Ret;
	}
	/*Allocate space for and read a 1D array containing all the elements by row.*/
	data = tcalloc(rows * cols, sizeof(int));
	for (i = 0; i < rows * cols; i++)
	{
		if (! fscanf(file, "%d", data + i))
		{
			free(data);
			return Ret;
		}
	}
	/*Use vector2matrix to convert the 1D array into a matrix.*/
	Ret = vector2matrix(data, rows, cols);
	free(data);
	return Ret;
}

int FindParameter(char* Name, Parameter* Param, int ParamCount)
{
	int i;
	char* start;
	/*Search the parameter list for a parameter with the given name.*/
	for (i = 0; i < ParamCount; i++)
	{
		if (! strcmp(Name, Param[i].Name))
		{
			return i;
		}		
	}
	/*If no such parameter is found, return a -1.*/
	return -1;
}

/*ParseDescription parses the given data description string and fills the 
Param array of parameters with corresponding parameter structures. It returns
the number of parameters found, and fills the integer pointed to by Items with
the number of parameters to expect in the variable-length parameter list in
ParseStructure.*/
int ParseDescription(MemoryManager* memory, char* DataDescription, Parameter** Param, int* Items)
{
	char Description[256];	
	char* Token;
	char Type[32];
	char Type2[33];
	char Name[32];
	int ToAdd;
	int TokenCount = 0;
	(*Param) = 0;
	(*Items) = 0;
	strcpy(Description, DataDescription);
	
	/*Tokenize the string around commas, the delimiters.*/
	Token = strtok(Description, ",");
	if (Token)
	{
		do
		{
			/*Reac the parameter type and name strings.*/
			if (sscanf(Token, "%s %s", Type, Name) == 2)
			{
				/*For search purposes, get a copy of the type string and add a space to
				the end.*/
				strcpy(Type2, Type);
				strcat(Type2, " ");
				ToAdd = 0;
				/*If the type is a matrix, int, double, or string, then only one item
				should be expected in the parameter list corresponding to this parameter.*/
				if (strstr("matrix int double string ", Type2))
				{
					ToAdd = 1;
				}
				/*If the type is an array type, there will be two items in 
				ParseStructure's parameter list: the array pointer and the pointer to 
				the integer destined to hold the array length.*/
				else if (strstr("arrayi arrayd indexarray ", Type2))
				{
					ToAdd = 2;
				}
				/*If the type is an array of arrays, there will be three items in 
				ParseStructure's parameter list: the array pointer, the array of counts
				pointer, and the pointer to the integer destined to hold the overall 
				count.*/
				else if (! strcmp("arraya ", Type2))
				{
					ToAdd = 3;
				}
				/*If the parameter was recognized...*/
				if (ToAdd)
				{
					/*If the parameter has not already been defined...*/
					if (FindParameter(Name, (*Param), TokenCount) >= 0)
					{
						/*If it has, empty the list and fail.*/
						free(*Param);
						merror(0, "PARSE/DISPLAYSTRUCTURE: Data description containts duplicate item names");
						return 0;
					}					
					/*Add a new element to the array of parameter description structures
					and fill in its members.*/
					(*Param) = realloc(*Param, (TokenCount + 1) * sizeof(Parameter));
					(*Param + TokenCount)->Name = mcalloc(memory, strlen(Name) + 1, sizeof(char));
					strcpy((*Param + TokenCount)->Name, Name);
					(*Param + TokenCount)->Type = mcalloc(memory, strlen(Type) + 1, sizeof(char));
					strcpy((*Param + TokenCount)->Type, Type);
					/*Start indicates which element in a variable-length parameter list 
					will be the first element corresponding to this parameter. It has
					to be adjusted separately from TokenCount because some parameters
					need multiple elements in the parameter list.*/
					(*Param + TokenCount)->Start = *Items;
					TokenCount++;
					(*Items) += ToAdd;
				}
				else
				{
					/*If we get here the parameter type was not recognized. Fail.*/
					free(*Param);
					merror(0, "PARSE/DISPLAYSTRUCTURE: Bad data description type");
					return 0;
				}				
			}
			else
			{
				/*If we get here there were problems reading the description group (a 
				single comma-surrounded token from the original data description). 
				Fail.*/
				free(*Param);
				printf("Warning: Bad Data Description Group '%s %s'.\n", Type, Name);
				merror(0, "PARSE/DISPLAYSTRUCTURE: Bad data description group");
				return 0;
			}
		} while (Token = strtok(0, ","));
		/*Add the parameter structure array to the list of memory to be freed later.*/
		ManageMemory(memory, *Param);
		return TokenCount;
	}
	else
	{
		/*If there was an error tokenizing the string, return 0.*/
		return 0;
	}
}

/*ReadArrayA takes as its third parameter a pointer to the array
pointer destined to hold the array of arrays, as its fourth parameter
a pointer to the array pointer destined to hold a count of the number
of elements in each subarray, and as its fifth parameter a pointer to
the number of arrays.*/
int ReadArrayA(FILE* file, MemoryManager* mem, int*** array, int** arraycount, int* count)
{
	int i;
	/*Arrays of arrays will be formatted thus:
	Number of arrays
	Array0Length Array0Contents
	Array1Length Array1Contents
	...*/
	/*Try to read the number of arrays. If successful, allocate space for the
	array of arrays and for the array of counts.*/
	if (! fscanf(file, "%d", count)) return 0;
	*arraycount = mcalloc(mem, *count, sizeof(int));
	*array = mcalloc(mem, *count, sizeof(int**));
	/*Read all the arrays.*/
	for (i = 0; i < *count; i++)
	{		
		/*Attempt to read the array. On success (indicated by a non-null pointer),
		manage the memory for the array.*/
		if ((*array)[i] = ReadIntArray(file, (*arraycount) + i))
		{
			ManageMemory(mem, (*array)[i]);
		}
		/*On failure, fail.*/
		else
		{
			return 0;
		}
	}
	return 1;
}

void TrimWhitespace(char* string)
{
	int test, flag = 0;
	/*Remove leading whitespace.*/
	for (test = 0; test <= strlen(string); test++)
	{
		if (! (flag || isspace(string[test])))
		{
			flag = test;
		}
		if (flag)
		{
			string[test - flag] = string[test];
		}
	}
	/*Remove trailing whitespace.*/
	for (test = strlen(string) - 1; test >= 0; test--)
	{
		if (! isspace(string[test]))
		{
			break;
		}
	}
	string[test + 1] = '\0';
}

/*This is called when the user makes a help request.*/
void Help(char* helpstring, Parameter* Param, int ParamCount)
{
	/*If the help string is empty or a null pointer, display the parameter help.*/
	if ((! helpstring) || strlen(helpstring) == 0)
	{
		printf("This program uses the Structured IO routines. These routines allow a\n");
		printf("test problem or other group of data to be entered in a human-readable\n");
		printf("format. Data for each problem is entered as a series of keywords,\n");
		printf("corresponding to variables used for the problem. Each keyword is followed\n");
		printf("by the data that will fill that variable. There are also predefined\n");
		printf("keywords that control the IO routines themselves.\n\n");
		printf("Keywords and types used in this program are shown below. For information\n");
		printf("about a specific data type, such as how to enter data of that type, enter\n");
		printf("\"help typename\". For information about one of the predefined keywords,\n");
		printf("enter \"help keyword\".\n");
		printf("Predefined keywords: echo, rem, help, done, quit\n");
		printf("Program-defined keywords:\n");
		/*Print keywords and types.*/
		int i;
		char* typestring;
		for (i = 0; i < ParamCount; i++)
		{
			if (! strcmp(Param[i].Type, "matrix")) typestring = "matrix";
			if (! strcmp(Param[i].Type, "arrayi")) typestring = "integer array";
			if (! strcmp(Param[i].Type, "arrayd")) typestring = "double array";
			if (! strcmp(Param[i].Type, "arraya")) typestring = "array of arrays";
			if (! strcmp(Param[i].Type, "indexarray")) typestring = "integer array";
			if (! strcmp(Param[i].Type, "int")) typestring = "integer";
			if (! strcmp(Param[i].Type, "double")) typestring = "double";
			if (! strcmp(Param[i].Type, "string")) typestring = "string";
			printf("\"%s\" of type \"%s\".\n", Param[i].Name, typestring);
		}
	}
	else if (! strcmp(helpstring, "echo"))
	{
		printf("echo: Predefined keyword. Upon encountering an echo request, the program\n");
		printf("reads the remainder of the line and prints it to the console output. Used\n");
		printf("primarily with scripts.\n");
	}
	else if (! strcmp(helpstring, "rem"))
	{
		printf("rem: Predefined keyword. Any line beginning with the rem keyword is\n");
		printf("ignored. Used for comments in scripts.\n");
	}
	else if (! strcmp(helpstring, "help"))
	{
		printf("help: Predefined keyword. The remainder of the line is read. If the line\n");
		printf("is empty, displays the general help and list of keywords. If the line\n");
		printf("contains a predefined keyword or a type name, help on that item is\n");
		printf("displayed. Note there is no built-in help for program-defined keywords.\n");
	}
	else if (! strcmp(helpstring, "done"))
	{
		printf("done: Marks the end of a set of input data. The IO routines parse data\n");
		printf("in sets, where each set is the data for a problem. When this keyword is\n");
		printf("encountered, the IO routines return control to the main program so that\n");
		printf("the data can be processed. Note that \"done\" must be used before any\n");
		printf("data is processed. If the quit keyword or an error is encountered before\n");
		printf("\"done\", none of that set of data will be processed.\n");
	}
	else if (! strcmp(helpstring, "quit"))
	{
		printf("quit: predefined kewyword. Marks the end of problems. The IO routines\n");
		printf("return control to the main program and allow it to shut down when this\n");
		printf("keyword is encountered. Note that any data that has not been marked for\n");
		printf("processing via a \"done\" keyword at the time this keyword is encountered\n");
		printf("will never be processed.\n");
	}
	else if (! strcmp(helpstring, "matrix"))
	{
		printf("matrix: data type. To enter data of type matrix, specify the keyword for the\n");
		printf("data being entered, followed by the number of rows, followed by the number of\n");
		printf("columns, followed by each element of the array.\n");
		printf("All the values should be separated by whitespace (spaces, tabs, newlines, etc.)\n"); 
		printf("The kind or amount of whitespace is irrelevant. This allows the user to enter\n");
		printf("the data in a visually pleasing manner.\n");
		printf("Example usage: Filling a matrix with keyword 'M' with a 3 x 3 identity:\n");
		printf("M 3 3\n");
		printf("1 0 0\n0 1 0\n0 0 1\n");
	}
	else if (! strcmp(helpstring, "integer array"))
	{
		printf("integer array: data type. An array of integers. To enter data, specify\n");
		printf("the keyword for the data, followed by the number of elements in the\n");
		printf("array, followed by each element of the array.\n");
		printf("All the values should be separated by whitespace (spaces, tabs, newlines, etc.)\n"); 
		printf("The kind or amount of whitespace is irrelevant. This allows the user to enter\n");
		printf("the data in a visually pleasing manner.\n");
		printf("Example usage: Filling an integer array with keyword 'A' with a sequence of 3:\n");
		printf("A 3\n1 2 3\n");
	}
	else if (! strcmp(helpstring, "double array"))
	{
		printf("double array: data type. An array of doubles (floating-point or decimal\n");
		printf("numbers. To enter, give the keyword followed by the number of elements in\n");
		printf("the array followed by each element of the array.\n");
		printf("All the values should be separated by whitespace (spaces, tabs, newlines, etc.)\n"); 
		printf("The kind or amount of whitespace is irrelevant. This allows the user to enter\n");
		printf("the data in a visually pleasing manner.\n");
		printf("Example usage: Filling a double array with keyword 'A' with a sequence\n");
		printf("of 4 elements counting by 0.25:\n");
		printf("A 4\n0.25 0.5 0.75 1\n");
	}
	else if (! strcmp(helpstring, "array of arrays"))
	{
		printf("array of arrays: data type. An array each element of which is itself an\n");
		printf("array. To enter, give the keyword followed by the number of arrays\n");
		printf("followed by each array. Each array should be entered as the number of\n");
		printf("elements in the array followed by the elements of the array. array of\n");
		printf("arrays only accepts integral numbers, not floating-point (decimal).\n");
		printf("All the values should be separated by whitespace (spaces, tabs, newlines, etc.)\n"); 
		printf("The kind or amount of whitespace is irrelevant. This allows the user to enter\n");
		printf("the data in a visually pleasing manner.\n");
		printf("Example usage: Filling an array of arrays with keyword AROA with 3 arrays,\n");
		printf("The first containing the elements [1, 2, 3], the second containing [4, 5],\n");
		printf("and the third containing only one element, [6]:\n");
		printf("AROA 3\n3 1 2 3\n2 4 5\n1 6\n");
	}
	else if (! strcmp(helpstring, "string"))
	{
		printf("string: data type. This is just a piece of text up to 127 characters long.\n");
		printf("To enter, give the keyword followed by the text on the same line. The rest\n");
		printf("of the line will be read, leading and trailing whitespace will be removed\n");
		printf("and what is left is the text.\n");
		printf("Example usage: Filling a string with keyword 's' with the text \"hello world\":\n");
		printf("s hello world\n");
	}
	else if (! strcmp(helpstring, "integer"))
	{
		printf("integer: data type. A single integer. To enter, give the keyword followed by\n");
		printf("the value.\n");
		printf("Example usage: Filling an integer with keyword 'i' with the value 4:\n");
		printf("i 4\n");
	}
	else if(! strcmp(helpstring, "double"))
	{
		printf("integer: data type. A single double (floating point or decimal number). To\n");
		printf("enter, give the keyword followed by the value.\n");
		printf("Example usage: Filling double with keyword 'd' with the value 3.14159:\n");
		printf("d 3.14159\n");
	}
	else
	{
		printf("Unrecognized help request. Type \"help\" on a line by itself to see the\n");
		printf("general help.\n");
	}
	printf("\n");
}
