/*
 * yepp.c:
 *
 * Copyright (c) 2001 James McKenzie <james@fishsoup.dhs.org>,
 * All rights reserved.
 *
 */

static char rcsid[] =
  "$Id: yepp.c,v 1.30 2001/10/12 13:51:21 root Exp root $";

/*
 * $Log: yepp.c,v $
 * Revision 1.30  2001/10/12 13:51:21  root
 * #
 *
 * Revision 1.23  2001/01/07 22:36:20  root
 * #
 *
 * Revision 1.22  2001/01/07 22:26:43  root
 * #
 *
 * Revision 1.21  2001/01/07 17:34:54  root
 * #
 *
 * Revision 1.20  2001/01/07 15:58:38  root
 * #
 *
 * Revision 1.19  2001/01/07 15:58:09  root
 * #
 *
 * Revision 1.18  2001/01/07 15:14:43  root
 * #
 *
 * Revision 1.17  2001/01/07 04:49:58  root
 * #
 *
 * Revision 1.16  2001/01/07 03:48:47  root
 * #
 *
 * Revision 1.15  2001/01/06 18:11:44  root
 * #
 *
 * Revision 1.14  2001/01/06 18:11:23  root
 * #
 *
 * Revision 1.13  2001/01/06 16:51:57  root
 * #
 *
 * Revision 1.12  2001/01/05 03:41:34  root
 * #
 *
 * Revision 1.11  2001/01/04 22:27:59  root
 * #
 *
 */

#include "project.h"


int stop=0;
static void interrupt(int d)
{
if (stop) {
        fprintf(stderr,"be patient...\n");
} else {
        fprintf(stderr,"Stopping, be patient...\n");
}
stop++;
}



void
usage (char *name)
{
  printf ("Usage:\n");
  printf ("%s -a [-c file [type]] [-d num] [-e num] ", name);
#ifdef HIFI
  printf ("[-g] [-G] ");
#endif
  printf ("[-p port] [-r] [-u file [type]]");
#ifdef HIFI
  printf (" [-w eweid] [-W eweid] [-z size] ");
#endif
  printf ("\n");
  printf (" -a  	 Erase all files with index>4\n");
  printf (" -c file [type] Upload file into card memory\n");
  printf (" -d num 	 Download file index num from the player\n");
  printf (" -e num 	 Erase file index num from the player\n");
#ifdef HIFI
  printf (" -g  	 Upload random song group from database to base\n");
  printf (" -G  	 Upload random song group from database to card\n");
#endif
  printf (" -p portnum  	 Upload random song group from database\n");
  printf (" -r  	 releive control of player\n");
  printf (" -u file [type] Upload file into base memory\n");
#ifdef HIFI
  printf (" -w eweid  	 Upload eweid to base\n");
  printf (" -W eweid 	 Upload eweid to card\n");
  printf (" -z size 	 Keep doing -g until freesize<size Kb\n");
  printf (" -Z size 	 Keep doing -G until freesize<size Kb\n");
#endif
  printf (" 		where type is one of\n");
  printf ("			sc4 mp3 tel data\n");

  exit (1);
}


void
dir (void)
{
  struct yepp_dirent *yd;
  struct yepp_dirent *ptr;
  unsigned char *order, *optr;
  int i;

  optr = order = yepp_getorder ();

  if (!order)
    return;

  i = YEPP_ORDER_LEN;



  ptr = yd = yepp_dir ();

  if (!yd)
    return;


  printf ("Indx Type           Size Attr Name               \n");
  printf ("-------------------------------------------------\n");



  while (i--)
    {
      if (!*optr)
        break;

      ptr = yd;
      while (ptr)
        {

          if (ptr->index == *optr)
            {
              printf ("%4d 0x%02x %14d 0x%02x %s\n",
                      ptr->index, ptr->type, ptr->size, ptr->attr, ptr->name);
              ptr->user = 1;
            }


          ptr = ptr->next;
        }


      optr++;
    }


  ptr = yd;
  while (ptr)
    {

      if (!ptr->user)
        {
          printf ("%4d 0x%02x %14d 0x%02x %s\n",
                  ptr->index, ptr->type, ptr->size, ptr->attr, ptr->name);
        }

      ptr = ptr->next;
    }


  yepp_dir_free (yd);
  printf ("\n");

  free (order);

}

void
status (void)
{
  struct yepp_status *ys;

  ys = yepp_status ();

  if (!ys)
    return;


  printf ("Status:\n");
  printf ("  Base: %d/%d Kbytes free\n", ys->main.free, ys->main.size);
  printf ("  Card: %d/%d Kbytes free\n", ys->card.free, ys->card.size);
  free (ys);


}

void
order (void)
{
  unsigned char *order, *ptr;
  int i;


  ptr = order = yepp_getorder ();

  if (!order)
    return;

  i = YEPP_ORDER_LEN;

  printf ("Playorder:");
  while (i--)
    {
      printf (" %d", *(ptr++));
      if (!*ptr)
        break;
    }

  printf ("\n");

  free (order);

}


void
do_setorder (char **list, int n)
{
  unsigned char order[YEPP_ORDER_LEN], *ptr;
  int i;

  ptr = order;
  bzero (order, sizeof (order));

  while (n--)
    {
      if ((*list)[0] == '-')
        break;
      *(ptr++) = atoi (*list);
      list++;
    }


  yepp_putorder (order);

}












int
do_erase (char *which)
{
  int i;

  if (which && (which[0] == '-'))
    return 0;

  i = atoi (which);

  return yepp_erase (i);
}


int
do_download (char *which)
{
  int i;
  FILE *f;
  char *name;

  if (which && (which[0] == '-'))
    return 0;

  i = atoi (which);

  name = yepp_getnamebyindex (i);

  if (!name)
    {
      fprintf (stderr, "download: can't find index %d\n", i);
      return 0;
    }

  fprintf (stderr, "download: index %d is %s\n", i, name);

  f = fopen (name, "w");

  if (!f)
    {
      fprintf (stderr, "download: can't open %s\n", name);
      return 0;
    }


  i = yepp_get (i, f);


  fclose (f);

  return i;
}

int
do_upload (int where, char *fname, char *ftype)
{
  int type = YEPP_TYPE_MP3;
  FILE *f;

  if (fname && (fname[0] == '-'))
    fname = NULL;
  if (ftype && (ftype[0] == '-'))
    ftype = NULL;

  if (ftype)
    {
      do
        {
          if (!strcasecmp (ftype, "mp3"))
            {
              type = YEPP_TYPE_MP3;
              break;
            }
          if (!strcasecmp (ftype, "sc4"))
            {
              type = YEPP_TYPE_SC4;
              break;
            }
          if (!strcasecmp (ftype, "tel"))
            {
              type = YEPP_TYPE_TEL;
              break;
            }

          if (!strcasecmp (ftype, "data"))
            {
              type = YEPP_TYPE_DATA;
              break;
            }

          fprintf (stderr, "upload: Unknown file type \"%s\" assuming mp3\n",
                   ftype);

        }
      while (0);
    }

  f = fopen (fname, "r");

  if (!f)
    {
      fprintf (stderr, "upload: can't open \"%s\"\n", fname);
      return 0;
    }


  yepp_put (where, type, fname, f);

  fclose (f);

  return 1;
}

void
do_erase_all (void)
{
  struct yepp_dirent *yd, *ptr;
  int happy = 0;

  ptr = yd = yepp_dir ();

  if (!yd)
    return;

  while (ptr)
    {
      switch (ptr->index)
        {
        case YEPP_CONFIG_INDEX:
          if (!strcmp (ptr->name, "config.dat"))
            happy++;
          break;
        case YEPP_ENCODE_INDEX:
          if (!strcmp (ptr->name, "encode.mas"))
            happy++;
          break;
        case YEPP_DECODE_INDEX:
          if (!strcmp (ptr->name, "decode.mas"))
            happy++;
          break;
        case YEPP_SERIAL_INDEX:
          if (!strcmp (ptr->name, "serial.dat"))
            happy++;
          break;
        }

      ptr = ptr->next;
    }

  if (happy != 4)
    {
      fprintf (stderr, "do_erase_all: not happy - aborting\n");
      yepp_dir_free (yd);
      return;
    }


  ptr = yd;

  while ((ptr) && (!stop))
    {
      switch (ptr->index)
        {
        case YEPP_CONFIG_INDEX:
        case YEPP_ENCODE_INDEX:
        case YEPP_DECODE_INDEX:
        case YEPP_SERIAL_INDEX:
          break;
        default:
          yepp_erase (ptr->index);
        }

      ptr = ptr->next;
    }


  yepp_dir_free (yd);

}

#ifdef HIFI
int
do_random_size (Files files, Eweid e, int i, struct yepp_dirent *yd)
{
  Flock flock;
  CFH h;
  char *a;

  h = files_open (files, e, O_RDONLY);

  if (!h)
    return 1000000000;
  if (files_is_group (h))
    {
      i += yepp_blocks_to_bytes (yepp_bytes_to_blocks (h->size (h)));

      flock = files_read_group (h);

      Obj_Delete (h);

      e = flock->head;
      while (e)
        {
          i = do_random_size (files, e, i, yd);
          e = e->next;
        }
      Obj_Delete (flock);

      return i;
    }

  a = eweidtoa (e);

  while (yd)
    {
      if (strstr (yd->name, a))
        {
          Obj_Delete (h);
          return 1000000000;
        }



      yd = yd->next;
    }



  i += yepp_blocks_to_bytes (yepp_bytes_to_blocks (h->size (h)));
  Obj_Delete (h);


  return i;
}



int
do_random_worker (int where, Files files, Eweid e, char *text, int i)
{
  Flock flock;
  CFH h;
  char *r;
  char buf[1024];

  h = files_open (files, e, O_RDONLY);

  if (files_is_group (h))
    {
      char *a = eweidtoa (e);
      flock = files_read_group (h);
      h->seek (h, 0L, SEEK_SET);



      sprintf (buf, "%s.grp", a);
      free (a);

      yepp_hifi_put (where, YEPP_TYPE_DATA, buf, h);

      Obj_Delete (h);

      e = flock->head;
      while (e)
        {
          i = do_random_worker (where, files, e, text, i);
          e = e->next;
        }
      Obj_Delete (flock);

      return i;
    }

  r = eweidtoa (e);


  sprintf (buf, "%s(%d) %s.mp3", text, ++i, r);
  free (r);

  yepp_hifi_put (where, YEPP_TYPE_MP3, buf, h);

  Obj_Delete (h);


  return i;
}


int
do_random (Files files, int where, Eweid e, struct yepp_status *ys,
           struct yepp_dirent *yd)
{
  char *text, *r;
  CFH h;
  int i;
  int spare = 0;


  if (!ys)
    return -1;


  switch (where)
    {
    case YEPP_WHERE_BASE:
      printf ("  Base: %d/%d Kbytes free\n", ys->main.free, ys->main.size);
      spare = ys->main.free;
      break;
    case YEPP_WHERE_CARD:
      printf ("  Card: %d/%d Kbytes free\n", ys->card.free, ys->card.size);
      spare = ys->card.free;
      break;
    }

  spare *= 1024;

  if (!e)
    e = files_random_work ();

  if (!e)
    {
      fprintf (stderr, "do_random: no work returned\n");
      return 0;
    }

  text = eweid_to_text (e);
  r = eweidtoa (e);
  printf ("do_random: %s %s\n", r, text);
  free (r);

  i = do_random_size (files, e, 0, yd);

  printf ("\n\ndo_random: collection needs %d bytes player has %d\n",
          i, spare);
  if (i > spare)
    {
      fprintf (stderr, "do_random: not enough space\n");
      free (text);
      Obj_Delete (e);
      return 0;
    }
  i = do_random_worker (where, files, e, text, 0);

  printf ("%d songs\n", i);

  Obj_Delete (e);
  free (text);



  return 1;

}

#endif

int
main (int argc, char **argv)
{
  int i, rel = 0;
  extern int optind;
  extern char *optarg;
  FILE *f;
  struct sigaction act;
  int port = 0;


  bzero (&act, sizeof (act));

  act.sa_flags = SA_RESTART;
  act.sa_handler = interrupt;

  if (sigaction (SIGINT, &act, NULL))
    perror ("sigaction");


  printf
    ("nope: OpenSource Yepp drivers (C) 2001 James McKenzie <james@fishsoup.dhs.org>\n");
  printf ("nope: NO WARRANTY EXPRESS OR IMPLIED\n");
  printf ("nope: %s\n", rcsid);
  printf ("\n");

#ifdef HIFI
  {
    time_t t;

    time (&t);
    srand48 (t);
  }
#endif

  for (i = 1; (i < argc) && (!stop); ++i)
    {
      if (!strncasecmp (argv[i], "-h", 2))
        usage (argv[0]);
      if (!strncmp (argv[i], "-?", 2))
        usage (argv[0]);
      if (!strncasecmp (argv[i], "-p", 2))
        {
          char *pport = ((i + 1) < argc) ? argv[i + 1] : NULL;
          if (pport)
            {
              sscanf (pport, "%x", &port);
            }
        }
    }

  if (!yepp_init (port)) 
    {
      fprintf (stderr, "Couldn't find suitable port\n");
      exit(1);
    }

  if (!yepp_wakeupandping ())
    {
      yepp_release ();
      fprintf (stderr, "Couldn't wakeup yepp\n");
      exit (1);
    }

  if (!yepp_ping ())
    {
      yepp_release ();
      exit (1);
    }

  for (i = 1; (i < argc) && (!stop) ; ++i)
    {

      if (!strcmp (argv[i], "-u"))
        {
          do_upload (YEPP_WHERE_BASE, ((i + 1) < argc) ? argv[i + 1] : NULL,
                     ((i + 2) < argc) ? argv[i + 2] : NULL);
        }

      if (!strcmp (argv[i], "-c"))
        {
          do_upload (YEPP_WHERE_CARD, ((i + 1) < argc) ? argv[i + 1] : NULL,
                     ((i + 2) < argc) ? argv[i + 2] : NULL);
        }

      if (!strcmp (argv[i], "-o"))
        {
          do_setorder (argv + (i + 1), argc - (i + 1));
        }


      if (!strcmp (argv[i], "-d"))
        {
          do_download (((i + 1) < argc) ? argv[i + 1] : NULL);
        }

      if (!strcmp (argv[i], "-e"))
        {
          do_erase (((i + 1) < argc) ? argv[i + 1] : NULL);
        }


      if (!strcmp (argv[i], "-a"))
        {
          do_erase_all ();
        }

#ifdef HIFI
      if (!strcmp (argv[i], "-w"))
        {
          char *s = ((i + 1) < argc) ? argv[i + 1] : NULL;
          Eweid e;

          if (s)
            {

              e = atoeweid (s);

              if ((e) && (!stop))
                {
                  struct yepp_status *ys;
                  struct yepp_dirent *yd;
                  Files files = files_user_init ();
                  yd = yepp_dir ();
                  ys = yepp_status ();

                  do_random (files, YEPP_WHERE_BASE, e, ys, yd);



                  Obj_Delete (files);
                  free (ys);
                  yepp_dir_free (yd);
                }



            }
        }

      if (!strcmp (argv[i], "-W"))
        {
          char *s = ((i + 1) < argc) ? argv[i + 1] : NULL;
          Eweid e;

          if (s)
            {

              e = atoeweid (s);

              if ((e) && (!stop))
                {
                  struct yepp_status *ys;
                  struct yepp_dirent *yd;
                  Files files = files_user_init ();
                  yd = yepp_dir ();
                  ys = yepp_status ();

                  do_random (files, YEPP_WHERE_CARD, e, ys, yd);


                  Obj_Delete (files);

                  free (ys);
                  yepp_dir_free (yd);
                }

            }

        }
      if (!strcmp (argv[i], "-z"))
        {
          char *ssize = ((i + 1) < argc) ? argv[i + 1] : NULL;
          int size = 0;

          if (ssize)
            size = atoi (ssize);


          if ((size) && (!stop))
            {
              struct yepp_status *ys;
              struct yepp_dirent *yd;
              Files files = files_user_init ();

              ys = NULL;

              do
                {
                  yd = yepp_dir ();
                  if (ys)
                    free (ys);
                  ys = yepp_status ();
		  if (!ys) {
                  	yepp_dir_free (yd);
			 break;
		  }

                  if (ys->main.free > size)
                    while ((do_random (files, YEPP_WHERE_BASE, NULL, ys, yd) ==
                           0) && (!stop));

                  yepp_dir_free (yd);

                }
              while (ys->main.free > size);

              Obj_Delete (files);
            }


        }

       if (!strcmp (argv[i], "-Z"))
        {
          char *ssize = ((i + 1) < argc) ? argv[i + 1] : NULL;
          int size = 0;

          if (ssize)
            size = atoi (ssize);


          if ((size) && (!stop))
            {
              struct yepp_status *ys;
              struct yepp_dirent *yd;
              Files files = files_user_init ();

              ys = NULL;

              do
                {
                  yd = yepp_dir ();
                  if (ys)
                    free (ys);
                  ys = yepp_status ();

                  if (ys->main.free > size)
                    while ((do_random (files, YEPP_WHERE_CARD, NULL, ys, yd) ==
                           0) && (!stop));

                  yepp_dir_free (yd);

                }
              while (ys->main.free > size);

              Obj_Delete (files);
            }


        }

      if ((!strcmp (argv[i], "-g")) && (!stop))
        {
          struct yepp_status *ys;
          struct yepp_dirent *yd;
          Files files = files_user_init ();
          yd = yepp_dir ();
          ys = yepp_status ();

          while ((do_random (files, YEPP_WHERE_BASE, NULL, ys, yd) == 0) && (!stop));

          Obj_Delete (files);
          free (ys);
          yepp_dir_free (yd);
        }

      if ((!strcmp (argv[i], "-G")) && (!stop))
        {
          struct yepp_status *ys;
          struct yepp_dirent *yd;
          Files files = files_user_init ();
          yd = yepp_dir ();
          ys = yepp_status ();

          while ((do_random (files, YEPP_WHERE_CARD, NULL, ys, yd) == 0) && (!stop));
          Obj_Delete (files);
          free (ys);
          yepp_dir_free (yd);
        }
#endif

    }


if (!stop) {
  status ();
  order ();
  dir ();
}


  for (i = 1; i < argc; ++i)
    {
      if (!strncasecmp (argv[i], "-r", 2))
        yepp_release ();
    }


  return 0;

}
