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

static char rcsid[] =
  "$Id: mpeg.c,v 1.16 2001/10/12 13:51:17 root Exp root $";

/*
 * $Log: mpeg.c,v $
 * Revision 1.16  2001/10/12 13:51:17  root
 * #
 *
 * Revision 1.15  2001/01/30 06:16:31  root
 * #
 *
 * Revision 1.14  2000/12/01 04:42:19  root
 * #
 *
 * Revision 1.13  2000/11/23 23:45:28  root
 * #
 *
 * Revision 1.12  2000/10/07 18:30:10  root
 * #
 *
 * Revision 1.11  2000/10/06 19:52:45  root
 * #
 *
 * Revision 1.10  2000/09/29 11:07:42  root
 * #
 *
 * Revision 1.9  2000/09/29 07:53:48  root
 * #
 *
 * Revision 1.8  2000/09/29 07:53:02  root
 * #
 *
 * Revision 1.7  2000/09/24 01:48:14  root
 * #
 *
 */


#include "project.h"


char *listnull[] = { "F", "H" };

static Word current_length;


typedef unsigned char Eweid[8];

static char **names = NULL;
static Eweid *eweids = NULL;
static Word num = 0;
static Word need_update = 1;


char szHistory[] = "HifiHistoryDB";
char szFavorite[] = "HifiFavoriteDB";


void
dodbhist (char *n)
{
  LocalID lid;
  DmOpenRef oref;
  VoidHand mh;
  UInt16 at = 0;
  char *p;

  lid = DmFindDatabase (0, szHistory);

  if (lid == 0)
    {
      DmCreateDatabase (0, szHistory, APPID, 'Data', 0);
      lid = DmFindDatabase (0, szHistory);
    }

  if (!lid)
    return;

  oref = DmOpenDatabase (0, lid, dmModeReadWrite);
  if (!oref)
    return;

  mh = NULL;

  mh = DmNewRecord (oref, &at, StrLen (n) + 1);

  if (mh)
    {
      p = MemHandleLock (mh);
      if (p)
        {
          DmWrite (p, 0, n, StrLen (n) + 1);
          MemHandleUnlock (mh);
        }
    }
  DmReleaseRecord (oref, at, 0);
  if (MpegListLen < DmNumRecords (oref))
    DmRemoveRecord (oref, MpegListLen);
  DmCloseDatabase (oref);

}

static void
do_search (char *s, int j)
{
  Byte *buf, *ptr, *cptr;
  int i = strlen (s);


  if (j)
    dodbhist (s);

  buf = ptr = hifi_getbuf ();
  ptr =
    hifipkt_new_rel (ptr, HIFI_CLASS_DISPLAY, displayunit, HIFI_CLASS_MPEG,
                     mpegunit);
  ptr = hifipkt_ecmd (cptr = ptr, HIFI_CMD_MPEG_SEARCH);

  i++;
  bcopy (s, ptr, i);
  ptr += i;

  hifipkt_elen (cptr, HIFI_PTR_DIFF (ptr, cptr));
  ptr = hifipkt_eeof (ptr);

  hifi_send (NULL, buf, HIFI_PTR_DIFF (ptr, buf));
  hifi_freebuf (buf);




}

static void
search_cb (int j)
{
  FormPtr formptr;
  FieldPtr fieldptr;
  UInt16 index;
  char buf[256], *p, *wptr = buf;
  VoidHand ptr;
  UInt16 i;


  formptr = FrmGetFormPtr (MpegForm);
  if (!formptr)
    return;
  index = FrmGetObjectIndex (formptr, MpegFindField);
  fieldptr = FrmGetObjectPtr (formptr, index);
  if (!fieldptr)
    return;


  ptr = (VoidHand) FldGetTextHandle (fieldptr);
  i = FldGetTextLength (fieldptr);

  FldSetInsertionPoint (fieldptr, i);
  FldSetSelection (fieldptr, 0, i);

  p = MemHandleLock (ptr);

  while (i--)
    {
      if (*p != 10)
        {
          *(wptr++) = *p;
        }
      *p++;
    }
  *wptr = 0;

  MemHandleUnlock (ptr);


  do_search (buf, j);

}

static void
set_and_search (char *to)
{
  FormPtr formptr;
  FieldPtr fieldptr;
  UInt16 index;
  VoidHand mh;
  VoidPtr p;
  int l;

  if (!to)
    return;
  l = StrLen (to);
  l++;


  formptr = FrmGetFormPtr (MpegForm);
  if (!formptr)

    formptr = FrmGetFormPtr (MpegForm);
  if (!formptr)
    return;

  index = FrmGetObjectIndex (formptr, MpegFindField);
  fieldptr = FrmGetObjectPtr (formptr, index);
  if (!fieldptr)
    return;

  mh = (VoidHand) FldGetTextHandle (fieldptr);
  FldSetTextHandle (fieldptr, NULL);
  if (!mh)
    {
      mh = MemHandleNew (l);
    }

  if (MemHandleSize (mh) < l)
    {
      MemHandleResize (mh, l);
    }

  p = MemHandleLock (mh);

  StrCopy (p, to);

  MemHandleUnlock (mh);

  FldSetTextHandle (fieldptr, (Handle) mh);
  FldDrawField (fieldptr);

  search_cb (0);
}

static void
dodb (char *dbname, int inum, RectangleType * bounds)
{
  LocalID lid;
  DmOpenRef oref;
  VoidHand mh;
  char *p;

  lid = DmFindDatabase (0, dbname);

  if (lid == 0)
    {
      DmCreateDatabase (0, dbname, APPID, 'Data', 0);
      lid = DmFindDatabase (0, dbname);
    }

  if (!lid)
    return;

  oref = DmOpenDatabase (0, lid, dmModeReadWrite);
  if (!oref)
    return;

  mh = NULL;

  if (inum < DmNumRecords (oref))
    mh = DmGetRecord (oref, inum);
  if (mh)
    {
      p = MemHandleLock (mh);

      if (bounds)
        {
          WinDrawChars (p, MemHandleSize (mh) - 1, bounds->topLeft.x,
                        bounds->topLeft.y);
        }
      else
        {
          set_and_search (p);
        }

      MemHandleUnlock (mh);
      DmReleaseRecord (oref, inum, 0);
    }

  DmCloseDatabase (oref);

}

static void
histdrawfn (Word inum, RectanglePtr bounds, CharPtr * itemstext)
{
  dodb (szHistory, inum, bounds);

}

static void
favrdrawfn (Word inum, RectanglePtr bounds, CharPtr * itemstext)
{
  dodb (szFavorite, inum, bounds);
}



void
mpeg_do_cleanup ()
{
  Word n = num;
  Word i;

  if (names)
    {
      if (!n)
        n++;

      for (i = 0; i < n; ++i)
        {
          MemPtrFree (names[i]);
        }

      MemPtrFree (names);
    }

  if (eweids)
    MemPtrFree (eweids);

  eweids = NULL;
  names = NULL;
  num = 0;


}

static void
maintain_list (int j, int n, Eweid e, char *name, int form)
{
  Word i;
  FormPtr formptr;
  ListPtr listptr;
  UInt16 index;


  if (n != num)
    {
      mpeg_do_cleanup ();

      if (n == -1)
        n = 1;

      num = n;

      if (!n)
        n++;

      names = (char **) MemPtrNew (n * sizeof (char *));
      eweids = (Eweid *) MemPtrNew (n * 8);

      bzero (eweids, n * 8);

      for (i = 0; i < n; ++i)
        {
          names[i] = MemPtrNew (15);
          bcopy ("Please wait...", names[i], 15);
        }


    }



  if ((j < num) && names)
    {
      int update = 0;

      if (names[j])
        {
          if (strcmp (names[j], name) || need_update)
            {
              update++;
              need_update = 0;
              MemPtrFree (names[j]);
            }
        }
      else
        {
          update++;
        }

      if (update)
        {


          names[j] = MemPtrNew (strlen (name) + 1);
          bcopy (name, names[j], strlen (name) + 1);
          if (e)
            bcopy (e, &eweids[j][0], 8);

          if (form)
            {
              formptr = FrmGetFormPtr (MpegForm);
              if (!formptr)
                return;
              index = FrmGetObjectIndex (formptr, MpegList);
              listptr = FrmGetObjectPtr (formptr, index);
              if (!listptr)
                return;

              LstSetListChoices (listptr, names, num);
              LstDrawList (listptr);
            }
        }

    }





}

static void
do_list_lookup (int i)
{
  FormPtr formptr;
  ListPtr listptr;
  UInt16 index;
  Int16 j;


  formptr = FrmGetFormPtr (MpegForm);
  if (!formptr)
    return;
  index = FrmGetObjectIndex (formptr, MpegList);
  listptr = FrmGetObjectPtr (formptr, index);
  if (!listptr)
    return;


  j = LstGetSelection (listptr);

  if (j != i)
    {
      LstSetSelection (listptr, i);
    }


}

static void
list_lookup (Eweid e)
{
  int i;

  if (!eweids)
    return;
  if (!num)
    do_list_lookup (-1);


  for (i = 0; i < num; ++i)
    {

      if (!MemCmp (&e[0], &eweids[i][0], 8))
        {
          do_list_lookup (i);
          return;
        }

    }
  do_list_lookup (-1);

}



void
mpeg_cmdst_message (Byte unit, Word cmd, Byte * data, Word len)
{
  Word id = FrmGetActiveFormID ();
  static int buffer;
  if (unit != mpegunit)
    return;

  if (cmd == HIFI_ST_MPEG_LIST)
    {
      maintain_list (data[0], data[1], &data[2], data + 10, id == MpegForm);
    }

  if (id != MpegForm)
    return;

  switch (cmd)
    {
    case HIFI_ST_VOL:
      {
        Word v;
        v = data[0] + data[1];
        v = v / 2;
        SliderSet (MpegForm, MpegVolume, v);
      }
      break;
    case HIFI_ST_MPEG_BUFFER:
      buffer = data[0];
      break;
    case HIFI_ST_MPEG_GPNAME:
      {
        RectangleType rt = {
          {MpegTtLeft, MpegTtTop}
          ,
          {MpegTtWidth, MpegTtHeight}
        };
        WinEraseRectangle (&rt, 0);
        WinDrawChars (data+8, StrLen (data+8), MpegTtLeft, MpegTtTop);
      }
      break;

    case HIFI_ST_MPEG_STATE:
      {
        int current_state;
        int fl = 0;

        DWord d;
        Word length;

        char buf[80], *ptr;


        RectangleType rt = {
          {MpegStLeft, MpegStTop},
          {MpegStWidth, MpegStHeight}
        };

        WinEraseRectangle (&rt, 0);

        ptr = buf;


        current_state = data[0];

        switch (current_state)
          {
          case HIFI_MPEG_State_Stopped:
            ptr += sprintf (ptr, "Stop: ");
            break;
          case HIFI_MPEG_State_Playing:
            ptr += sprintf (ptr, "Play: ");
            fl++;
            break;
          case HIFI_MPEG_State_Paused:
            ptr += sprintf (ptr, "Paused: ");
            fl++;
            break;
          case HIFI_MPEG_State_Error:
            ptr += sprintf (ptr, "Error: ");
            break;
          case HIFI_MPEG_State_Unknown:
            ptr += sprintf (ptr, "???: ");
            break;
          }

        hifipkt_dword (&data[3], &current_length);


        if (fl)
          {
            sprintf (ptr, "%02d:%02d/%d:%02d %d%%", data[1], data[2],
                     current_length / 60, current_length % 60, buffer);

          }
        if (current_length > 0)
          {
            d = data[1];
            d *= 60;
            d += data[2];
            d *= 100;
            d = d / current_length;
          }

        SliderSet (MpegForm, MpegProgress, (Word) d);

        list_lookup (&data[5]);


        WinDrawChars (buf, StrLen (buf), MpegStLeft, MpegStTop);
      }

      break;

    }


}

static void
progress_callback (Word formid, Word sliderid, int v)
{
  DWord o = v;
  Byte *buf, *ptr, *cptr;
  Byte min, sec;

  o = o * (DWord) current_length;
  o = o / 100;


  buf = ptr = hifi_getbuf ();
  ptr =
    hifipkt_new (ptr, HIFI_CLASS_DISPLAY, displayunit, HIFI_CLASS_MPEG,
                 mpegunit);
  ptr = hifipkt_ecmd (cptr = ptr, HIFI_CMD_MPEG_SEEK);

  ptr = hifipkt_eword (ptr, o);

  hifipkt_elen (cptr, HIFI_PTR_DIFF (ptr, cptr));
  ptr = hifipkt_eeof (ptr);

  hifi_send (NULL, buf, HIFI_PTR_DIFF (ptr, buf));
  hifi_freebuf (buf);

}

static void
volume_callback (Word formid, Word sliderid, int v)
{
  Byte *cptr, *ptr, *buf;

  buf = ptr = hifi_getbuf ();
  ptr =
    hifipkt_new (ptr, HIFI_CLASS_DISPLAY, displayunit, HIFI_CLASS_MPEG,
                 mpegunit);
  ptr = hifipkt_ecmd (cptr = ptr, HIFI_CMD_VOL);
  ptr = hifipkt_ebyte (ptr, v);
  ptr = hifipkt_ebyte (ptr, v);
  hifipkt_elen (cptr, HIFI_PTR_DIFF (ptr, cptr));
  ptr = hifipkt_eeof (ptr);

  hifi_send (NULL, buf, HIFI_PTR_DIFF (ptr, buf));
  hifi_freebuf (buf);

}



void
mpeg_dispatch (EventType * e)
{
  Err err;
  Byte *cptr, *ptr, *buf;

  switch (e->eType)
    {
    case penDownEvent:
      slider_dispatch (e, MpegForm, MpegVolume, volume_callback);
      slider_dispatch (e, MpegForm, MpegProgress, progress_callback);
      break;
    case keyDownEvent:
      if (e->data.keyDown.chr == 10)
        search_cb (1);
      break;
    case lstSelectEvent:
      {
        Word i = e->data.lstSelect.selection;
        switch (e->data.lstSelect.listID)
          {
          case MpegList:
            if (i >= num)
              break;
            if (!eweids)
              break;

            buf = ptr = hifi_getbuf ();
            ptr =
              hifipkt_new_rel (ptr, HIFI_CLASS_DISPLAY, displayunit,
                               HIFI_CLASS_MPEG, mpegunit);
            ptr = hifipkt_ecmd (cptr = ptr, HIFI_CMD_MPEG_PLAY);
            bcopy (&eweids[i][0], ptr, 8);
            ptr += 8;


            hifipkt_elen (cptr, HIFI_PTR_DIFF (ptr, cptr));
            ptr = hifipkt_eeof (ptr);

            hifi_send (NULL, buf, HIFI_PTR_DIFF (ptr, buf));
            hifi_freebuf (buf);

            break;
          }
      }
      break;
    case popSelectEvent:
      {
        FormPtr formptr;
        ControlPtr ctrl;
        UInt16 index;


        formptr = FrmGetFormPtr (MpegForm);
        if (!formptr)
          break;

        index = FrmGetObjectIndex (formptr, e->data.popSelect.controlID);
        ctrl = FrmGetObjectPtr (formptr, index);
        if (!ctrl)
          break;

        switch (e->data.popSelect.listID)
          {
          case MpegHistList:
            dodb (szHistory, e->data.popSelect.selection, NULL);
            break;
          case MpegFavrList:
            dodb (szFavorite, e->data.popSelect.selection, NULL);
            break;
          }

        switch (e->data.popSelect.controlID)
          {
          case MpegHistPop:
            e->data.popSelect.selection = 1;
            e->data.popSelect.priorSelection = 1;
            //CtlSetLabel (ctrl, "H");
            break;
          case MpegFavrPop:
            e->data.popSelect.selection = 0;
            e->data.popSelect.priorSelection = 0;
            //CtlSetLabel (ctrl, "F");
            break;
          }

        //FrmDrawForm (formptr);

        FrmHandleEvent (FrmGetActiveForm (), e);

      }
      break;
    case ctlSelectEvent:

      switch (e->data.ctlEnter.controlID)
        {
        case MpegRandomButton:
          hifi_cmd (NULL, HIFI_CLASS_DISPLAY, displayunit, HIFI_CLASS_MPEG,
                    mpegunit, HIFI_CMD_RANDOM);
          break;

        case MpegRescanButton:
          hifi_cmd (NULL, HIFI_CLASS_DISPLAY, displayunit, HIFI_CLASS_MPEG,
                    mpegunit, HIFI_CMD_MPEG_RESCAN);
          maintain_list (0, -1, NULL, "Rescanning...", 1);
          break;

        case MpegStopButton:
          hifi_cmd_rel (NULL, HIFI_CLASS_DISPLAY, displayunit,
                        HIFI_CLASS_MPEG, mpegunit, HIFI_CMD_STOP);
          break;

        }
      break;

    case frmOpenEvent:
      redraw_screen ();
      SliderSet (MpegForm, MpegVolume, 0);
      SliderSet (MpegForm, MpegProgress, 0);
      {
        FormPtr formptr;
        FieldPtr fieldptr;
        ListPtr listptr;
        UInt16 index;
        UInt16 i;


        formptr = FrmGetFormPtr (MpegForm);
        if (!formptr)
          break;

        index = FrmGetObjectIndex (formptr, MpegFindField);
        fieldptr = FrmGetObjectPtr (formptr, index);
        if (!fieldptr)
          break;

        i = FldGetTextLength (fieldptr);
        FldSetInsertionPoint (fieldptr, i);
        FldSetSelection (fieldptr, 0, i);
        FrmSetFocus (formptr, index);
        FldGrabFocus (fieldptr);
        need_update++;

        index = FrmGetObjectIndex (formptr, MpegFavrList);
        listptr = FrmGetObjectPtr (formptr, index);
        if (!listptr)
          break;
        LstSetDrawFunction (listptr, favrdrawfn);
        LstSetListChoices (listptr, listnull, favnum ());

        index = FrmGetObjectIndex (formptr, MpegHistList);
        listptr = FrmGetObjectPtr (formptr, index);
        if (!listptr)
          break;
        LstSetDrawFunction (listptr, histdrawfn);
        LstSetListChoices (listptr, listnull, MpegListLen);


      }


      break;
    }

}
