/*
**  Q&D Protracker DataType
**
**      Written by Martin Blom, based on the AIFF DataType by
**  Olaf `Olsen' Barthel <olsen@sourcery.han.de>
**  Public domain
**
*/

extern void KPrintF(char *fmt,...);

#include "Data.h"

/* Our PlayerFunc() */

void __asm __saveds __interrupt PlayerFunc(
    register __a0 struct Hook *me,
    register __a2 struct AHIAudioCtrl *AudioCtrl,
    register __a1 void *unused)
{
  struct ObjectData *ObjectData=me->h_Data;

  mt_music(&ObjectData->ptdata);
}


  /* ClassDispatch():
   *
   *  The class dispatcher routine.
   */

Object * LIBENT
ClassDispatch(REG(a0) Class *class,REG(a2) Object *object,REG(a1) Msg msg)
{
  struct  ClassBase *ClassBase = (struct ClassBase *) class->cl_UserData;
  Object  *Result;
  struct  ObjectData *ObjectData=NULL;

    // What message is it?

  switch(msg->MethodID)
  {
      // Create a new instance

    case OM_NEW:
    {
      BOOL success=FALSE;
      char prefs[40]="0 14000";
      int offset;
      LONG audiomode, freq, size=NULL;
      BPTR File=NULL;

      if(Result = (Object *)DoSuperMethodA(class,object,msg))
      {

// The following code assumes that all methods will be sent by one task only.
// I have no idea if that is really true...

        if(ObjectData = (struct ObjectData *) AllocVec(sizeof(struct ObjectData), MEMF_CLEAR))
        {
            // Fill in the remaining information

          SetDTAttrs(Result,NULL,NULL,
            DTA_ObjName,    GetTagData(DTA_Name,NULL,((struct opSet *)msg)->ops_AttrList),
            DTA_UserData,   ObjectData,
            SDTA_Cycles,    1,
            TAG_DONE);

          ObjectData->PlayerHook.h_Entry=(ULONG (*)()) PlayerFunc;
          ObjectData->PlayerHook.h_Data=ObjectData;

          if(ObjectData->AHImp=CreateMsgPort())
          {
            if(ObjectData->AHIio=(struct AHIRequest *)CreateIORequest(
                ObjectData->AHImp,sizeof(struct AHIRequest)))
            {

              ObjectData->AHIio->ahir_Version=2;
              if(!(ObjectData->AHIDevice=OpenDevice(AHINAME,AHI_NO_UNIT,
                  (struct IORequest *)ObjectData->AHIio,NULL)))
              {

                AHIBase=ObjectData->AHIio->ahir_Std.io_Device;

                  // Get desired audio mode and frequency

                GetVar( "ENV:DataTypes/Protracker", prefs, sizeof prefs, NULL );
                offset=StrToLong(prefs,&audiomode);
                if(offset  != -1)
                {
                  if(StrToLong(&prefs[offset],&freq) != -1)
                  {
                    if(ObjectData->ptdata.ptd_AudioCtrl=AHI_AllocAudio(
                        AHIA_AudioID,audiomode,
                        AHIA_MixFreq,freq,
                        AHIA_Channels,4,
                        AHIA_Sounds,1,
                        AHIA_PlayerFunc,&ObjectData->PlayerHook,
                        AHIA_PlayerFreq,50<<16,
                        AHIA_MinPlayerFreq,(32*2/5)<<16,
                        AHIA_MaxPlayerFreq,(255*2/5)<<16,
                        TAG_DONE))
                    {
                      GetDTAttrs(Result,
                          DTA_Handle,&File,
                          TAG_DONE);
                      if(File)
                      {
                        Seek(File, 0, OFFSET_END);
                        size=Seek(File, 0, OFFSET_BEGINNING);
                        if(ObjectData->ptdata.ptd_ModuleAddress=AllocVec(size, MEMF_PUBLIC))
                        {
                          if(Read(File, ObjectData->ptdata.ptd_ModuleAddress, size) == size)
                          {
                              // Check if known module format
                            if(*((ULONG *) ObjectData->ptdata.ptd_ModuleAddress+(1080/4)) == MKID)
                            {
                              if(mt_init(&ObjectData->ptdata))
                              {
                                ObjectData->ModInitialized=TRUE;
                                success=TRUE;
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
      
      if(!success)
      {
        CoerceMethod(class,Result,OM_DISPOSE);
        Result = NULL;
      }
      break;
    }


    case GM_GOACTIVE:
    case DTM_TRIGGER:
      {
        GetDTAttrs(object,
          DTA_UserData, &ObjectData,
          TAG_DONE);
        if(ObjectData)
        {
          mt_start(&ObjectData->ptdata);
        }
      }
      Result = (Object *)DoSuperMethodA(class,object,msg);
      break;



    case OM_DISPOSE:
      GetDTAttrs(object,
        DTA_UserData, &ObjectData,
        TAG_DONE);
      if(ObjectData)
      {
        SetDTAttrs(object,NULL,NULL,
          DTA_UserData, NULL,
          TAG_DONE);

        if(ObjectData->ModInitialized)
          mt_end(&ObjectData->ptdata);
        FreeVec(ObjectData->ptdata.ptd_ModuleAddress);
        AHI_FreeAudio(ObjectData->ptdata.ptd_AudioCtrl);
        if(ObjectData->AHIDevice != -1)
          CloseDevice((struct IORequest *)ObjectData->AHIio);
        DeleteIORequest((struct IORequest *)ObjectData->AHIio);
        DeleteMsgPort(ObjectData->AHImp);

        FreeVec(ObjectData);
      }
      Result = (Object *)DoSuperMethodA(class,object,msg);
      break;




      // Let the superclass handle the rest

    default:

      Result = (Object *)DoSuperMethodA(class,object,msg);

      break;
  }

  return(Result);
}
