/*
 *  Copyright (c) by Jaroslav Kysela (Perex soft)
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ncurses.h>
#include "pmod.h"

int moduleType = 0;
int songLoopFlags = DEFAULT_LOOP_FLAGS;
int warnings = 0;
int background = 0;
int ncursesFlag = 0;

#ifdef DEBUG

void SET_BPERIOD( byte channel, int period )
{
  SET_PERIOD( channel, period );
  voices[ channel ].basePeriod = period;
}

void SET_NOTE_PERIOD( byte channel )
{
  voices[ channel ].basePeriod =
    GET_NOTE_PERIOD( channel, voices[ channel ].note );
  SET_BPERIOD1( channel );
}  

#endif

void help()
{
  printf( "\
PMOD version " VERSION ", Copyright (c) 1994/95 by Jaroslav Kysela (Perex soft)\n\
\n\
Usage: pmod [options] <filename> [options] [filename] ...\n\
\n\
  Global options:\n\
    -h -?    : this help\n\
    -b       : background mode\n\
    -w[-]    : warnings on / off (default)\n\
    -g <n>   : set volume (0-100)\n\
\n\
  Local (for one song only) options:\n\
    -p[-]    : set/unset PAL frequency (default is NTSC)\n\
    -v <n>   : set volume (0-100)\n\
    -l[-j]   : loop whole module or accept pattern jump effect (-lj)\n\
    -i       : heavy vibrato\n\
    -f[l3a]  : frequency computing method ({l}inear, s{3}m, {a}miga)\n\
    -r <rng> : play only specified patterns (example '-r 2,4,10-14')\n\
    -s <rng> : download specified instruments as short (half size in GUS DRAM)\n\
    -t <sec> : sleep for specified time in seconds before this song\n\
    -op <v>  : set smooth pan value (0-255), 0=off\n\
    -or <v>  : set auto ramp value (0-64), 0=off\n\
" );
}

int main( int argc, char *argv[] )
{
  int i;
  char *s;
  FILE *in;
  struct sPlayList *pl;
  short pal, vol;
  int loop;
  dword options;
  short localFreqType;
  char patterns[ MAX_RANGE_SIZE + 1 ];
  char sinstruments[ MAX_RANGE_SIZE + 1 ];
  int sleepForSecs;
  short span, rauto;

  if ( argc < 2 )
    {
      help();
      return 1;
    }

  i = 1;
  while ( i < argc )
    {
      pal = 0;
      vol = -1;
      loop = DEFAULT_LOOP_FLAGS;
      options = 0;
      localFreqType = FTYPE_NOTHING;
      patterns[ 0 ] = 0;
      sinstruments[ 0 ] = 0;
      sleepForSecs = 0;
      span = rauto = -1;
      
      while ( i < argc && argv[ i ][ 0 ] == '-' ) /* seems to be option */
        {
          s = argv[ i ];
          switch ( *(s+1) ) {
            case '-':
            case '?':
            case 'h':
              help();
              break;
            case 'g':
              if ( ++i < argc ) mainVolume = atoi( argv[ i ] );
              break;
            case 'v':
              if ( ++i < argc ) vol = atoi( argv[ i ] );
              break;
            case 'p':
              pal = !( *(s+2) == '-' );
              break;
            case 'l':
              switch ( *(s+2) ) {
                case 'j': loop = LFLG_JUMP; break;
                case '-': loop = LFLG_NONE; break;
                default:  loop = LFLG_WHOLE;
              }
              break;
            case 'w':
              warnings = !( *(s+2) == '-' );
              break;
            case 'b':
              background = 1;
              break;
            case 'i':
              options = SNDO_VIBRATO;
              break;
            case 'f':
              switch ( *(s+2) ) {
                case 'l': localFreqType = FTYPE_LINEAR; break;
                case '3': localFreqType = FTYPE_S3M; break;
                case 'a': localFreqType = FTYPE_AMIGA; break;
              }
              break;
            case 'r':
              if ( ++i < argc )
                {
                  if ( rangeCheck( argv[ i ] ) )
                    fatal( "bad pattern number(s) (%s)", argv[ i ] );
                  if ( strlen( argv[ i ] ) > MAX_RANGE_SIZE )
                    fatal( "pattern number(s) too big" );
                  strcpy( patterns, argv[ i ] );
                }
              break;
            case 's':
              if ( ++i < argc )
                {
                  if ( rangeCheck( argv[ i ] ) )
                    fatal( "bad instrument number(s) (%s)", argv[ i ] );
                  if ( strlen( argv[ i ] ) > MAX_RANGE_SIZE )
                    fatal( "instrument number(s) too big" );
                  strcpy( sinstruments, argv[ i ] );
                }
              break;
            case 't':
              if ( ++i < argc ) sleepForSecs = atoi( argv[ i ] );
              break;
            case 'o':
              if ( ++i < argc )
                {
                  switch ( *(s+2) ) {
                    case 'p': 
                      span = atoi( argv[ i ] );
                      if ( span < 0 || span > 255 )
                        fatal( "smooth pan value out of range (0-100).." );
                      break;
                    case 'r': 
                      rauto = atoi( argv[ i ] ); 
                      if ( rauto < 0 || rauto > 64 )
                        fatal( "auto ramp value out of range (0-64).." );
                      break;
                  }
                }
              break;
          }
          i++;
          continue;
        }
      if ( ( pl = playListAdd( argv[ i++ ] ) ) != NULL )
        {
          pl -> volume = vol;
          pl -> palFreq = pal;
          pl -> loopFlags = loop;
          pl -> options = options;
          pl -> freqType = localFreqType;
          pl -> sleepForSecs = sleepForSecs;
          pl -> rampAuto = rauto >= 0 ? 64 - rauto : -1;
          pl -> smoothPan = span;
          strcpy( pl -> patterns, patterns );
          strcpy( pl -> sinstruments, sinstruments );
        }
    }

  if ( playListFirst == NULL )
    return 0;

  if ( background )
    {
      if ( ( i = fork() ) < 0 )
        fatal( "background fork" );
      if ( i != 0 )
        return 0;
    }
#if 0
  background = 1;
#endif
      
  if ( !background )
    {
      initscr();
      cbreak();
      noecho();
      timeout( 0 );
      keypad( stdscr, TRUE );
      ncursesFlag = 1;
    }
  initSignalHandlers();
  gusInit();
  playListCurrent = playListFirst;
  while ( !quit && playListCurrent )
    {
      if ( playListCurrent -> sleepForSecs > 0 )
        {
          sleep( playListCurrent -> sleepForSecs );
          initSignalHandlers();
        }
      songVolume    = playListCurrent -> volume;
      palFreq       = playListCurrent -> palFreq;
      songLoopFlags = playListCurrent -> loopFlags;
      songOptions   = playListCurrent -> options;
      freqType      = playListCurrent -> freqType;
      songPatterns  = playListCurrent -> patterns;
      shortInstrs   = playListCurrent -> sinstruments;
      smoothValue   = playListCurrent -> smoothPan;
      rampAutoValue = playListCurrent -> rampAuto;
      s             = playListCurrent -> filename;
      if ( ( in = fopen( s, "rb" ) ) == NULL )
        dprintf( "I cann't open file '%s'. Skipping..\n", playListCurrent -> filename );
       else
        {
          songError = 0;
	  convNewSong();
	  detectModuleType( in );
	  pprintf( "\n" );
	  switch ( moduleType ) {
	    case MODULE_MOD: loadMOD( in, s ); break;
            case MODULE_XM:  loadXM ( in, s ); break;
	    case MODULE_S3M: loadS3M( in, s ); break;
	    case MODULE_MTM: loadMTM( in, s ); break;
	    case MODULE_669: load669( in, s ); break;
	  }
          fclose( in );
          if ( !songError )
            {
              convReallocSong(); 
              info();
#if 1
              play();
#endif
            }
           else
            pprintf( "Skipping...\n" );
          convClearSong();
        }
      if ( quit ) continue;
      if ( !prev )
        playListCurrent = playListCurrent -> next;
       else
        playListCurrent = playListCurrent -> prev;
      if ( !playListCurrent )
        {
          if ( next ) 
            playListCurrent = playListFirst;
           else
          if ( prev )
            playListCurrent = playListLast;
        }
      next = prev = 0;
    }
  playListFree();
  gusDone();
  doneSignalHandlers();
  if ( !background )
    {
      endwin();
      ncursesFlag = 0;
    }
  return 0;
}
