#include <exec/memory.h>
#include <exec/tasks.h>
#include <utility/tagitem.h>
#include <powerup/ppclib/interface.h>
#include <powerup/ppclib/message.h>
#include <powerup/ppclib/tasks.h>
#include <powerup/proto/ppc.h>
#include <proto/exec.h>
#include <proto/dos.h>

#include <stdio.h>
#include <string.h>

#include "portlists.h"

struct Library *PPCLibBase;



int main(void)
{
  struct TagItem ti[8];
  int i,flag,rc=10;
  void *elfobj,*portlist,*startmsg,*task,*mp,*msg;
  struct StartupData *startup;
  BYTE sig;
  ULONG sm;

  printf("Opening ppc.library v46\n");
  if (PPCLibBase = OpenLibrary("ppc.library",46)) {

    printf("Loading PPC object\n");
    if (elfobj = PPCLoadObject("PROGDIR:portlistsPPC.elf")) {

      printf("Allocating Startup Data\n");
      if (startup = PPCAllocVec(sizeof(struct StartupData), MEMF_ANY)) {

        printf("Creating 3 MsgPorts\n");
        ti[0].ti_Tag	=	TAG_DONE;
        startup->port[3] = NULL;
        for (i=0,flag=0; i<3; i++) {
          if (!(startup->port[i] = PPCCreatePort(ti)))
            flag++;
        }
        if (flag == 0) {
          printf("Getting a task signal\n");
          sig = AllocSignal(-1);
          startup->sigmask = 1L<<sig;
          startup->sigtask = FindTask(NULL);
          printf("Signal=%d SigMask=0x%08lx Task=0x%08lx\n",(int)sig,
                 startup->sigmask,(ULONG)startup->sigtask);

          printf("Creating a port array with these ports and ext. signal\n");
          if (portlist = PPCCreatePortList(startup->port,1L<<sig)) {

            printf("Creating StartupMsg\n");
            if (startmsg = PPCCreateMessage(startup->port[0],0)) {

              printf("Launching PPC task\n");
              ti[0].ti_Tag = PPCTASKTAG_STARTUP_MSG;
              ti[0].ti_Data = (ULONG)startmsg;
              ti[1].ti_Tag = PPCTASKTAG_STARTUP_MSGDATA;
              ti[1].ti_Data = (ULONG)startup;
              ti[2].ti_Tag = PPCTASKTAG_STARTUP_MSGLENGTH;
              ti[2].ti_Data = 0;
              ti[3].ti_Tag = PPCTASKTAG_STARTUP_MSGID;
              ti[3].ti_Data = 0;
              ti[4].ti_Tag = PPCTASKTAG_MSGPORT;
              ti[4].ti_Data = TRUE;
              ti[5].ti_Tag = TAG_DONE;
              if (task = PPCCreateTask(elfobj,ti)) {
                printf("PPC task launched\n");
                rc = 0;
                printf("PPCFindTask(\"PROGDIR:portlistsPPC.elf\") = 0x%08lx\n",
                       (ULONG)PPCFindTask("PROGDIR:portlistsPPC.elf"));
                printf("PPCFindTaskObject() = 0x%08lx\n",
                       (ULONG)PPCFindTaskObject(task));

                for (;;) {
                  printf("Waiting for message or extended signals...\n");
                  mp = PPCWaitPortList(portlist);
                  sm = PPCGetPortListAttr(portlist,
                                          PPCPORTLISTTAG_RECEIVEDSIGNALS);

                  printf("received signals = 0x%08lx\n",sm);
                  if (sm == (1L<<sig))
                    printf("Received extended signal!\n");

                  if (mp) {
                    if (msg = PPCGetMessage(mp)) {
                      if (mp == startup->port[0]) i = 0;
                      else if (mp == startup->port[1]) i = 1;
                      else if (mp == startup->port[2]) i = 2;
                      else i = -1;
                      printf("Received message from PPC on port %d!\n",i);
                      if (msg == startmsg) {
                        printf("Got StartupMsg. Running cleanup!\n");
                        break;
                      }
                      PPCReplyMessage(msg);
                    }
                  }
                }
              }
              else
                printf("Could not create PPC task!\n");

              printf("Deleting StartupMsg\n");
              PPCDeleteMessage(startmsg);
            }
            else
              printf("Could not create Startup message!\n");

            printf("Removing PortList\n");
            PPCDeletePortList(portlist);
          }
          else
            printf("Could not create PortList!\n");

          if (sig >= 0)
            FreeSignal(sig);
          printf("Freeing the MsgPorts\n");
          for (i=0; i<3; i++) {
            if (startup->port[i]) {
              if (PPCDeletePort(startup->port[i]) == FALSE)
                printf("Delete port %d failed!\n",i);
            }
          }
        }
        else
          printf("Unable to create 3 MsgPorts!\n");

        printf("Free Startup Data\n");
        PPCFreeVec(startup);
      }
      else
        printf("Couldn't allocate StartupData!\n");

      printf("Unloading PPC object\n");
      PPCUnLoadObject(elfobj);
    }
    else
      printf("Can't load PPC object \"PROGDIR:portlistsPPC.elf\"!\n");

    printf("Closing ppc.library\n");
    CloseLibrary(PPCLibBase);
  }
  else
    printf("Could not open ppc.library V46!\n");

  return rc;
}
