/*
 *  This is the main part
 */

#include "video.h"
#include "proto.h"
#include <sys/types.h>
#include <signal.h>

#include "util.h"

/* Define buffer length. */

#define BUF_LENGTH 65536


char animname[1024];

/* Declaration of global variable to hold dither info. */

int ditherType;

/* Global file pointer to incoming data. */
FILE *input;

/* End of File flag. */
static int EOF_flag = 0;

/* Loop flag. */
int loopFlag = 0;

/* Quiet flag. */
int quietFlag = 0;

/* Display image on screen? */
int noDisplayFlag = 0;

/* Setjmp/Longjmp env. */
jmp_buf env;

/* HAM6 rendering / HAM hires flag */
extern int ham6, lores;

/* modeid of CyberGraphX screen */
unsigned long modeid = 0xffffffff;

/* Method of picture conversion */
void (*DoDitherImage)(unsigned char *l, unsigned char *Cr, unsigned char *Cb,
		      unsigned char *disp, int h, int w);

static char version[]="$VER: aMiPEG 0.5 (compiled on " __DATE__ ", " __TIME__ ")\n";

/*
 *--------------------------------------------------------------
 *
 * get_more_data --
 *
 *	Called by correct_underflow in bit parsing utilities to
 *      read in more data.
 *
 * Results:
 *	Input buffer updated, buffer length updated.
 *      Returns 1 if data read, 0 if EOF, -1 if error.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */

int get_more_data(unsigned int *buf_start, int max_length, int *length_ptr, unsigned int **buf_ptr)
{
  
  int length, num_read, request;
  unsigned char *buffer, *mark;

  if (EOF_flag) return 0;

  length = *length_ptr;
  buffer = (unsigned char *) *buf_ptr;

  if (length > 0) {
    memcpy((unsigned char *) buf_start, buffer, (length*4));
    mark = ((unsigned char *) (buf_start + length));
  }
  else {
    mark = (unsigned char *) buf_start;
    length = 0;
  }

  request = (max_length-length)*4;
  
  num_read = fread( mark, 1, request, input);

  /* Paulo Villegas - 26/1/1993: Correction for 4-byte alignment */
  {
    int num_read_rounded;
    unsigned char *index;
 
    num_read_rounded = num_read & 0xfffffffc;
 
    /* this can happen only if num_read<request; i.e. end of file reached */
    if( num_read_rounded < num_read )
      { 
 	num_read_rounded+=4;
 	/* fill in with zeros */
 	for( index=mark+num_read; index<mark+num_read_rounded; *(index++)=0 );
 	/* advance to the next 4-byte boundary */
 	num_read = num_read_rounded;
      }
  }
  
  if (num_read < 0) {
    return -1;
  }
  else if (num_read == 0) {
    *buf_ptr = buf_start;
    
    /* Make 32 bits after end equal to 0 and 32
       bits after that equal to seq end code
       in order to prevent messy data from infinite
       recursion.
    */

    *(buf_start + length) = 0x0;
    *(buf_start + length+1) = SEQ_END_CODE;

    EOF_flag = 1;
    return 0;
  }

  num_read >>= 2;

  *buf_ptr = buf_start;
  *length_ptr = length + num_read;
 
  return 1;
}

/*
 *--------------------------------------------------------------
 *
 * int_handler --
 *
 *	Handles Cntl-C interupts..
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 *
 *--------------------------------------------------------------
 */
void int_handler(int dummy)
{
	if (!quietFlag) fprintf(stderr, "Interrupted!\n");
	if (curVidStream) DestroyVidStream(curVidStream);
	exit(1);
}


/*
 *--------------------------------------------------------------
 *
 * main --
 *
 *	Parses command line, starts decoding and displaying.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 *
 *--------------------------------------------------------------
 */

void main(int argc, char **argv)
{

  char *name;
  static VidStream *theStream;
  int mark;
  extern int lores;

  mark = 1;
  argc--;

  name = "";
  input = stdin;
  ditherType = FULL_COLOR_DITHER;
  noDisplayFlag = 0;

  while (argc) {
    if (strcmp(argv[mark], "-nop") == 0) {
      TogglePFlag();
      argc--; mark++;
    } else if (strcmp(argv[mark], "-nob") == 0) {
      ToggleBFlag();
      argc--; mark++;
    } else if (strcmp(argv[mark], "-display") == 0) {
      name = argv[++mark];
      argc -= 2; mark++;
    } else if (strcmp(argv[mark], "-dither") == 0) {
      argc--; mark++;
      if (argc < 1) {
	perror("Must specify dither option after -dither flag");
	usage(argv[0]);
      }
      if (strcmp(argv[mark], "gray") == 0) {
	argc--; mark++;
	ditherType = GRAY_DITHER;
      } else if (strcmp(argv[mark], "color") == 0) {
	argc--; mark++;
	ditherType = FULL_COLOR_DITHER;
      } else if (strcmp(argv[mark], "hiresham") == 0) {
	argc--; mark++;
	ditherType = FULL_COLOR_DITHER;
	lores = FALSE;
      } else if (strcmp(argv[mark], "ham6") == 0) {
	argc--; mark++;
	ditherType = FULL_COLOR_DITHER;
	ham6 = TRUE;
      } else if (strcmp(argv[mark], "cybergfx") == 0) {
	argc--; mark++;
	ditherType = CYBERGFX_DITHER;
			} else if (strcmp(argv[mark], "cybergfxgray") == 0) {
	argc--; mark++;
	ditherType = CYBERGFXGRAY_DITHER;
			} else if (strcmp(argv[mark], "none") == 0) {
	argc--; mark++;
	ditherType = NO_DITHER;
      } else {
	perror("Illegal dither option.");
	usage(argv[0]);
      }
    } 
    else if (strcmp(argv[mark], "-eachstat") == 0) {
      argc--; mark++;
#ifdef ANALYSIS
      showEachFlag = 1;
#else
      fprintf(stderr, "To use -eachstat, recompile with -DANALYSIS in CFLAGS\n");
      exit(1);
#endif
    }
    else if (strcmp(argv[mark], "-quiet") == 0) {
      argc--; mark++;
      quietFlag = 1;
    }
    else if (strcmp(argv[mark], "-loop") == 0) {
      argc--; mark++;
      loopFlag = 1;
    }
    else if (strcmp(argv[mark], "-no_display") == 0) {
      argc--; mark++;
      noDisplayFlag = 1;
    }
    else if (strcmp(argv[mark], "-modeid") == 0) {
      argc--; mark++;
      if(sscanf(argv[mark], "%x", &modeid) != 1)
      {
	      fprintf(stderr, "ModeID not given.\n",argv[mark]);
				usage(argv[0]);
			}
      argc--; mark++;
    }
    else if (argv[mark][0] == '-') {
      fprintf(stderr, "Unrecognized flag %s\n",argv[mark]);
      usage(argv[0]);
    }
    else {
      input = fopen(argv[mark], "r");
      if (input == NULL) {
	fprintf(stderr, "Could not open file %s\n", argv[mark]);
	usage(argv[0]);
      }
      strcpy(animname, argv[mark]);
      argc--; mark++;
    }
  }

  signal(SIGINT, int_handler);

  init_tables();
  
  switch (ditherType) {
	case CYBERGFX_DITHER:
		InitColorDither();
		modeid = InitCyberGfxDisplay(modeid);
		HAM8_draw = (void (*)(void *, int, int)) DrawCyberGfxImage;
		DoDitherImage = ColorDitherImage_RGB;
		break;

	case CYBERGFXGRAY_DITHER:
		InitColorDither();
		modeid = InitCyberGfxDisplay(modeid);
		HAM8_draw = (void (*)(void *, int, int)) DrawCyberGfxImage;
		DoDitherImage = NoDitherImage;
		break;

	case GRAY_DITHER:
		InitGrayDisplay(name);
		break;

	case FULL_COLOR_DITHER:
		InitColorDither();
		InitColorDisplay(name);
		break;

	case NO_DITHER:
		HAM8_draw = (void (*)(void *, int, int)) NoDitherImage;	// method casting ... argh!
		DoDitherImage = NoDitherImage;
		break;
  }

/*
 *  The new restart handling has not been checked out very closely with changing
 *  (non)intra scale matrices!
 */

  theStream = NewVidStream(BUF_LENGTH);

  if (setjmp(env) != 0) {
    mpegInitVidRsrc(); /* fix bug in static first in mpegVidRsrc */

    rewind(input);

    EOF_flag = 0;
    theStream->bit_offset = 0;
    theStream->buf_length = 0;
    theStream->buffer = NULL;
    totNumFrames = 0;
#ifdef ANALYSIS 
    init_stats();
#endif
  }

  realTimeStart = ReadSysClock();
  while (mpegVidRsrc(0, theStream));

}
 

/*
 *--------------------------------------------------------------
 *
 * usage --
 *
 *	Print mpeg_play usage
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	exits with a return value -1
 *
 *--------------------------------------------------------------
 */

void usage(char *s)  /* program name */
{
    fprintf(stderr, "Usage:\n");
    fprintf(stderr, "mpeg_play\n");
    fprintf(stderr, "          [-nob]\n");
    fprintf(stderr, "          [-nop]\n");
    fprintf(stderr, "          [-dither {gray|color|ham6|hiresham|cybergfx|cybergfxmono|none}]\n");
    fprintf(stderr, "          [-modeid nnnnnnnn]\n");
    fprintf(stderr, "          [-loop]\n");
    fprintf(stderr, "          [-eachstat]\n");
    fprintf(stderr, "          [-no_display]\n");
    fprintf(stderr, "          [-quiet]\n");
    fprintf(stderr, "          file_name\n");
    exit (-1);
}


/*
 *  Dummy display method
 *
 */
void NoDitherImage(unsigned char *l, unsigned char *Cr, unsigned char *Cb,
		   unsigned char *disp, int h, int w)
{}