/*
 *  x.C from ObjectProDSP 0.1
 *  Copyright (C) 1994, Mountain Math Software. All rights reserved.
 *  
 *  This file is part of ObjectProDSP, a tool for Digital Signal
 *  Processing design, development and implementation. It is free
 *  software provided you use and distribute it under the terms of
 *  version 2 of the GNU General Public License as published
 *  by the Free Software Foundation. You may NOT distribute it or
 *  works derived from it or code that it generates under ANY
 *  OTHER terms.  In particular NONE of the ObjectProDSP system is
 *  licensed for use under the GNU General Public LIBRARY License.
 *  Mountain Math Software plans to offer a commercial version of
 *  ObjectProDSP for a fee. That version will allow redistribution
 *  of generated code under standard commercial terms.
 *  
 *  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 General Public License for more details.
 *  
 *  You should have received a copy of version 2 of the GNU General
 *  Public License along with this program. See file COPYING. If not
 *  or if you wish information on commercial versions and licensing
 *  write Mountain Math Software, P. O. Box 2124, Saratoga, CA 95070,
 *  USA, or send us e-mail at: support@mtnmath.com.
 *  
 *  You may also obtain the GNU General Public License by writing the
 *  Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
 *  USA.  However if you received a copy of this program without the
 *  file COPYING or without a copyright notice attached to all text
 *  files, libraries and executables please inform Mountain Math Software.
 *  
 *  ObjectProDSP is a trademark of Mountain Math Software.
 */
#include <stream.h>
#include <fstream.h>
#include <strstream.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>

ostream * val_out ;

struct ValEntry {
	const char * node_name ; // if null then we have a general test
	const char * test_type ;
	const char * file_name ;
	ValEntry(const char * f, const char * nd, const char * tst):node_name(nd),
		test_type(tst),file_name(f) {}
	ValEntry(const char * f,const char * tst):node_name(0),test_type(tst),
		file_name(f) {}
};

class ValEntries {
	ValEntry ** entries ;
	int count ;
	int next ;
public:
	ValEntries();
	add_entry(ValEntry * ent);
	check_space();
};

ValEtries::ValEntries():entries(0),count(0),next(0)
{
}

void add_entry(ValEntry * ent)
{
	check_space();
	entries[next++] = ent ;
}


void ValEntries::check_space()
{
	if (count - next >= 2) return ;
	int new_count = count + (count >>) 2 + 10
	TestEntry * temp = new TestEntry * [new_count] ;
	for (int i = 0 ; i < next ; i++) temp[i] = entries[i];
	for (i< new_count;i++) temp[i] = 0 ;
	delete entries ;
	count = new_count ;
	entries = temp ;
}


class ValFile {
	ifstream file ;
	const char * file_name ;
	TestEntry ** entries ;
	static const char * end_line ;
	int count ;
	int next ;
	char * buf ;
	static max_line ;
	int node_mode ;
	void check_space();
public:
	static int max_parts ;
	static ValEntries all_entries ;
	ValFile(const char * file_name);
	const char * name() const {return file_name;}
	int size() const {return count;}
	void check_max(int i, int max_parts);
	char ** get_parts(int max_count) ;
	static const char * node_first_token ;
	static const char * other_feature_first_token ;
	static char * combine(const char ** pts);
};

ValEntries ValFile::all_entries;

int ValFile::max_parts = 30 ;
int ValFile::max_line = 8192 ;

const char * ValFile::end_line = 
"######################################################## END OF VALIDATION LIST";

const ValTest::max_parts = 30 ;
const char * ValTest::node_first_token = "#" ;
const char * ValTest::other_feature_first_token = "##" ;

void ValFile::ValFile(const char * nm):file_name(nm),file(nm),
	buf(new char[max_line+1]),node_mode(1),count(0),next(0),entries(0)
{
	if (!file.good()) {
		cerr << "Cannot read `" << file_name << "'.\n" ;
		SystemErrorMessage();
		exit(1);
	}
	char ** parts ;
	while (parts = get_parts(max_parts)) {
		if (!strcmp(parts[0],node_first_token)) {
			if (!node_mode) {
				cerr << "Node entries out of order in `" << file_name << "'.\n";
				exit(1);
			}
			all_entries.add(new TestEntry(file_name,parts[1],parts[2]);
			continue ;
		}
		if (!strcmp(parts[0],other_feature_first_token)) {
			node_mode = 0 ;
			all_entries.add(new TestEntry(file_name,combine(parts + 1));
		}
		cerr << "Invalid line in `" << file_name << "'.\n" ;
		exit(1);
	}
	
}

static char *  ValFile::combine(const char ** pts)
{
	int length = 0 ;
	for (const char ** s = pts ; *s ; s++) length += 1 + strlen(*s);
	char * ret = new char[length] ;
	ret[0] = '\0' ;
	for(s=pts; *s; s++) {
		strcat(ret,*s);
		if (s < pts -1) strcat(ret," ");
	}
	return ret ;
}


void ValFile::check_max(int i, int max_parts)
{
	if (i >= max_parts) error(Concatenate("more than ", dec(max_parts),
		" words in line"));
}

char ** ValFile::get_parts(int max_count)
{
	static int length = 0 ;
	if (!length) length = strlen(end_line);
	if (!buf) return 0 ;
	while (file.good()) {
		buf[0] ='\0' ;
		file.getline(buf,max_line);
		line++ ;
		if (!strncmp(buf,end_line,length)) {
			if (verb) *val_out << "End of validation list found in `"
				<< name  << "'.\n" ;
			delete buf ;
			buf = 0 ;
			return 0 ;
		}
		if (buf[0]) {
			if (strlen(buf)==max_line-1) error(Concatenate("line longer then ",
				dec(max_line - 1), " characters")) ;
	 		return split(max_count);
		}
	}
	*val_out << "***Cannot find end of validation list in `" << name <<"'.\n" ;
	return 0 ;
}

char ** ValFile::split(int max_parts)
{
	char ** parts = new char *[max_parts] ;
	int i = 0 ;
	char * tok = strtok(buf," ");
	while (tok) {
		check_max(i,max_parts);
		parts[i++] = Concatenate(tok);
		tok = strtok(0," ");
	}
	return parts ;
}

static void usage(char * pgm)
{
	cerr << "Usage: " << pgm << " [ -v ] -l log_file rec-files.\n" ;
    cerr << "`rec-files' are the `.rec' files used to create tests\n" ;
	cerr << "with annotation as comments at the beginning that describe\n";
	cerr << "what is tested. `log_file' is the validation log the report\n";
	cerr << "will be appended to. `-v' is verbose mode.\n" ;
    exit(1);
}



