/**********************************************************************
	"Copyright 1990-2026 Brian MacWhinney. Use is subject to Gnu Public License
	as stated in the attached "gpl.txt" file."
*/


#include "ced.h"
#include "cu.h"
#ifdef _WIN32 
	#include "stdafx.h"
#endif

#if !defined(UNX)
#define _main temp_main
#define call temp_call
#define getflag temp_getflag
#define init temp_init
#define usage temp_usage
#endif

#include "mul.h" 

#define IS_WIN_MODE FALSE
#define CHAT_MODE 0

#define TAGSLEN   128
#define CODESLEN  1024

struct SpRec {
	char isUsed;
	char oldSp[TAGSLEN];
	char newSp[TAGSLEN];
	char spRole[TAGSLEN];
	struct SpRec *nextSp;
} ;
typedef struct SpRec SP_CONVRT;

struct linesRec {
	char sp[TAGSLEN];
	char *line;
	char *codes;
	long bt, et;
	struct linesRec *nextLine;
} ;
typedef struct linesRec LINESLIST;

static SP_CONVRT *spConvRoot;
static LINESLIST *sLinesRoot;
static char slx_ftime, emptyLine[3];
static long ln;
static double timeOffset;
static FNType sp_codes_fname[FNSize];

extern char GExt[];
extern struct tier *defheadtier;
extern char OverWriteFile;
extern long option_flags[];
extern char isRecursive;

void init(char f) {
	if (f) {
		timeOffset = 0.0;
		sLinesRoot = NULL;
		spConvRoot = NULL;
		strcpy(sp_codes_fname, "0attribs.cut");
		strcpy(emptyLine, "0.");
		OverWriteFile = TRUE;
		AddCEXExtension = "";
		stout = FALSE;
		onlydata = 1;
		FilterTier = 0;
		LocalTierSelect = TRUE;
		slx_ftime = TRUE;
		if (defheadtier != NULL) {
			if (defheadtier->nexttier != NULL)
				free(defheadtier->nexttier);
			free(defheadtier);
			defheadtier = NULL;
		}
	} else {
		if (slx_ftime) {
			slx_ftime = FALSE;
			strcpy(GExt, ".cha");
			option_flags[CLAN_PROG_NUM] = 0L;
		}
	}
}

void usage() {
	printf("Converts SLX text files to CHAT text files\n");
	printf("Usage: temp [tN] filename(s)\n",mainflgs());
	puts("+dF: specify speaker codes conversion file F.");
	puts("+tN: specify movie segment start time offset relative to actual movie start.");
	cutt_exit(0);
}

static SP_CONVRT *freeTiers(SP_CONVRT *p) {
	SP_CONVRT *t;

	while (p != NULL) {
		t = p;
		p = p->nextSp;
		free(t);
	}
	return(NULL);
}

static LINESLIST *freeLines(LINESLIST *p) {
	LINESLIST *t;

	while (p != NULL) {
		t = p;
		p = p->nextLine;
		if (t->line != NULL)
			free(t->line);
		if (t->codes != NULL)
			free(t->codes);
		free(t);
	}
	return(NULL);
}

static void freeMem(void) {
	sLinesRoot = freeLines(sLinesRoot);
	spConvRoot = freeTiers(spConvRoot);
}

static SP_CONVRT *add_each_sp(SP_CONVRT *root, const char *fname, char *oldSp, char *newSp, char *spRole) {
	SP_CONVRT *p;

	if (oldSp[0] == EOS)
		return(root);

	if (root == NULL) {
		if ((p=NEW(SP_CONVRT)) == NULL)
			out_of_mem();
		root = p;
	} else {
		for (p=root; p->nextSp != NULL && uS.mStricmp(p->oldSp, oldSp); p=p->nextSp) ;
		if (uS.mStricmp(p->oldSp, oldSp) == 0)
			return(root);

		if ((p->nextSp=NEW(SP_CONVRT)) == NULL)
			out_of_mem();
		p = p->nextSp;
	}

	p->nextSp = NULL;
	if ((strlen(oldSp) >= TAGSLEN) || (strlen(newSp) >= TAGSLEN)) {
		freeMem();
		fprintf(stderr,"*** File \"%s\": line %ld.\n", fname, ln);
		fprintf(stderr, "Tag(s) too long. Longer than %d characters\n", TAGSLEN);
		cutt_exit(0);
	}
	strcpy(p->oldSp, oldSp);
	strcpy(p->newSp, newSp);
	strcat(p->newSp, ":");
	strcpy(p->spRole, spRole);
	return(root);
}

static void rd_dep_f(const char *fname) {
	FILE *fp;
	char *oldSp, *newSp, *spRole;
	long i, j;
	FNType mFileName[FNSize];

	if (*fname == EOS) {
		fprintf(stderr,	"No speaker conversion file specified.\n");
		cutt_exit(0);
	}

	if ((fp=OpenGenLib(fname,"r",TRUE,FALSE,mFileName)) == NULL) {
		fprintf(stderr, "Can't open either one of speaker conversion files:\n\t\"%s\", \"%s%s\"\n", fname, templineC, fname);
		cutt_exit(0);
	}
	ln = 0L;
	while (fgets_cr(templineC, 255, fp)) {
		ln++;
		if (uS.isUTF8(templineC) || uS.isInvisibleHeader(templineC) || templineC[0] == ';')
			continue;
		uS.remblanks(templineC);
		if (templineC[0] == EOS)
			continue;
		
		for (i=0; isSpace(templineC[i]); i++) ;
		for (j=i; !isSpace(templineC[j]) && templineC[j] != EOS; j++) ;
		if (templineC[j] == EOS) {
			freeMem();
			fprintf(stderr,"*** File \"%s\": line %ld.\n", fname, ln);
			fprintf(stderr, "Missing speaker name\n");
			cutt_exit(0);
		}
		templineC[j] = EOS;
		newSp = templineC+i;
		for (i=j+1; isSpace(templineC[i]); i++) ;
		if (templineC[i] == EOS) {
			freeMem();
			fprintf(stderr,"*** File \"%s\": line %ld.\n", fname, ln);
			fprintf(stderr, "Missing info\n");
			cutt_exit(0);
		}
		for (j=i; !isSpace(templineC[j]) && templineC[j] != EOS; j++) ;
		templineC[j] = EOS;
		oldSp = templineC+i;
		for (i=j+1; isSpace(templineC[i]); i++) ;
		if (templineC[i] == EOS) {
			freeMem();
			fprintf(stderr,"*** File \"%s\": line %ld.\n", fname, ln);
			fprintf(stderr, "Missing info\n");
			cutt_exit(0);
		}
		for (j=i; !isSpace(templineC[j]) && templineC[j] != '\n' && templineC[j] != EOS; j++) ;
		templineC[j] = EOS;
		spRole = templineC+i;
		spConvRoot = add_each_sp(spConvRoot, fname, oldSp, newSp, spRole);
	}
	fclose(fp);
}

CLAN_MAIN_RETURN main(int argc, char *argv[]) {
	isWinMode = IS_WIN_MODE;
	chatmode = CHAT_MODE;
	CLAN_PROG_NUM = TEMP;
	OnlydataLimit = 0;
	UttlineEqUtterance = TRUE;

	bmain(argc,argv,NULL);
	
	sLinesRoot = freeLines(sLinesRoot);
	spConvRoot = freeTiers(spConvRoot);
}

static double calculateOffset(char *s) {
	double time;

	time = (double)(atof(s) * (double)1000.0);
	return(time);
}

void getflag(char *f, char *f1, int *i) {
	f++;
	switch(*f++) {
		case 'd':
			if (*f) {
				strcpy(sp_codes_fname, getfarg(f,f1,i));
			} else {
				fprintf(stderr,"Missing argument to option: %s\n", f-2);
				cutt_exit(0);
			}
			break;
		case 't':
			if (*f) {
				strcpy(templineC1, getfarg(f,f1,i));
				timeOffset = calculateOffset(templineC1);
			} else {
				fprintf(stderr,"Missing argument to option: %s\n", f-2);
				cutt_exit(0);
			}
			break;
		default:
			fprintf(stderr,"Invalid option: %s\n", f-2);
			cutt_exit(0);
			break;
	}
}

static LINESLIST *add_each_line(LINESLIST *root, const char *sp, char *line, long bt, long et) {
	long len;
	LINESLIST *nt, *tnt;

	if (root == NULL) {
		if ((root=NEW(LINESLIST)) == NULL)
			out_of_mem();
		nt = root;
		nt->nextLine = NULL;
	} else {
		tnt= root;
		nt = root;
		while (nt != NULL) {
			if (bt < nt->bt)
				break;
			tnt = nt;
			nt = nt->nextLine;
		}

		if (nt == NULL) {
			tnt->nextLine = NEW(LINESLIST);
			if (tnt->nextLine == NULL)
				out_of_mem();
			nt = tnt->nextLine;
			nt->nextLine = NULL;
		} else if (nt == root) {
			root = NEW(LINESLIST);
			if (root == NULL)
				out_of_mem();
			root->nextLine = nt;
			nt = root;
		} else {
			nt = NEW(LINESLIST);
			if (nt == NULL)
				out_of_mem();
			nt->nextLine = tnt->nextLine;
			tnt->nextLine = nt;
		}
	}
	nt->codes = NULL;
	nt->line = NULL;
	for (len=strlen(line); len >= 0; len--) {
		if (uS.IsUtteranceDel(line, len))
			break;
	}
	if (len < 0)
		sprintf(templineC2, " . %c%ld_%ld%c\n\t", HIDEN_C, bt, et, HIDEN_C);
	else
		sprintf(templineC2, " %c%ld_%ld%c\n\t", HIDEN_C, bt, et, HIDEN_C);

	strcpy(nt->sp, sp);
	nt->line = (char *)malloc(strlen(line)+strlen(templineC2)+1);
	if (nt->line == NULL) {
		freeMem();
		out_of_mem();
	}
	strcpy(nt->line, line);
	strcat(nt->line, templineC2);
	nt->bt = bt;
	nt->et = et;
	return(root);
}

static void outputTiers(LINESLIST *p) {
	strcpy(templineC2, "%cod:");
	for (; p != NULL; p=p->nextLine) {
		uS.remblanks(p->line);
		if (p->line[0] != EOS) {
			printout(p->sp, p->line, NULL, NULL, TRUE);
			if (p->codes != NULL)
				printout(templineC2, p->codes, NULL, NULL, TRUE);
		}
	}
}

static void output_Participants_ID(void) {
	int  len, i;
	SP_CONVRT *p;

	templineC[0] = EOS;
	for (p=spConvRoot; p != NULL; p=p->nextSp) {
		if (p->isUsed) {
			len = strlen(templineC);
			if (len > 0) {
				strcat(templineC, ", ");
				len = strlen(templineC);
			}
			strcpy(templineC2, p->newSp+1);
			for (i=strlen(templineC2)-1; i >= 0 && (isSpace(templineC2[i]) || templineC2[i] == ':'); i--) ;
			templineC2[++i] = EOS;
			sprintf(templineC+len, "%s %s", templineC2, p->spRole);
		}
	}
	if (templineC[0] != EOS)
		printout("@Participants:", templineC, NULL, NULL, TRUE);
	
	for (p=spConvRoot; p != NULL; p=p->nextSp) {
		if (p->isUsed) {
			strcpy(templineC2, p->newSp+1);
			for (i=strlen(templineC2)-1; i >= 0 && (isSpace(templineC2[i]) || templineC2[i] == ':'); i--) ;
			templineC2[++i] = EOS;
			fprintf(fpout, "@ID:	eng|sample|%s|||||%s|||\n", templineC2, p->spRole);
		}
	}
}

static char *getSp(char *sp, char *bS) {
	int i;

	i = 0;
	for (bS++; *bS != ']' && *bS != EOS; bS++) {
		sp[i++] = *bS;
		if (i >= TAGSLEN-4)
			break;
	}
	sp[i] = EOS;
	if (*bS == ']')
		bS++;
	for (; isSpace(*bS); bS++) ;
	return(bS);
}

static void readFile(void) {
	char *bS, *eS, *line;
	char sp[TAGSLEN];
	long bt, et;
	SP_CONVRT *p;

	ln = 0L;
    while (fgets_cr(templineC, UTTLINELEN, fpin)) {
    	ln++;
		if (uS.isUTF8(templineC) || uS.isInvisibleHeader(templineC))
			continue;
		uS.remblanks(templineC);
		if (templineC[0] == EOS)
			continue;
		bt = 0;
		et = 0;
		for (bS=templineC; isSpace(*bS); bS++) ;
		if (*bS == EOS) {
			freeMem();
			fprintf(stderr,"*** File \"%s\": line %ld.\n", oldfname, ln);
			fprintf(stderr, "File is corrupted1\n");
			cutt_exit(0);
		}
		for (eS=bS; !isSpace(*eS) && *eS != EOS; eS++) ;
		if (*eS == EOS) {
			freeMem();
			fprintf(stderr,"*** File \"%s\": line %ld.\n", oldfname, ln);
			fprintf(stderr, "File is corrupted2\n");
			cutt_exit(0);
		}
		bt = (long)(calculateOffset(bS) - timeOffset);
		for (bS=eS; isSpace(*bS); bS++) ;
		if (*bS == EOS) {
			freeMem();
			fprintf(stderr,"*** File \"%s\": line %ld.\n", oldfname, ln);
			fprintf(stderr, "File is corrupted3\n");
			cutt_exit(0);
		}
		for (eS=bS; !isSpace(*eS) && *eS != EOS; eS++) ;
		if (*eS == EOS) {
			freeMem();
			fprintf(stderr,"*** File \"%s\": line %ld.\n", oldfname, ln);
			fprintf(stderr, "File is corrupted4\n");
			cutt_exit(0);
		}
		et = (long)(calculateOffset(bS) - timeOffset);
		for (bS=eS; isSpace(*bS); bS++) ;
		for (; !isSpace(*bS) && *bS != EOS; bS++) ;
		for (; isSpace(*bS); bS++) ;
		if (*bS == EOS) {
			freeMem();
			fprintf(stderr,"*** File \"%s\": line %ld.\n", oldfname, ln);
			fprintf(stderr, "File is corrupted5\n");
			cutt_exit(0);
		}
		if (*bS == '[')
			bS = getSp(sp, bS);
		if (*bS == EOS)
			line = emptyLine;
		else
			line = bS;
		for (p=spConvRoot; p != NULL; p=p->nextSp) {
			if (uS.mStricmp(p->oldSp, sp) == 0)
				break;
		}
		if (p == NULL) {
			fprintf(stderr,"*** File \"%s\": line %ld.\n", oldfname, ln);
			fprintf(stderr, "There is not conversion for original speaker name %s\n", sp);
			sLinesRoot = add_each_line(sLinesRoot, sp, line, bt, et);
		} else
			sLinesRoot = add_each_line(sLinesRoot, p->newSp, line, bt, et);
    }
}

static void add_codes(LINESLIST *p, char *code) {
//	fprintf(stdout, "line=%scode=%s\n", p->line, code);

	if (p == NULL || code[0] == EOS)
		return;
	
	if (p->codes != NULL) {
		strcpy(templineC2, p->codes);
		free(p->codes);
		p->codes = (char *)malloc(strlen(code)+strlen(templineC2)+3);
		if (p->codes == NULL) {
			freeMem();
			out_of_mem();
		}
		strcpy(p->codes, templineC2);
		strcat(p->codes, ", ");
		strcat(p->codes, code);
	} else {
		p->codes = (char *)malloc(strlen(code)+1);
		if (p->codes == NULL) {
			freeMem();
			out_of_mem();
		}
		strcpy(p->codes, code);
	}
}

static char *getCodes(char *codes, char *bS) {
	int i;

	strcpy(codes, "$");
	i = 1;
	for (; !isSpace(*bS) && *bS != EOS; bS++) {
		codes[i++] = *bS;
		if (i >= CODESLEN-4)
			break;
	}
	if (i >= CODESLEN-4) {
		codes[i] = EOS;
		return(bS);
	}
	for (; isSpace(*bS) && *bS != EOS; bS++) ;
	if (*bS == '(') {
		codes[i++] = ':';
		for (bS++; *bS != ')' && *bS != EOS; bS++) {
			codes[i++] = *bS;
			if (i >= CODESLEN-4)
				break;
		}
		if (*bS == ')')
			bS++;
		for (bS++; isSpace(*bS) && *bS != EOS; bS++) ;
		if (*bS == '[') {
			codes[i++] = ':';
			for (bS++; *bS != ']' && *bS != EOS; bS++) {
				codes[i++] = *bS;
				if (i >= CODESLEN-4)
					break;
			}
		}
	}
	if (i == 1)
		codes[0] = EOS;
	else
		codes[i] = EOS;
	return(bS);
}

static void readAndAddVars(char *fname) {
	char *bS, *eS, isOneUsed;
	char codes[CODESLEN];
	long bt, et, fi;
	LINESLIST *p;
	FILE *fp;

	isOneUsed = FALSE;
	fi = strlen(fname);
	strcat(fname, ".tsv");
	fp = fopen(fname, "r");
	if (fp == NULL) {
		fname[fi] = EOS;
		isOneUsed = TRUE;
		strcat(fname, "1.tsv");
		fp = fopen(fname, "r");
		if (fp == NULL)
			return;
	}
readSecondFile:
	ln = 0L;
	while (fgets_cr(templineC, UTTLINELEN, fp)) {
		ln++;
		if (uS.isUTF8(templineC) || uS.isInvisibleHeader(templineC))
			continue;
		uS.remblanks(templineC);
		if (templineC[0] == EOS)
			continue;
		bt = 0;
		et = 0;
		for (bS=templineC; isSpace(*bS); bS++) ;
		if (*bS == EOS) {
			freeMem();
			fprintf(stderr,"*** File \"%s\": line %ld.\n", fname, ln);
			fprintf(stderr, "File is corrupted1\n");
			cutt_exit(0);
		}
		for (eS=bS; !isSpace(*eS) && *eS != EOS; eS++) ;
		if (*eS == EOS) {
			freeMem();
			fprintf(stderr,"*** File \"%s\": line %ld.\n", fname, ln);
			fprintf(stderr, "File is corrupted2\n");
			cutt_exit(0);
		}
		bt = (long)(calculateOffset(bS) - timeOffset);
		for (bS=eS; isSpace(*bS); bS++) ;
		if (*bS == EOS) {
			freeMem();
			fprintf(stderr,"*** File \"%s\": line %ld.\n", fname, ln);
			fprintf(stderr, "File is corrupted3\n");
			cutt_exit(0);
		}
		for (eS=bS; !isSpace(*eS) && *eS != EOS; eS++) ;
		if (*eS == EOS) {
			freeMem();
			fprintf(stderr,"*** File \"%s\": line %ld.\n", fname, ln);
			fprintf(stderr, "File is corrupted4\n");
			cutt_exit(0);
		}
		et = (long)(calculateOffset(bS) - timeOffset);
		for (bS=eS; isSpace(*bS); bS++) ;
		for (; !isSpace(*bS) && *bS != EOS; bS++) ;
		for (; isSpace(*bS); bS++) ;
		if (isSpace(*(bS+1)))
			bS = bS + 2;
		if (*bS == EOS) {
			freeMem();
			fprintf(stderr,"*** File \"%s\": line %ld.\n", fname, ln);
			fprintf(stderr, "File is corrupted5\n");
			cutt_exit(0);
		}
		bS = getCodes(codes, bS);
		for (p=sLinesRoot; p != NULL; p=p->nextLine) {
			if (p->bt <= bt && et <= p->et) {
				add_codes(p, codes);
			}
		}

//		sLinesRoot = add_each_line(sLinesRoot, p->newSp, line, bt, et);
	}
	fclose(fp);
	if (isOneUsed) {
		fname[fi] = EOS;
		isOneUsed = FALSE;
		strcat(fname, "2.tsv");
		fp = fopen(fname, "r");
		if (fp == NULL)
			return;
		goto readSecondFile;
	}
}

void call() {
	char *s;

	if (spConvRoot == NULL) {
		rd_dep_f(sp_codes_fname);
		if (spConvRoot == NULL) {
			fprintf(stderr,"Please specify 0attribs.cut file with +d option.\n");
			cutt_exit(0);
		}
	}
	FileName1[0] = EOS;
	FileName2[0] = EOS;
	strcpy(FileName2, oldfname);
	s = strchr(FileName2, '.');
	if (s != NULL)
		*s = EOS;
	strcpy(FileName1, FileName2);
	readFile();
	if (FileName2[0] != EOS) {
		fprintf(fpout, "%s\n", UTF8HEADER);
		fprintf(fpout, "@Begin\n");
		fprintf(fpout, "@Languages:	eng\n");
		output_Participants_ID();
		fprintf(fpout, "%s\t%s, audio\n", MEDIAHEADER, FileName2);
		// read 0variables
		s = strrchr(FileName1, '_');
		if (s != NULL) {
			*s = EOS;
			if (strcmp(s+1, "01") == 0) {
				readAndAddVars(FileName1);
			}
		}
		outputTiers(sLinesRoot);
		fprintf(fpout, "@End\n");
	}
    sLinesRoot = freeLines(sLinesRoot);
}
