#include <exec/exec.h>
#include <stdlib.h>
#include <stdio.h>
#define gu getuserstring
#define pu putuserstring
#define sm sendmessage
#include "dh1:source/doors/romconf/doorheader.h"

char MultiName[] = "MULTINODE";
#define ALL -1
#define NEW 1
#define N_TEXT 2
#define QUIT 3
#define ACTIVE 1
#define INACTIVE 2
int my_node;
void LastCommand(void);
void end(void);
void InitMultiNode(void);
void SendSig(int node,int Type,int ch);
void my_Interact(void);
void ProcessInfo(int node);
extern struct JHMessage *Jhmsg;
int LastNode=0;
void ListNodes(void);
struct NodeData
{
  int nodeid;
  unsigned long tasksignal;
  struct Task *mytask;
  int Type;
  int status;
  char string[100];
  int ch;
  
  struct NodeData *NextNode;
  
} *MyNode=NULL;
struct MultiPort
{
  struct SignalSemaphore semi;
  struct NodeData *NodeInfo;
  int FromNode;
  int TotalNodes;
} *Nodes=NULL;

main(int argc,char *argv[])
{
   char t[200];
  if(argc!=2)
  {
    printf("MultiNode Experiment\n");
    exit(0);
  }
  my_node=argv[1][0]-'0';
  Register(argv[1][0]-'0');
  getuserstring(t,BB_TASKPRI);
  Forbid();
  SetTaskPri(FindTask(0),atol(t));
 
  InitMultiNode();
  my_Interact();
}
void LastCommand(void)
{
             // ObtainSemaphore((struct SignalSemaphore *)Nodes);
              SendSig(ALL,QUIT,NULL);
             // 
             // ReleaseSemaphore((struct SignalSemaphore *)Nodes);
}

void end(void)
{
  exit(0);
}
void InitMultiNode(void)
{
  unsigned long signal;
  struct NodeData *it;
  struct NodeData *new=NULL;
  char *Name;
  int found=0;
  char myname[40];
  signal=getsignal();
 pu("",BB_GETTASK);
  gu(myname,DT_NAME);
  if(!(Nodes=(struct MultiPort *)FindSemaphore(MultiName)))
  {

       Nodes=(struct MultiPort *)AllocMem(sizeof(struct MultiPort),MEMF_PUBLIC|MEMF_CLEAR);
       Name=(char *)AllocMem((strlen(MultiName)+1)*sizeof(char),MEMF_PUBLIC|MEMF_CLEAR);
       strcpy(Name,MultiName);

       Nodes->semi.ss_Link.ln_Pri=0;
       Nodes->semi.ss_Link.ln_Name=Name;
       Nodes->NodeInfo=(struct NodeData *)AllocMem(sizeof(struct NodeData),MEMF_PUBLIC|MEMF_CLEAR);
       AddSemaphore((struct SignalSemaphore *)Nodes);
       Nodes->NodeInfo->NextNode=NULL; 
       Nodes->NodeInfo->nodeid=my_node;
       Nodes->NodeInfo->tasksignal=signal;
       Nodes->TotalNodes=1; 
       Nodes->NodeInfo->mytask=(struct Task *)Jhmsg->aeproc;
       Nodes->NodeInfo->status=ACTIVE;
       strcpy(Nodes->NodeInfo->string,myname);
       MyNode=Nodes->NodeInfo;
       
  }
  else
  {
    found=1;
    ObtainSemaphore((struct SignalSemaphore *)Nodes);
    for(it=(struct NodeData *)Nodes->NodeInfo;it->NextNode;it=it->NextNode)
    { 
      if(it->nodeid==my_node) new=(struct NodeData *)it;
    }
      if(it->nodeid==my_node) new=(struct NodeData *)it;
         if(it->NextNode==NULL && new==NULL)
         {
            new=(struct NodeData *)AllocMem(sizeof(struct NodeData),MEMF_PUBLIC|MEMF_CLEAR);
            if(my_node!=it->nodeid)it->NextNode=new;
            new->NextNode=NULL;
            new->nodeid=my_node;
         }
    MyNode=new;
    new->tasksignal=signal;
    new->mytask=(struct Task *)Jhmsg->aeproc;
    new->nodeid=my_node;
    strcpy(new->string,myname);
    new->status=ACTIVE;
    
    ReleaseSemaphore((struct SignalSemaphore *)Nodes);
    
  }
if(!found)sm("Can't Find Semaphore",1);
SendSig(ALL,NEW,NULL);
}

void SendSig(int node,int Type,int ch)
{
  struct NodeData *it;
  int value=0;
  char temp[100];
  ObtainSemaphore((struct SignalSemaphore *)Nodes);
  Nodes->FromNode=MyNode->nodeid;
  MyNode->Type=Type;
  MyNode->ch=ch;
  if(Type==QUIT)MyNode->status=INACTIVE;
  switch(node)
  {
    case ALL: 
       for(it=(struct NodeData *)Nodes->NodeInfo;it;it=it->NextNode)
       {
         if(it->nodeid!=MyNode->nodeid && it->status==ACTIVE)
         {
           if(Type==NEW)
           {
              if(value==0)
              {
                sm("",1);
                sm("[32mUsers in Chat[33m:",1);
                value=1;
              }
             sprintf(temp,"[3%dm",(it->nodeid)+1);
             sm("\t\t",0); sm(temp,0); sm(it->string,0); sm("[0m",1);
           }
           Signal(it->mytask,it->tasksignal);
         }
       }break;
    default:
       for(it=(struct NodeData *)Nodes->NodeInfo;it;it=it->NextNode)
       {
         if(it->nodeid!=MyNode->nodeid && it->nodeid==node && it->status==ACTIVE)
         {
           Signal(it->mytask,it->tasksignal);
           ReleaseSemaphore((struct SignalSemaphore *)Nodes); return;
         }
       }
       break;
  }
ReleaseSemaphore((struct SignalSemaphore *)Nodes);
  if(value && Type==NEW) sm("",1);
  else if(Type==NEW)
  {
    sm("",1);
    sm("[0mThe Chat Room is[32m: [36mEmpty![0m",1); sm("",1);
  }
  
  
}

void my_Interact(void)
{
   char mes[10];
   char temp[100];
   strcpy(mes,"");
   strcpy(temp,"");
   mes[1]='\0';
   LastNode=-1;
   while(1)
   {
      mes[0]=sigkey();
      switch(mes[0])
      {
         case 0:
              ObtainSemaphore((struct SignalSemaphore *)Nodes);
              ProcessInfo(Nodes->FromNode);
              ReleaseSemaphore((struct SignalSemaphore *)Nodes);
              break;
         case '\\': ShutDown(); end();
              break;
         case '/': ListNodes(); break;
         default:
              if(LastNode!=MyNode->nodeid)
              {
                sprintf(temp,"[3%dm%s[32m>[0m",MyNode->nodeid+1,MyNode->string);
                sm("",1);
                sm(temp,0);
                LastNode=MyNode->nodeid;
              }
              if(mes[0]==13 || mes[0]==12 ) sm("",1);else
              sm(mes,0);
              //ObtainSemaphore((struct SignalSemaphore *)Nodes);
              SendSig(ALL,N_TEXT,mes[0]);
              //ReleaseSemaphore((struct SignalSemaphore *)Nodes);
              break;
      }
   }
}

void ProcessInfo(int node)
{
   struct NodeData *it;
   char temp[200];
       for(it=(struct NodeData *)Nodes->NodeInfo;it;it=it->NextNode)
       {
         if(it->nodeid!=MyNode->nodeid && it->nodeid==node)
         {
           switch(it->Type)
           {
             case QUIT:
                  sprintf(temp,"[3%dm%s[32m>[31mExits chat",it->nodeid+1,it->string);
                  sm("",1);
                  sm(temp,1);
                  LastNode=-1;
                  break;
             case N_TEXT:
                  if(LastNode!=it->nodeid)
                  {
                    LastNode=it->nodeid;
                    sm("",1);
                    sprintf(temp,"[3%dm%s[32m>[0m",LastNode+1,it->string);
                    sm(temp,0);
                  }
                  sprintf(temp,"%c",it->ch);
    if(it->ch=='\r' || it->ch=='\n') sm("",1);else
                  sm(temp,0);
                  break;
             case NEW:
                  sprintf(temp,"[3%dm%s[32m>[36mEnters chat[0m",it->nodeid+1,it->string);
                  sm("",1);
                  sm(temp,1);
                  LastNode=-1;
                  break;
            }
         }
       }
}

void ListNodes(void)
{
  struct NodeData *it;
   char temp[200];
   sm("",1);
       ObtainSemaphore((struct SignalSemaphore *)Nodes);
       for(it=(struct NodeData *)Nodes->NodeInfo;it;it=it->NextNode)
       {
         sprintf(temp,"Name: %s, status %d, type %d",it->string,it->status,it->Type);
         sm(temp,1);
       }
       ReleaseSemaphore((struct SignalSemaphore *)Nodes);
}