#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include <errno.h>
#include <locale.h>
#include <string.h>

static char mapfile[256];
static char after_depend[100];

static void
input_extra_header_to_mapfile(char *name, FILE *fp1) {
	FILE *tmp;
	char buf[256];
	if(((tmp=fopen(name,"r"))!=NULL) || ((tmp=fopen("default.hdr","r"))!=NULL)) {
		rewind(tmp);
		while ( fgets(buf, 256, tmp)) {
			(void)fprintf(fp1,"%s", buf);
		}
	} else {
		(void)fprintf(stderr,"<lang>.hdr or default.hdr header file for mapfile not found\n");
		exit(-1);
	}
}

static void 
create_mapfile( char *infile) {
	FILE *fp, *fp1;
	char buf[256];
	char *t;
	int put_space=1;
	char *b, *lang;
	char e[256];
	long l1=0;


	(void)sprintf(mapfile,"%s.%s",infile,"mapfile");
	fp = fopen(infile,"r");
	fp1= fopen(mapfile,"w");
	rewind(fp);
	(void)strcpy(e,mapfile);
	lang=(char *)strchr(e,'.');
	if(lang) {
		*lang='\0';
		(void)strcat(e,".hdr");
	} 
	input_extra_header_to_mapfile(e,fp1);
	while ( fgets(buf, 256, fp)) {
		if ((t=(char *)strtok(buf, " \t"))!= NULL) {
			if ((*t) == '#' || (*t) == '%') continue;
			b=(char*)strdup(t);
			if(strcmp(b,"special_midword_consonant\n")==0)
				put_space=0;
			else if(strcmp(b,"vowel\n")==0)
				put_space=1;
			(void)fprintf(fp1,"%s", b);
			if((t=(char *)strtok(NULL," \t"))!=NULL) {
				b=(char*)strdup(t);
				l1=strtol(t,(char**)NULL, 16);
				if(l1) {
					(void)fprintf(fp1,"		");
					(void)fputwc(l1, fp1);
					l1=strtol(t,(char**)NULL, 16);
				} 
				if ((t=(char *)strchr(b,','))!=NULL)  (void)fprintf(fp1," ");
				while ((t=(char *)strtok(NULL," \t"))!=NULL) {
					if(put_space)
						(void)fprintf(fp1,"		");
					l1=strtol(t,(char**)NULL, 16);
					if(l1) (void)fputwc(l1, fp1);
				}
				(void)fprintf(fp1,"\n");
			}
		}	
	}
	(void)fclose(fp);
	(void)fclose(fp1);
}

static void
usage(char *prog) {
	(void)fprintf(stderr,"Usage: %s [-c lang.ucs]/[utf-8 map file]\n", prog);
	exit(-1);
}

static void
check_special_midword_consonant(FILE *in) {
	char buf[256];
	char *t;
	rewind(in);
	while ( fgets(buf, 256, in)) {
		if ((t=(char *)strtok(buf, " \t\n"))!= NULL) {
			if(strcmp(t,"special_midword_consonant")==0) {
				(void)strcpy(after_depend,"special");
				return;
			}
		}
	}
	(void)strcpy(after_depend,"INITIAL");
}
static void
output_token_rules(FILE *mapp, FILE *outp) {
	char buf[256];
	int gen_flag=0;
	char *t, *b, *c;

	rewind(mapp);
	while ( fgets(buf, 256, mapp)) {
		if ((t=(char *)strtok(buf, " \t\n"))!= NULL) {
			b=(char*)strdup(t);
			if(strncmp(b,"virama", 6)==0) {
				gen_flag=0;
				continue;
			} else if ((strcmp(b,"other")==0) || (strcmp(b,"special_other")==0)) {
				gen_flag=1;
				continue;
			} else if ((strcmp(b,"vowel")==0) || (strcmp(b,"special_vowel")==0)) {
				gen_flag=2;
				continue;
			} else if ((strcmp(b,"consonant")==0) || (strcmp(b,"special_consonant")==0)) {
				gen_flag=3;
				continue;
			} else if ((strcmp(b,"digit")==0) || (strcmp(b,"special_digit")==0)) {
				gen_flag=4;
				continue;
			} else if ((strcmp(b,"special_midword_consonant")==0)) {
				gen_flag=5;
				continue;
			}
			if ((t=(char *)strtok(NULL," \t\n"))==NULL)
				t = (char*)strdup("");
			if(gen_flag==1)
				(void)fprintf(outp,"%s		{ (void)strcpy(lang_str,\"%s\"); return(OTHER); }\n", b, t);
			else if(gen_flag==2) {
				c=(char *)strtok(NULL," \t\n");
				if(!c) c=(char *)strdup("");
				(void)fprintf(outp,"<depend>%s	{ BEGIN %s; (void)strcpy(lang_str,\"%s\"); return(DEP_VOWEL); }\n", b, after_depend, c);
				(void)fprintf(outp,"%s		{ (void)strcpy(lang_str,\"%s\"); return(INDEP_VOWEL); }\n", b, t);
			} else if(gen_flag==3) {
				(void)fprintf(outp,"%s		{ BEGIN depend; (void)strcpy(lang_str,\"%s\"); return(CONS); }\n", b, t);
			} else if(gen_flag==4) {
				(void)fprintf(outp,"%s		{ (void)strcpy(lang_str,\"%s\"); return(DIGIT); }\n", b, t);
			} else if(gen_flag==5) {
				(void)fprintf(outp,"<depend,special>%s	{ BEGIN depend; (void)strcpy(lang_str,\"%s\"); return(CONS); }\n", b, t);
			}
		}
	}
}
static void
output_virama(FILE *mapp, FILE *outp) {
	char buf[256];
	int virama_found=0;
	int has_half_form=0;
	char *t, *b;

	rewind(mapp);
	while ( fgets(buf, 256, mapp)) {
		if ((t=(char *)strtok(buf, " \t\n"))!= NULL) {
			b=(char*)strdup(t);
			if(!has_half_form && strncmp(b,"has_half_form",13)==0) {
				has_half_form=1;
			}
			if(!virama_found && strncmp(b,"virama", 6)==0) {
				virama_found=1;
				continue;
			} else if (virama_found) {
				if((t=(char *)strtok(NULL," \t\n"))!=NULL) {
					(void)fprintf(outp,"#define VIRAMA_CHAR 	\"%s\"\n",t);
				} else  {
					(void)fprintf(stderr,"Incomplete virama mapping in map file\n");
					exit(-1);
				}	
				virama_found=0;
			}	
		}
	}
	(void)fprintf(outp,"#define HAS_HALF_FORM 	%d\n", has_half_form);
}
	
static void
fill_in_lex_skeleton(char *skel_file, char *map_file) {
	FILE *fp, *fp1, *outfp;
	char *b, *e, *lang;
	char buf[256];
	char dbuf[256];
	char lexsource[128];
	char *t;
	int sect_over=0;

	fp = fopen(skel_file,"r");
	fp1= fopen(map_file,"r");
	if(!fp) {
		(void)fprintf(stderr,"Skeleton file lex.skel does not exist\n");
		exit(-1);
	}
	e=(char *)strdup(map_file);
	lang=(char *)strchr(e,'.');

	if(!lang) {
		(void)sprintf(lexsource,"%s%s.merged",map_file, skel_file);
	} else {
		*lang='\0';
		(void)sprintf(lexsource,"%s.l",e);
	}

	outfp= fopen(lexsource,"w");
	rewind(fp);
	while ( fgets(buf, 256, fp)) {
		(void)strcpy(dbuf, buf);
		if ((t=(char *)strtok(buf, " \t\n"))!= NULL) {
			b=(char*)strdup(t);
			if(strcmp(b,"#define")==0) {
				if((t=(char *)strtok(NULL," \t"))!=NULL) {
					if(strcmp(t,"VIRAMA_CHAR")==0)
						output_virama(fp1,outfp);
					else
						(void)fputs(dbuf,outfp);
				}
			} else if (strcmp(b,"%%")==0 && !sect_over) {
				sect_over=1;
				(void)fputs(dbuf,outfp);
				check_special_midword_consonant(fp1);
				output_token_rules(fp1,outfp);
				(void)fprintf(outfp,"{space}|\\n	{ BEGIN INITIAL; return(WORD_START); }\n");
				(void)fprintf(outfp,"[a-zA-Z]		{ return(ALPHA_NOT_MAPPED); }\n");
				(void)fprintf(outfp,".		{ BEGIN INITIAL; return(NOT_MAPPED); }\n");
			} else {
				(void)fputs(dbuf,outfp);
			}
				
		}
	}
}

int 
main(int argc, char *argv[]) {

  /*
	locale=setlocale(LC_ALL,"");
	if(strstr(locale,"UTF-8")==NULL) {
		(void)fprintf(stderr,"Invoke the program %s in a UTF-8 locale\n", argv[0]);
		exit(-1);

	}
  */
	if(!argv[1]) {
		usage(argv[0]);
	} else if (argv[1][0]=='-') {
		if(argv[1][1]=='c' && argv[2] )
			create_mapfile(argv[2]);
		else
			usage(argv[0]);
	} else {
		(void)strcpy(mapfile,argv[1]);
	}

	fill_in_lex_skeleton("lex.skel", mapfile );
	return(0);
}
