#define __GNUC__

#include <stdio.h>
#include "portab.h"
#include <stdlib.h>
#include <string.h>
#include <math.h>
/*
#include <values.h>
*/
char filename[80];
char vuename[80];
char tplname[80];
char outname[80];
int  fstart;
int  fend;
int  fstep;

void process_args (int argc, char *argv[]);
void read_vue (char *fname, int *start, int *end);
void add_ext (char *fname, char *ext, int force);
void abortmsg (char *msg, int exit_code);
char *after (char *str, char *target);
char lookahead (FILE *f);
char upcase (char ch);


int main (int argc, char *argv[])
{
    FILE *tpl, *out;
    char fstring[] = "%03d";
    char ch;
    int  frame, digits, i;

    /* Handle the command line args */
    process_args (argc, argv);

    /* Get the start/end frame numbers from the .vue file */
    read_vue (vuename, &fstart, &fend);

    if (fstart > fend)
	abortmsg ("No frames generated.", 1);

    digits = (fend < 1) ? 1 : (floor(log10(fend)) + 1);

    out = fopen (outname, "w");
    if (out == NULL) {
	printf ("Unable to open output file '%s'", outname);
	exit(1);
    }

    printf ("Output to: %s\n", outname);

    for (frame = fstart; frame <= fend; frame = frame + fstep) {
	tpl = fopen (tplname, "r");

	if (tpl == NULL) {
	    printf ("Unable to open template file '%s'\n", tplname);
	    exit(1);
	}

	while (1) {
	    ch = getc (tpl);

	    if (feof(tpl))
		break;

	    if (ch == '$') {
		if (lookahead(tpl) == '#' && (strlen(filename) + digits > 8)) {
		    for (i = 0; i < 8 - digits; i++)
			putc (filename[i], out);
		}
		else
		    fprintf (out, "%s", filename);
	    }
	    else if (ch == '#') {
		fstring[2] = '0' + digits;
		fprintf (out, fstring, frame);
	    }
	    else
		putc (ch, out);
	}

	fclose (tpl);
    }

    fclose (out);

    return 0;
}



void process_args (int argc, char *argv[])
{
    int i;

    printf("\n\n3DS2POV Animation Utility\n");
    printf ("\n");

    if (argc < 2) {
	printf ("Usage: 3dsani inputfile [options]\n\n");
	printf ("Options: -a<filename> - Specifies name of the 3ds animation (.vue) file\n");
	printf ("         -t<filename> - Specifies name of the template (.tpl) file\n");
	printf ("         -o<filename> - Specifies name of the output (.bat) file\n");
	printf ("         -snnn        - Start animation at frame nnn\n");
	printf ("         -ennn        - End animation at frame nnn\n");
	printf ("         -pnnn        - Render every nnn'th frane\n");
	printf ("\nex. 3dsani ruby -aruby.vue -tani.tpl -oruby.bat -s0 -e10\n\n");
	exit(1);
    }

    strcpy (filename, "");
    strcpy (vuename, "");
    strcpy (tplname, "");
    strcpy (outname, "");
    fstart = -1;
    fend   = -1;
    fstep  =  1;

    for (i = 1; i < argc; i++) {
	if (argv[i][0] == '-' || argv[i][0] == '/') {
	    switch (upcase(argv[i][1])) {
		case 'A': strcpy (vuename, &argv[i][2]);
			  break;

		case 'T': strcpy (tplname, &argv[i][2]);
			  break;

		case 'O': strcpy (outname, &argv[i][2]);
			  break;

		case 'S': if (argv[i][2] != '\0')
			      fstart = atoi (&argv[i][2]);
			  break;

		case 'E': if (argv[i][2] != '\0')
			      fend = atoi (&argv[i][2]);
			  break;

		case 'P': if (argv[i][2] != '\0') {
			      fstep = atoi (&argv[i][2]);

			      if (fstep < 1)
				  fstep = 1;
			  }
			  break;

		default : printf ("\nInvalid option -%c\n", argv[i][1]);
			  exit (1);
	    }
	}
	else if (strlen (filename) == 0) {
	    strcpy (filename, argv[i]);
	    add_ext (filename, "", 1);
	}
	else
	    abortmsg ("Too many file names specified.", 1);
    }

    if (strlen (filename) == 0)
	abortmsg ("No file name specified", 1);

    if (strlen(vuename) == 0) {
	strcpy (vuename, filename);
	add_ext (vuename, "vue", 1);
    }

    if (strlen (tplname) == 0) {
	strcpy (tplname, filename);
	add_ext (tplname, "tpl", 1);
    }

    if (strlen (outname) == 0) {
	strcpy (outname, filename);
	add_ext (outname, "bat", 1);
    }

    add_ext (vuename, "vue", 0);
    add_ext (tplname, "tpl", 0);
    add_ext (outname, "bat", 0);
}

/* Read the start/end frame numbers from the .vue file */
void read_vue (char *fname, int *start, int *end)
{
    FILE *f;
    char string[256];
    int  fmin, fmax, frame;

    f = fopen (fname, "r");

    if (f != NULL) {
	fmin = +MAXINT;
	fmax = -MAXINT;

	while (fgets (string, 256, f) != NULL) {
	    if (strstr (string, "frame") == string) {
		frame = atoi (after (string, "frame"));

		if (frame < fmin)  fmin = frame;
		if (frame > fmax)  fmax = frame;
	    }
	}

	if (*start < 0 && fmin != +MAXINT)
	    *start = fmin;

	if (*end < 0 && fmax != -MAXINT)
	    *end = fmax;

	fclose(f);
    }

    if (*start < 0)
	abortmsg ("No start frame specified", 1);

    if (*end < 0)
	abortmsg ("No end frame specified", 1);

    printf ("Generating frames %d through %d", *start, *end);

    if (fstep > 1)
	printf (" (every %d frames)", fstep);

    printf ("\n");
}


void add_ext (char *fname, char *ext, int force)
{
    int i;

    for (i = 0; i < strlen(fname); i++)
	if (fname[i] == '.') break;

    if (fname[i] == '\0' || force) {
	if (strlen(ext) > 0)
	    fname[i++] = '.';

	strcpy (&fname[i], ext);
    }
}


void abortmsg (char *msg, int exit_code)
{
    printf ("\n%s\n", msg);
    exit (exit_code);
}


char *after (char *str, char *target)
{
    static char result[256];
    char   *search;

    search = strstr (str, target);

    if (search == NULL)
	strncpy (result, "", 256);
    else
	strncpy (result, search + strlen(target), 256);

    result[255] = '\0';

    return result;
}

/* Peek at the next character in the file */
char lookahead (FILE *f)
{
    char ch;

    ch = getc (f);
    ungetc (ch, f);

    return ch;
}


char upcase (char c)
{
    if (c >= 'a' && c <= 'z')
	c = c - 'a' + 'A';

    return c;
}
