/*

  JoinConference
  ==============

    Join's a conference

  Version
  =======

    2.0

  Options
  =======

    N_ND->ActiveDoor->SystemOptions
    -------------------------------

    FORWARD

    BACKWARD

    REJOIN

    SYSTEM


    Command Line Arguments
    ----------------------

    2 <ConfNumber>

  Returns
  =======

    OK     - if a new conference is joined
    FAILED - if no conference is joined

*/


#include <exec/types.h>
#include <exec/memory.h>
#include <dos/dos.h>
#include <clib/exec_protos.h>
#include <clib/alib_protos.h>

#include <HBBS/ANSI_Codes.h>
#include <HBBS/Defines.h>
#include <HBBS/types.h>
#include <HBBS/structures.h>
#include <HBBS/hbbscommon_protos.h>
#include <HBBS/hbbscommon_pragmas.h>
#include <HBBS/Hbbsnode_protos.h>
#include <HBBS/Hbbsnode_pragmas.h>
#include <HBBS/release.h>
char *versionstr="$VER: JoinConference "RELEASE_STR;


#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <time.h>


#ifdef __SASC
int CXBRK(void) { return(0); }
int _CXBRK(void) { return(0); }
void chkabort(void) {}
#endif

struct Library *HBBSCommonBase=NULL;
struct Library *HBBSNodeBase=NULL;

struct BBSGlobalData *BBSGlobal=NULL;
struct NodeData *N_ND=NULL;
int N_NodeNum=-1;
char outstr[BIG_STR];

static VOID cleanup(ULONG num)
{
  if (HBBSNodeBase)
  {
    HBBS_CleanUpDoor();
    CloseLibrary (HBBSNodeBase);
  }

  if (HBBSCommonBase)
  {
    HBBS_CleanUpCommon();
    CloseLibrary (HBBSCommonBase);
  }

  if (num) printf("Door Error = %d\n",num);

  exit(0);
}

static VOID init(VOID)
{
  if(!(HBBSCommonBase = OpenLibrary("HBBSCommon.library",0)))
  {
    cleanup(1);
  }

  if (!(HBBS_InitCommon()))
  {
    cleanup(2);
  }

  if(!(HBBSNodeBase = OpenLibrary("HBBSNode.library",0)))
  {
    cleanup(3);
  }

  if (!(HBBS_InitDoor(N_NodeNum,"JoinConference")))
  {
    cleanup(4);
  }
}

#define DIR_BACKWARD 1
#define DIR_FORWARD 2

V_BIGNUM FindConference( V_BIGNUM confnum, short Direction )
{
  // this routine selects a conference that the user has access to
  // if the user does not have access to the one passed as the parameter

  // returns 0 if no conference can be found.

  // direction, 1 for backwards, 2 for forwards.

  V_BIGNUM newconf=0,loop;
  BOOL CheckedAll=FALSE;

  if (HBBS_AllowConfAccess(confnum,NULL))  // access allowed to conf ?
  {
    return(confnum);
  }
  else // nope, so find a different one..
  {
    loop=confnum;

    while (newconf==0 && !CheckedAll)
    {
      switch (Direction)
      {
        case DIR_FORWARD:
          loop++;
          if (loop>BBSGlobal->Conferences)
          {
            loop=1;
          }
          break;

        case DIR_BACKWARD:
          if (confnum>1)
          {
            loop--;
          }
          else
          {
            loop=BBSGlobal->Conferences;
          }
          break;
      }

      if (loop==confnum)
      {
        CheckedAll=TRUE;
      }


      if (HBBS_AllowConfAccess(loop,NULL))
      {
        newconf=loop;
      }
    }
    return(newconf);
  }
}

void HBBS_JoinConference(V_BIGNUM newconf,V_BIGNUM oldconf) // *C* move to HBBSNode.library...
{
  char outstr[BIG_STR];

  // display a screen (unless they were not in to start with)

  if (oldconf!=0) DOOR_DisplaySpecialScreen("ConfLeft");
  N_ND->CurrentConf=(struct ConfData *)GetNode(BBSGlobal->ConfList,newconf-1);
  N_ND->User.NormalData.LastConf=newconf;
  N_ND->User.CallData.LastConf=newconf;
  N_ND->MaxDIZLines=N_ND->CurrentConf->MaxDIZLines; //copy this accross
  HBBS_SetAccess();
  HBBS_SetBBSCols();
  strcpy(outstr,"Joined Conference: ");
  strcat(outstr,N_ND->CurrentConf->node.ln_Name);
  HBBS_AddToCallersLog(outstr);
  if (N_ND->OnlineStatus==OS_ONLINE) DOOR_DisplaySpecialScreen("ConfLogo");
  if (N_ND->OnlineStatus==OS_ONLINE) DOOR_DisplaySpecialScreen("ConfBulletin");
  if (N_ND->OnlineStatus==OS_ONLINE) DOOR_DisplaySpecialScreen("ConfJoined");
}

struct CData
{
  struct List *Confs;
  V_BIGNUM Seen;
  V_BIGNUM Allowed;
};

struct CNode
{
  struct Node node;
  V_BOOL See;
  V_BIGNUM Number;
  V_BOOL Allowed;
};

void DisplayConfList( struct CData *CD)
{
  struct CNode *cn;
  short side=1;
  char numstr[3];

  for (cn=(struct CNode *)CD->Confs->lh_Head;cn->node.ln_Succ;cn=(struct CNode *)cn->node.ln_Succ)
  {
    if (cn->See)
    {
      if (BBSGlobal->Conferences<10)
      {
        sprintf(numstr,"%ld",cn->Number);
      }
      else
      {
        sprintf(numstr,"%2ld",cn->Number);
      }
      sprintf(outstr,ANSI_BOLD ANSI_FG_PURPLE" ["ANSI_FG_WHITE"%s"ANSI_FG_PURPLE"]"ANSI_RESET ANSI_FG_CYAN" - "ANSI_FG_WHITE"%-25s",numstr,cn->node.ln_Name);
      side++;
      if (side==1 && (cn->Number<BBSGlobal->Conferences))
      {
        strcat(outstr,ANSI_FG_YELLOW " -");
      }
      if (side==3)
      {
        strcat(outstr,"\r\n" ANSI_RESET);
        side=1;
      }
      DOOR_WriteText(outstr);
    }
  }
  if (side==2)
  {
    DOOR_WriteText("\r\n");
  }
  DOOR_WriteText("\r\n");
}

V_BIGNUM SelectConference(V_BIGNUM oldconf)
{
  struct CData CD;

  struct CNode *cn=NULL;
  struct ConfData *cd;
  struct BoolNode *boolnode;
  V_BIGNUM loop;
  V_BIGNUM newconf=0;

  DOOR_DisplaySpecialScreen("ConfHead");

  // first we create a list containing the numbers and names of the conferences
  // that the user is allowed to join.
  CD.Seen=0;
  CD.Allowed=0;

  if (CD.Confs=HBBS_CreateList())
  {
    for (loop=0;loop<BBSGlobal->Conferences;loop++) // loop starts at 0!
    {
      cd=(struct ConfData *)GetNode(BBSGlobal->ConfList,loop);
      boolnode=(struct BoolNode *)GetNode(N_ND->User.ConfAcs.See,loop);

      if (cn=(struct CNode *)HBBS_CreateNode(cd->node.ln_Name,sizeof(struct CNode)))
      {
        if (cn->Allowed=HBBS_AllowConfAccess(loop+1,NULL)) CD.Allowed++;
        if (cn->See=boolnode->Boolean) CD.Seen++;
        cn->Number=loop+1;
        AddTail(CD.Confs,(struct Node *)cn);
      }
      else
      {
        loop=BBSGlobal->Conferences; // to end loop as we are out of mem!
      }
    }
    if (HBBS_NodesInList(CD.Confs)==BBSGlobal->Conferences)
    {
      // OK, list is now created so we wanna display them to the user..

      if (CD.Seen==0)
      {
        DOOR_WriteText("You have no conferences to choose from!\r\n");
      }
      else
      {
        DisplayConfList(&CD);

        DOOR_MenuPrompt("[Q]uit, Conference [#] > ",'Q');
        strcpy(N_ND->CharsAllowed,"0123456789Qq");

        // hehe, this next bit is cool.. you get sortof hotkeys :-)
        // if your bbs has 20 confs you will be able to enter 2 chars...
        // if it has les than 10 you enter one char. etc...

        sprintf(outstr,"%d",BBSGlobal->Conferences);                                          //MAXLEN
        DOOR_GetLine(GL_CVTUPPER|GL_NORETURN|GL_DISPLAY|GL_EDIT|GL_USECHARS|GL_IMMEDIATE,'\0',strlen(outstr),0,NULL);
        if (N_ND->OnlineStatus==OS_ONLINE)
        {
          switch (N_ND->CurrentLine[0])
          {
            case '\0':
              DOOR_WriteText("Q");
            case 'Q':
              break;
            default:
              sscanf(N_ND->CurrentLine,"%ld",&newconf);
              break;
          }
          DOOR_WriteText("\r\n");
        }
      }
    }
    else DOOR_WriteText("Out Of Memory!\r\n");
    FreeStrList(CD.Confs);
  }
  return(newconf);
}

V_BOOL JoinIt(V_BIGNUM confnum, V_BIGNUM lastconf)
{
  if (confnum>0 && confnum<=BBSGlobal->Conferences)
  {
    if (HBBS_AllowConfAccess(confnum,NULL))
    {
      HBBS_JoinConference(confnum,lastconf);
      return(TRUE);
    }
  }
  return(FALSE);
}

void DoorMain(int argc,char *argv[])
{
  V_BIGNUM confnum=0;
  V_BIGNUM lastconf=0;
  V_BOOL JoinedConf=FALSE;

  if (N_ND->CurrentConf) lastconf=N_ND->CurrentConf->ConfNum;

  if (N_ND->ActiveDoor->SystemOptions && N_ND->ActiveDoor->SystemOptions[0]) // check system options first..
  {
    if (stricmp("REJOIN",N_ND->ActiveDoor->SystemOptions)==0)
    {
      JoinedConf=JoinIt(lastconf,lastconf);
    }
    else
    {
      if (stricmp("BACKWARD",N_ND->ActiveDoor->SystemOptions)==0)
      {
        confnum=FindConference(lastconf-1,DIR_BACKWARD);
      }
      else
      if (stricmp("FORWARD",N_ND->ActiveDoor->SystemOptions)==0)
      {
        confnum=FindConference(lastconf+1,DIR_FORWARD);
      }
      else
      if (stricmp("SYSTEM",N_ND->ActiveDoor->SystemOptions)==0)
      {
        if (N_ND->User.CallData.PreferedConf)
        {
          confnum=FindConference(N_ND->User.CallData.PreferedConf,DIR_FORWARD);
        }
        else
        {
          confnum=FindConference(N_ND->User.CallData.LastConf,DIR_FORWARD);
        }
      }
      else
      {
        DOOR_SysopText("Invalid System Option Specified");
      }

      if (confnum!=lastconf) JoinedConf=JoinIt(confnum,lastconf);
    }
  }
  else // then check command line options!
  {
    if (argc==3) // have we got any to check ?
    {
      if (sscanf(argv[2],"%ld",&confnum))
      {
        if (confnum!=lastconf) JoinedConf=JoinIt(confnum,lastconf);
      }
    }
    else // nope, so display a me menu
    {
      confnum=SelectConference(lastconf);
      if (confnum!=lastconf) JoinedConf=JoinIt(confnum,lastconf);
    }
    if (!JoinedConf)
    {
      DOOR_WriteText(ANSI_RESET ANSI_FG_RED ANSI_BOLD "Invalid Conference Number/Access Denied!\r\n" ANSI_RESET);
    }
  }

  if (JoinedConf)
  {
    DOOR_Return("OK");
  }
  else
  {
    DOOR_Return("FAILED");
    DOOR_Continue(FALSE);
  }
}

int main(int argc,char *argv[])
{
  if (sscanf(argv[1],"%d",&N_NodeNum)==0)
  {
    printf("Invalid/No Paramaters for door!\n");
    exit (20);
  }
  init();

  if (BBSGlobal=HBBS_GimmeBBS())
  {
    if (N_ND=HBBS_NodeDataPtr(N_NodeNum)) // this should not fail in normal circumstances..
    {
      DoorMain(argc,argv);
    }
  }
  cleanup(0);
}
