//------------------------------------------------------------------------------
#include "movieIO.h"
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stropts.h>
#include <sys/ioctl.h>


bool 
movieIO::setRate(int rate)
{
  playRate_ = rate;
  return true;
}

bool
movieIO::open( const char *filename )
{
  if ( !getStats(filename) ) return false;
  char basename[255], extension[255];
  splitFilename( filename, basename, extension );
  char framenames[255];
  sprintf( framenames, "%s####.rgb", basename );

  int phandle[2];
  pipe(phandle);
  if ( fork()==0 )
  { // child
    dup2( phandle[1], fileno(stdout) ); // route stdout to pipe
    execlp( "dmconvert", "dmconvert", "-d", "-frgb",
	    filename, framenames, 0 );
  }
  // parent
  wait(0);
  ::close(phandle[1]);
  char line[255];
  int n, i=0;
  while( (ioctl(phandle[0],FIONREAD,&n)>=0) && (n>0) )
  {
    read( phandle[0], &line[i], 1 );
    if ( line[i]=='\n' )
    {
      line[i]=0;
      if ( strstr( line, "File Name:" )!=0 )
      {
	strcpy(framenames, line);
      }
      i=0;
    }
    else
    {
      i++;
      
      if (i>=255)
      {
	::close(phandle[0]);
	return false;
      }
    }
  }
  ::close(phandle[0]);

  if ( strstr( framenames, basename )==0 ) return false;
  *(strstr( framenames, basename )+strlen(basename)+4) = 0;
  length_ = atoi( strstr( framenames, basename )+strlen(basename) )+1;
  
  filename_  = strdup(filename);
  basename_  = strdup(basename);
  extension_ = strdup(extension);
  return true;
}

bool 
movieIO::save( const char *filename )
{
  char basename[255], extension[255];
  splitFilename( filename, basename, extension );
  char framenames[255];
  sprintf( framenames, "%s####.rgb", basename_ );
  char vidOptions[255];
  sprintf(vidOptions,"video,inrate=%.6f",getRate());

  if ( (strcmp(extension,"mpg")==0) || (strcmp(extension,"mpeg")==0) )
  {
    strcpy(extension,"mpeg1v");
  }
  else if ( strcmp(extension,"qt")==0 )
  {
    strcat( vidOptions, ",comp=jpeg" );
  }

  if ( fork()==0 )
  { // child
    ::close(fileno(stdout));
    execlp( "dmconvert", "dmconvert", "-f", extension,
	    "-p", vidOptions,
	    framenames, filename, 0 );
  }
  
  wait(0);
  return true;
}

bool checkPS( pid_t pid, const char *pname )
{
  char psname[255];
  if ( pid!=0 )
  {
    sprintf( psname, "%i", pid );
  }
  else if ( pname!=0 )
  {
    strcpy( psname, pname );
  }
  else return false;
  
  int phandle[2];
  pipe(phandle);
  if ( fork()==0 )
  { // child
    dup2( phandle[1], fileno(stdout) ); // route stdout to pipe
    execlp( "ps", "ps", 0 );
  }
  // parent
  wait(0);
  ::close(phandle[1]);
  char line[255];
  int n, i=0;
  while( (ioctl(phandle[0],FIONREAD,&n)>=0) && (n>0) )
  {
    read( phandle[0], &line[i], 1 );
    if ( line[i]=='\n' )
    {
      line[i]=0;
      if ( strstr( line, psname )!=0 )
      {
	::close(phandle[0]);
	return true;
      }
      i=0;
    }
    else
    {
      i++;
      
      if (i>=255)
      {
	::close(phandle[0]);
	return false;
      }
    }
  }
  ::close(phandle[0]);
  return false;
}

void
movieIO::play()
{
  char framename[255];
  char **filelist = (char**)malloc( (length_+2)*sizeof(char*) );
  filelist[0] = "movie";
  for( int i=0; i<length_; i++ )
  {
    sprintf( framename, "%s%04i.rgb", basename_, i );
    filelist[i+1] = strdup(framename);
  }
  filelist[i+1] = 0;
  pcreatevp( "movie", filelist );
  for( i=1; i<=length_; i++ )
  {
    free( filelist[i] );
  }
  free( filelist[i] );
  wait(0);  // unfortnutaly the process forks so this doesn't work properly
  while ( checkPS(0,"movie") ) sginap(25);
}

bool
movieIO::getStats( const char *filename )
{
  FILE *tmp = fopen( filename, "r" );
  if ( tmp==0 ) return false;
  fclose( tmp );

  int phandle[2];
  pipe(phandle);

  if ( fork()==0 )
  { // child
    dup2( phandle[1], fileno(stdout) ); // route stdout to pipe
    execlp( "dmconvert", "dmconvert", "-D", filename, 0 );
  }
  else
  { // parent
    wait(0);
    ::close(phandle[1]);
    char line[255];
    int n, i=0;
    bool vidTrackInfo=false;
    while( (ioctl(phandle[0],FIONREAD,&n)>=0) && (n>0) )
    {
      read( phandle[0], &line[i], 1 );
      if ( line[i]=='\n' )
      {
	line[i]=0;
	if ( !vidTrackInfo )
	{
	  vidTrackInfo = strcmp("Video Track:",line)==0;
	}
	else
	{
	  if ( strstr( line, "DM_IMAGE_WIDTH:" )!=0 )
	    width_ = atoi( strstr(line,"DM_IMAGE_WIDTH:")+16 );
	  
	  else if ( strstr( line, "DM_IMAGE_HEIGHT:" )!=0 )
	    height_ = atoi( strstr(line,"DM_IMAGE_HEIGHT:")+17 );
	  
	  else if ( strstr( line, "TRACK_LENGTH:" )!=0 )
	    length_ = atoi( strstr(line,"TRACK_LENGTH:")+14 );
	  
	  else if ( strstr( line, "DM_IMAGE_RATE:" )!=0 )
	  {
	    if ( strstr(line,"Hz")!=0 ) *strstr(line,"Hz")=0;
	    playRate_ = atof( strstr(line,"DM_IMAGE_RATE:")+15 );
	  }
	  
	  if ( (width_>=0) && (height_>=0) && (length_>=0) )
	  {
	    ::close(phandle[0]);
	    return true;
	  }
	}
	i=0;
      }
      else
      {
	i++;
	if (i>=255)
	{
	  ::close(phandle[0]);
	  return false;
	}
      }
    }
  }
  
  ::close(phandle[0]);
  return false;
}

bool
movieIO::close()
{
  char framename[255];
  for( int i=0; i<length_; i++ )
  {
    sprintf( framename, "%s%04i.rgb", basename_, i );
    remove( framename );
  }
  return true;
}

// Some old c code for SGI image format I/O
#include "movieIO_IRIX_image.c"

bwImage *
movieIO::deepBWFrame( int i ) const
{
  if ( i==-1 )
  {
    return new bwImage( width_, height_ );
  }
  
  if ( (i<0) || (i>=length_) ) return 0;
  char framename[255];
  sprintf( framename, "%s%04i.rgb", basename_, i );
  
  int width, height;
  unsigned long *lbuf = getLongImage( framename, &width, &height );
  if ( lbuf==0 ) return 0;
  if ( (width!=width_) || (height!=height_) )
  {
    free( lbuf );
    return 0;
  }
  
  unsigned char *retImg =
    (unsigned char *)malloc( width_*height_*sizeof(unsigned char) );
  if ( retImg==0 )
  {
    free( lbuf );
    return 0;
  }
  
  unsigned long *lptr = lbuf;
  unsigned char *bptr = retImg;
  for ( int size = width_*height_; size>0; size-- )
  {
    *bptr = ((*lptr>>24) + ((*lptr>>16)&0xff) + ((*lptr>>8)&0xff)) / 3;
    bptr++;
    lptr++;
  }
  
  free(lbuf);
  
  return new bwImage( retImg, width, height );
}

void
movieIO::delBWFrame( bwImage *image ) const
{
  delete image;
}

void
movieIO::setBWFrame( int i, bwImage *buf )
{
  char framename[255];
  sprintf( framename, "%s%04i.rgb", basename_, i );
  
  unsigned long *base =
    (unsigned long *)malloc( (width_*height_+TAGLEN)*sizeof(long) );
  addlongimgtag( base, width_, height_ );
  unsigned long *lptr = base;
  unsigned char *bptr = buf->rawData();
  for ( int size = width_*height_; size>0; size-- )
  {
    *lptr = (*bptr<<24) | (*bptr<<16) | (*bptr<<8) | 0xff;
    bptr++;
    lptr++;
  }
  longstoimage( base, width_, height_, 4, framename );
}

rgbImage *
movieIO::deepRGBFrame( int i ) const
{
  if ( i==-1 )
  {
    return new rgbImage( width_, height_ );
  }
  
  if ( (i<0) || (i>=length_) ) return 0;
  char framename[255];
  sprintf( framename, "%s%04i.rgb", basename_, i );
  
  int width, height;
  unsigned long *lbuf = getLongImage( framename, &width, &height );
  if ( lbuf==0 ) return 0;
  if ( (width!=width_) || (height!=height_) )
  {
    free( lbuf );
    return 0;
  }
  
  unsigned char *retImg =
    (unsigned char *)malloc( width_*height_*3*sizeof(unsigned char) );
  if ( retImg==0 )
  {
    free( lbuf );
    return 0;
  }
  
  unsigned long *lptr = lbuf;
  unsigned char *bptr = retImg;
  for ( int size = width_*height_; size>0; size-- )
  {
    bptr[R] =  *lptr>>24;
    bptr[G] = (*lptr>>16)&0xff;
    bptr[B] = (*lptr>>8 )&0xff;
    bptr+=3;
    lptr++;
  }
  
  free(lbuf);
  
  return new rgbImage( retImg, width, height );
}

void
movieIO::delRGBFrame( rgbImage *image ) const
{
  delete image;
}

void
movieIO::setRGBFrame( int i, rgbImage *buf )
{
  char framename[255];
  sprintf( framename, "%s%04i.rgb", basename_, i );
  
  unsigned long *base =
    (unsigned long *)malloc( (width_*height_+TAGLEN)*sizeof(long) );
  addlongimgtag( base, width_, height_ );
  unsigned long *lptr = base;
  unsigned char *bptr = buf->rawData();
  for ( int size = width_*height_; size>0; size-- )
  {
    *lptr = (bptr[R]<<24) | (bptr[G]<<16) | (bptr[B]<<8) | 0xff;
    bptr+=3;
    lptr++;
  }
  longstoimage( base, width_, height_, 4, framename );
}
