#include <fstream.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "ObjProGen/cpyrght_exe.h"


class Names {
	int the_size ;
	const char ** list ;
public:
	Names(int);
	int set(int, const char *);
	const char * get(int);
	int size() {return the_size;}
};

class MakeMake {
	Names& help ;
	Names& examp ;
	Names& node ;
	ofstream& out ;

	void all_tex();
	void all_help();
	void make_help_kernel(const char * target, const char * source);
	void make_help_examp(const char * name);
	void make_help();
	void make_tex();
public:
	MakeMake(Names& h, Names& n, Names& e,ofstream& o):help(h),examp(e),out(o),node(n){}
	void write();
};
	
Names::Names(int n):
	the_size(n)
{
	list = new char *[the_size+1];
	for (int i = 0 ; i < the_size+1;i++) list[i] = 0 ;
}

void MakeMake::all_tex()
{
	out << "ALL_TEX : RM_TEX_ERR \\\n" ;
	for (int i = 0 ; i < node.size(); i++) 
		out << "\t${NODE_TEX}/" << node.get(i) << ".tex \\\n" ;
	for (i = 0 ; i < help.size(); i++) 
		out << "\t${HELP_TEX}/" << help.get(i) << ".tex \\\n" ;
	for (i = 0 ; i < examp.size(); i++) {
		out << "\t${EXAMP_TEX}/" << examp.get(i) << ".tex" ;
		if (i < examp.size() -1) out << " \\\n" ;
	}
	out << "\n\n" ;
}

void MakeMake::all_help()
{
	out << "ALL_HELP : RMERR \\\n" ;
	for (int i = 0 ; i < node.size(); i++) {
		out << "\t${HELP}/" << node.get(i) + 1 << ".hlp \\\n" ;
	}
	for (i = 0 ; i < help.size(); i++) {
		out << "\t${HELP}/" << help.get(i) + 1 << ".hlp \\\n" ;
	}
	 for (i = 0 ; i < examp.size(); i++) {
		out << "\t${HELP}/" << examp.get(i) << ".hlp" ;
		if (i != examp.size()-1) out << " \\\n" ;
	}
	out << "\n\n" ;
}

void MakeMake::make_help_kernel(const char * target, const char * source)
{
		out << "${HELP}/" << target << ".hlp : " << source  << ".roff" ;
		if (strcmp(target,source)) out << "\n" ;
		else out << " ${EXAMP}/" << source << ".xml\n" ;
		const char * mkhlp = "${OPD_ROOT}/doc/scripts/mkhlp.sh" ;
		if ('T' == target[strlen(target)-1])
			mkhlp = "${OPD_ROOT}/doc/scripts/tmkhlp.sh" ;
		out << "\t${OPD_SHELL} " << mkhlp << " ${HELP}/" << target << ".hlp ${ROFF}/"
			<< source << ".roff\n" ;
}

void MakeMake::make_help_examp(const char * name)
{
/*
 *	out <<
 * "\techo \"       Following is the DSP++ code for this example:\\n\" >> \\\n"
 *	<<		"\t\t${HELP}/" << name << ".hlp\n" ;
 */
	out<<"\tperl ${OPD_ROOT}/doc/scripts/padcat.pl ${EXAMP}/"<<name << ".xml >> ${HELP}/" << name << ".hlp\n\n" ;
}

void MakeMake::make_help()
{
	for (int i = 0 ; i < help.size(); i++) {
		make_help_kernel(help.get(i)+1, help.get(i));
		out << "\n" ;
	}
	for (i = 0 ; i < node.size(); i++) {
		make_help_kernel(node.get(i)+1, node.get(i));
		out << "\n" ;
	}
	for (i = 0 ; i < examp.size(); i++) {
		make_help_kernel(examp.get(i), examp.get(i));
		make_help_examp(examp.get(i));
	}
}

static const char * mktex = "${OPD_ROOT}/doc/scripts/mktex.sh" ;

void MakeMake::make_tex()
{
	for (int i = 0 ; i < help.size(); i++) {
		out << "${HELP_TEX}/" << help.get(i) << ".tex : ${ROFF}/" <<
			help.get(i) << ".roff\n" ;
		out << "\t${OPD_SHELL} " << mktex << " ${ROFF}/" << help.get(i) <<
			".roff -w ${HELP_TEX}\n\n";
	}
	for (i = 0 ; i < node.size(); i++) {
		out << "${NODE_TEX}/" << node.get(i) << ".tex : ${ROFF}/" <<
			node.get(i) << ".roff\n" ;
		out << "\t${OPD_SHELL} " << mktex << " ${ROFF}/" << node.get(i) <<
			".roff -w ${NODE_TEX}\n\n";
	}

	for (i = 0 ; i < examp.size(); i++) {
		const char * nm = examp.get(i) ;
		out << "${EXAMP_TEX}/" << nm << ".tex : " << "${ROFF}/" << nm <<
			".roff ${EXAMP}/" << nm << ".xml\n" ;
		out << "\t${OPD_SHELL} " << mktex << " ${ROFF}/" << nm << ".roff -w ${EXAMP_TEX}\n" ;
		out << "\techo >> $@\n" ;
		out << "\techo \"This is the \\Dpp{} program for this example.\" >> $@\n" ;
		out << "\techo >> $@\n" ;
		out << "\techo \"\\begin{verbatim}\" >> $@\n" ;
		// out << "\tcat examp.hd >> ${EXAMP_TEX}/" << nm << ".tex\n" ;
		out << "\tcat ${EXAMP}/" << nm << ".xml >> $@\n" ;
		// out << "\tcat examp.tl >> $@\n\n" ;
		out << "\techo \"\\end{verbatim}\" >> $@\n" ;
	}
}


void MakeMake::write()
{
	all_tex();
	all_help();
	make_help();
	make_tex();
}


const char * Names::get(int i)
{
	if (i < 0 || i >= the_size) {
		cerr << "Names::get bad index\n" ;
		exit(1);
	}
	if (!list[i]) {
		cerr << "Names::get not set\n" ;
		exit(1);
	}
	return list[i] ;
}

int Names::set(int j,const char * str)
{
	if (*str == '#') return 0 ;
	if (isspace(*str)) return 0 ;
	if (j < 0 || j >= the_size) {
		cerr << "Names::set bad index\n" ;
		exit(1);
	}
	if (list[j]) {
		cerr << "Names::set alread set\n" ;
		exit(1);
	}
	char * c = new char[strlen(str)+1];
	list[j] = c ;
	strcpy(c,str);
	for (char * pt = c; *pt; pt++) if (*pt == '#' || isspace(*pt)) {
		*pt = '\0' ;
		break ;
	}
	return 1 ;
}

int read_names(const char * file_name, Names * names=0)
{
	const buf_size = 1024 ;
	char buf[buf_size] ;
	ifstream file_list(file_name);
	int limit = 1000000 ;
	// if (names) limit = names->size();
	int name_count = 0 ;
	for(int count=0;count < limit;count++) {
		buf[0] = '\0'; ;
		file_list.get(buf,buf_size);
		if (buf[0]) {
			if (names) names->set(name_count,buf);
			if ((!isspace(buf[0])) && (buf[0] != '#')) name_count++ ;
		}
		if (!file_list.good()) break ;
		char eol ;
		file_list.read(&eol,1) ;
		if (eol != '\n') cerr << "Line terminated with `" << eol << "' (" <<
			(int) eol << ").\n" ;
	}
	if (names) {
		if (name_count != names->size()) {
			cerr << name_count << " " << names->size() << "\n" ;
			cerr << "Did not finish file.\n" ;
			exit(1);
		}
		file_list.get(buf,buf_size);
	}
	if (file_list.good()) {
		cerr << "File not completed.\n" ;
		exit(1);
	}
	return name_count ;
}

void copy_base(const char * in, ofstream& file_out)
{
	const buf_size = 1024 ;
	char buf[buf_size] ;
	ifstream file_in(in);
	if (!file_in.good()) {
		cerr << "Cannot read `" << in << "'.\n" ;
		exit(1);
	}
	for(;;) {
		file_in.get(buf,buf_size);
		if (!file_in.good()) break ;
		file_out << buf << "\n" ;
		if (!file_out.good()) {
			cerr << "Output error.\n" ;
			exit(1);
		}
		char eol ;
		file_in.read(&eol,1);
		if (eol != '\n') cerr << "Line terminated with `" << eol << "' (" <<
			(int) eol << ").\n" ;
	}
}

main()
{
	ofstream file_out("makefile_out");
	if (!file_out.good()) {
		cerr << "Output error.\n" ;
		exit(1);
	}
	file_out << "#  Makefile created using --\n" ;
	copy_base("Makefile.base",file_out);

	const char * help_input = "help_list" ;
	const char * examp_input = "examp_list" ;
	const char * node_input = "node_list" ;

	Names help_names(read_names(help_input));
	read_names(help_input,&help_names);

	Names examp_names(read_names(examp_input));
	read_names(examp_input,&examp_names);

	Names node_names(read_names(node_input));
    read_names(node_input,&node_names);

	MakeMake make_make(help_names,node_names,examp_names,file_out);

	make_make.write();
}
