#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <dos/dostags.h>

#include "include/Messiecommon.h"
#include "include/Mess.h"

//------------------------------------
//    Mess
//------------------------------------


struct MsgPort * Mess::Mutterport=0;  //todo: das ersetzen durch startup-messages
struct MsgPort * Mess::Tochterport=0;
int Mess::Msgcount=0;

int Mess::GetData(struct Mess_Param& param) {
 int ret=0;
 if((msg=(struct MESSage*)GetMsg(Mutterport))!=0) {
  param.Command=msg->param.Command;
  param.Channel=msg->param.Channel;
  param.Day=msg->param.Day;
  param.Time=msg->param.Time;
  param.Value=msg->param.Value;
  FreeMESSage(msg);
  if(param.Command==DATA) ret=1;
 }   
 return ret;
}

Mess::~Mess() {
 if(!(Mutterport)) return;

 if(Tochterport!=0) {
  Stop();
  while((msg=(struct MESSage*)GetMsg(Mutterport))!=0) FreeMESSage(msg);
  param.Command=QUIT;
  MakeMESSage(MOTHER,&param);
 }
 while(FindTask(Procname)!=0) Delay(10); 
 while((msg=(struct MESSage*)GetMsg(Mutterport))!=0) FreeMESSage(msg);
 DeleteMsgPort(Mutterport);
}       

UBYTE Mess::Procname[]="Messie-Subtask";
 
Mess::Mess() {
 error=1;
     
 if(FindTask(Procname)) {
  PrintString(MSG_ALREADYACTIVE);
 } else {    
  msg=0;

  if((Mutterport=CreateMsgPort())==NULL) PrintString(MSG_CANTGETMSGPORT); 
  else { 

   struct TagItem Mess_NPTags[]={
    {NP_Entry,NULL},{NP_Output,NULL},{NP_CloseOutput,FALSE},
    {NP_Name,(ULONG)Procname},{NP_Priority,19},{TAG_DONE,NULL}
   };

   Mess_NPTags[0].ti_Data=(ULONG)handlerfunc;
   Mess_NPTags[1].ti_Data=(ULONG)Output();

   if((proc=CreateNewProc(Mess_NPTags)) !=0) {
    int timeout=0;
    bool drinbleiben=true;
    while((timeout<100)&&drinbleiben) {
     if((msg=(struct MESSage*)GetMsg(Mutterport))!=0) {
      drinbleiben=false;
      if(msg->param.Command==DATA) error=0;
      else PrintString(MSG_SUBTASKPROBLEM);
      FreeMESSage(msg);
     }
     Delay(1);
     timeout++;
    }
    if(drinbleiben) PrintString(MSG_SUBTASKPROBLEM);
   } else PrintString(MSG_COULDNOTMAKESUBTASK);
  }
 }
}

void Mess::MakeMESSage(Mess::sender from,struct Mess_Param *param) {
 MESSage *msg = NULL;
 if((msg=(struct MESSage*)MEMALLOC(sizeof(struct MESSage))) ==0 || Msgcount>MAXMESSAGES) {
  if(msg) {
   PrintString(MSG_MSGOVERFLOW);
   Msgcount++;
   FreeMESSage(msg);
  }
  PrintString(MSG_MSGOVERFLOW);
 
 } else {
    
  msg->execmsg.mn_Length=sizeof(struct MESSage);
  msg->param.Command=param->Command;
  msg->param.Channel=param->Channel;
  msg->param.Day=param->Day;
  msg->param.Time=param->Time;
  msg->param.Value=param->Value;

  Msgcount++;
  int drinbleiben = 1;
  switch(from) {
   case MOTHER:
    msg->execmsg.mn_ReplyPort=Mutterport;
    if((Tochterport)) {
     PutMsg(Tochterport,(struct Message*)msg);
    } else return;
    do {
     WaitPort(Mutterport);
     if((msg=(struct MESSage*)GetMsg(Mutterport)) != 0) {
      if(msg->param.Command==(param->Command|REPLY)) {
       drinbleiben=0;
       FreeMESSage(msg);
      } else PutMsg(Mutterport,(struct Message*)msg);
     }
    }while(drinbleiben);

    break;
   case DAUGHTER:
    msg->execmsg.mn_ReplyPort=Tochterport; // Sollte nichts ankommen
    PutMsg(Mutterport,(struct Message*)msg);
    break;
   default: // Sollte gar nicht vorkommen!
    break;
  }
 }
}

void Mess::handlerfunc(void) {
 ULONG running=0;  
 LONG ssm=0;
 LONG ssmold[MAXCHANNELS],interval[MAXCHANNELS],looptime[MAXCHANNELS];
 struct Mess_Param param;
 struct DateStamp ds;
 ULONG firstrun=0; 
 struct MESSage *msg=NULL;
 class Karte card;

 if((card.error)) {
   param.Command=QUIT;
   MakeMESSage(DAUGHTER,&param);
  } else if((Tochterport=CreateMsgPort())==0) {
   PrintString(MSG_CANTGETMSGPORT);
   param.Command=QUIT;
   MakeMESSage(DAUGHTER,&param);
  } else {

  DateStamp(&ds);
  ssm=ds.ds_Minute*60+ds.ds_Tick/50;
  int i;

  for(i=0;i<MAXCHANNELS;i++) {
   interval[i]=1; 
   ssmold[i]=ssm;
  }
      
  int drinbleiben=1;
  param.Command=DATA;
  MakeMESSage(DAUGHTER,&param);

  do {
   if(running) {  
    DateStamp(&ds);
    ssm=ds.ds_Minute*60+ds.ds_Tick/50;
    param.Time=ssm;

    for(i=0;i<MAXCHANNELS;i++) {
     if(ssmold[i]<=ssm) looptime[i]=ssm-ssmold[i];
     else looptime[i]=(3600*24-ssmold[i])+ssm;

     if( (looptime[i]>=interval[i] || (firstrun&(1L<<i))) && (running&(1L<<i))) {
      param.Command=DATA;
      param.Channel=i;
      param.Day=(ULONG)ds.ds_Days;
      param.Time=ssm;
      param.Value=card.ReadVal(i);

      MakeMESSage(DAUGHTER,&param);
      firstrun=(firstrun&~(1L<<i));
      DateStamp(&ds);
      ssmold[i]=ds.ds_Minute*60+ds.ds_Tick/50;
     }
    }
    Delay(10); // eine 5tel sekunde sollte reichen, um nix zu verpennen
   } else if(drinbleiben) WaitPort(Tochterport);

   if((msg=(struct MESSage*)GetMsg(Tochterport)) !=NULL) {
    param.Command=(msg->param.Command);
    param.Channel=(msg->param.Channel);
    param.Day=(msg->param.Day);
    param.Time=(msg->param.Time);
    param.Value=(msg->param.Value);
    msg->param.Command=((msg->param.Command)|REPLY);
    ReplyMsg((struct Message*)msg);

    if(param.Channel<MAXCHANNELS && param.Channel>=0)   {
     switch(param.Command) {
      case QUIT:
       drinbleiben=0;
       break;
      case INTERVAL:
       interval[param.Channel]=param.Time;
       break;
      case START:
       running=(running|(1L<<param.Channel));
       firstrun=(firstrun|(1L<<param.Channel));
       break;
      case STOP:
       running=(running)&(~(1L<<param.Channel));
       break;
      default:
       break;
     }
    }
   }
  }while(drinbleiben);
      
  while((msg=(struct MESSage*)GetMsg(Tochterport)) !=0) 
   ReplyMsg((struct Message*)msg);

  Forbid();
  DeleteMsgPort(Tochterport);
  Tochterport=NULL;
  Permit();
 }
}


