#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <ctype.h>
#include <lists.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/memory.h>

#include "mm2.h"

/* Prototypes */

Prototype BOOL Edit(void);
Prototype BOOL Add(void);
Prototype BOOL Del(void);
Prototype BOOL MemIns(struct MI_Mem *);
Prototype BOOL MemoReq(struct Memo_Item *);
Prototype BOOL MemoDel(struct MI_Mem *);
Prototype void ClearWaitPointer(struct Window *);
Prototype void SetWaitPointer(struct Window *);
Prototype void DisableGadgets(void);
Prototype void EnableGadgets(void);

extern struct MinList *MemListPtr;
extern struct MinNode *DisplayFirst;
extern struct Remember *RK;
extern struct IntuitionBase *IntuitionBase;

BOOL DataAmended = FALSE;
BOOL memostate = 0;

extern struct IntuitionBase *IntuitionBase;
extern void Display_Block(struct MinNode *);

__chip const UWORD waitspritedata[36] = {
	0x0000, 0x0000,

	0x0400, 0x07C0,
	0x0000, 0x07C0,
	0x0100, 0x0380,
	0x0000, 0x07E0,
	0x07C0, 0x1FF8,
	0x1FF0, 0x3FEC,
	0x3FF8, 0x7FDE,
	0x3FF8, 0x7FBE,
	0x7FFC, 0xFF7F,
	0x7FFC, 0xFEFF,
	0x7FFC, 0xFFFF,
	0x3FF8, 0x7FFE,
	0x3FF8, 0x7FFE,
	0x1FF0, 0x3FFC,
	0x07C0, 0x1FF8,
	0x0000, 0x07E0,

	0x0000, 0x0000};

/*--------------------------------------------------------------------------
 * Function Edit() calls MemoReq() for each selected memo in the list. Prior
 *  to the call, Edit() sets up the current field values in a Memo_Item
 *  structure. Returns TRUE if no errors found, otherwise FALSE. (Actually,
 *  it currently returns TRUE under all circumstances.
 */
BOOL Edit()
  {
  struct Memo_Item m;
  struct MinNode *n;
  BOOL result;


  if (LISTEMPTY) return TRUE;
  n=MemListPtr->mlh_Head;
  while (n->mln_Succ)
    {
    if ( ((struct MI_Mem *)n)->mim_Select == 1)
      {
      strcpy(m.mi_Date , ((struct MI_Mem *)n)->mim_MI.mi_Date);
      strcpy(m.mi_Notice , ((struct MI_Mem *)n)->mim_MI.mi_Notice);
      strcpy(m.mi_Type , ((struct MI_Mem *)n)->mim_MI.mi_Type);
      strcpy(m.mi_Text , ((struct MI_Mem *)n)->mim_MI.mi_Text);
      result = MemoReq(&m);
      if (result)
	{
	strcpy( ((struct MI_Mem *)n)->mim_MI.mi_Date, m.mi_Date);
	strcpy( ((struct MI_Mem *)n)->mim_MI.mi_Notice, m.mi_Notice);
	strcpy( ((struct MI_Mem *)n)->mim_MI.mi_Type, m.mi_Type);
	strcpy( ((struct MI_Mem *)n)->mim_MI.mi_Text, m.mi_Text);
	Remove((struct List *)n);
	MemIns((struct MI_Mem *)n);
	DataAmended=TRUE;
	}
      }
    ((struct MI_Mem *)n)->mim_Select=0;
    n=n->mln_Succ;
    }
  Display_Block(DisplayFirst);
  return TRUE;
  }

/*--------------------------------------------------------------------------
 * Function Add() calls MemoReq() to get data for new memo.
 *  Returns TRUE if no errors found, otherwise FALSE. (Actually,
 *  it currently returns TRUE under all circumstances.
 */
BOOL Add()
  {
  struct Memo_Item m;
  struct MI_Mem *mim;
  BOOL result;

  m.mi_Date[0]='\0';
  m.mi_Notice[0]='\0';
  m.mi_Type[0]='\0';
  m.mi_Text[0]='\0';
  result=MemoReq(&m);
  if (result)
    {
    mim=(struct MI_Mem *)AllocRemember(&RK,sizeof(struct MI_Mem),MEMF_PUBLIC);
    if (!mim) return FALSE;
    strcpy( mim->mim_MI.mi_Date, m.mi_Date);
    strcpy( mim->mim_MI.mi_Notice, m.mi_Notice);
    strcpy( mim->mim_MI.mi_Type, m.mi_Type);
    strcpy( mim->mim_MI.mi_Text, m.mi_Text);
    mim->mim_Select=0;
    result=MemIns(mim);
    if (!result) return FALSE;
    DisplayFirst = (struct MinNode *)mim;
    Display_Block(DisplayFirst);
    DataAmended=TRUE;
    }
  return (TRUE);
  }

/*--------------------------------------------------------------------------
 * Function Del() reads through Memo list and, with the confirmation of the
 *  user, deletes selected memos. The memos are actually just removed from
 *  the list, the memory is not released until the program terminates. (Later
 *  deleted memos could be organised as a separate list and a process made
 *  available for the user to change his/her mind and reinsert any memos?)
 *  Returns TRUE if no errors found, otherwise FALSE. (Actually,
 *  it currently returns TRUE under all circumstances.
 */
BOOL Del()
  {
  struct MinNode *n;
  int result;


  if (LISTEMPTY) return TRUE;
  n=MemListPtr->mlh_Head;
  while (n->mln_Succ)
    {
    if ( ((struct MI_Mem *)n)->mim_Select == 1)
      {
      result = MemoDel((struct MI_Mem *)n);
      if (result == 1)
	{
	Remove((struct Node *)n);
	DataAmended=TRUE;
	if ( n = DisplayFirst)
	  {
	  if (LISTEMPTY)
	    DisplayFirst = NULL;
	  else
	    DisplayFirst = MemListPtr->mlh_Head;
	  }
	Display_Block(DisplayFirst);
	}
      }
    n=n->mln_Succ;
    }
  return TRUE;
  }

/*--------------------------------------------------------------------------
 * Function MemIns() allocates a new MI_Mem structure in memory, copies
 *  data into it from a Memo_Item structure whose address was given as a
 *  parameter and then returns TRUE if no errors found, otherwise FALSE.
 */
BOOL MemIns(struct MI_Mem *m)
  {
  char d1[5],d2[5];
  struct MinNode *n;
  BOOL found;
  int cmp,mnum;

  if (LISTEMPTY)
    {
    AddHead((struct List *)MemListPtr,(struct Node *)m);
    }
  else
    {
    mnum = Month2Num((char *)&(m->mim_MI.mi_Date[3]));
    sprintf(d1, "%02d", mnum);
    d1[2]=m->mim_MI.mi_Date[0];
    d1[3]=m->mim_MI.mi_Date[1];
    d1[4]='\0';
    n=MemListPtr->mlh_Head;
    found=FALSE;
    while ( (!found) && (n->mln_Succ) )
      {
      mnum = Month2Num((char *)&(((struct MI_Mem *)n)->mim_MI.mi_Date[3]));
      sprintf(d2, "%02d", mnum);
      d2[2]=((struct MI_Mem *)n)->mim_MI.mi_Date[0];
      d2[3]=((struct MI_Mem *)n)->mim_MI.mi_Date[1];
      d2[4]='\0';
      cmp=strcmp(d1,d2);
      if ( cmp > 0 )
	{
	n=n->mln_Succ;
	}
      else
	{
	Insert( (struct List *)MemListPtr,(struct Node *)m,(struct Node *)n->mln_Pred);
	found=TRUE;
	}
      }
      if (!found) AddTail( (struct List *)MemListPtr, (struct Node *)m );
    }
  return TRUE;
  }

/* -------------------------------------------------------------------
 *	Function handling Requester allowing addition of new memos and
 *	editing of existing ones
 */
BOOL MemoReq(struct Memo_Item *mim)
{
  BOOL finished = FALSE;
  BOOL ret = FALSE;
  ULONG SignalMask,Signal;
  struct StringInfo *strinfo;

  SetWaitPointer(mm_w);
  DisableGadgets();

  if (!OpenEditWindow())
  {
    strinfo = EditGadgets[GDX_DateGad]->SpecialInfo;
    strcpy(strinfo->Buffer,mim->mi_Date);
    GT_SetGadgetAttrs(EditGadgets[GDX_DateGad],EditWnd,0,
		      GTST_String, strinfo->Buffer,
		      TAG_DONE);
    strinfo = EditGadgets[GDX_NoticeGad]->SpecialInfo;
    strcpy(strinfo->Buffer,mim->mi_Notice);
    GT_SetGadgetAttrs(EditGadgets[GDX_NoticeGad],EditWnd,0,
		      GTST_String, strinfo->Buffer,
		      TAG_DONE);
    strinfo = EditGadgets[GDX_TypeGad]->SpecialInfo;
    strcpy(strinfo->Buffer,mim->mi_Type);
    GT_SetGadgetAttrs(EditGadgets[GDX_TypeGad],EditWnd,0,
		      GTST_String, strinfo->Buffer,
		      TAG_DONE);
    strinfo = EditGadgets[GDX_MemoGad]->SpecialInfo;
    strcpy(strinfo->Buffer,mim->mi_Text);
    GT_SetGadgetAttrs(EditGadgets[GDX_MemoGad],EditWnd,0,
		      GTST_String, strinfo->Buffer,
		      TAG_DONE);
    ActivateGadget(EditGadgets[GDX_DateGad],EditWnd,0);
    SignalMask = 1<<EditWnd->UserPort->mp_SigBit;
    while(!finished)
    {
      Signal = Wait(SignalMask);
      if ((Signal & SignalMask) == SignalMask)
      {
        if (HandleEditIDCMP() == -1)
          finished = TRUE;
      }
    }
    if (memostate)
    {
      strcpy(mim->mi_Date,GetString(EditGadgets[GDX_DateGad]));
      strcpy(mim->mi_Notice,GetString(EditGadgets[GDX_NoticeGad]));
      strcpy(mim->mi_Type,GetString(EditGadgets[GDX_TypeGad]));
      strcpy(mim->mi_Text,GetString(EditGadgets[GDX_MemoGad]));
      ret = TRUE;
    }
  }
  CloseEditWindow();

  EnableGadgets();
  ClearWaitPointer(mm_w);
  return ret;
}

/*======================================================================*/
BOOL MemoDel(struct MI_Mem *memo)
  {
  char *Query[] = {
    "",
    "   Do you want to delete this memo?   ",
    "",
    "", /* Date */
    "", /* Type */
    "", /* Memo Text */
    "",
    '\0' };
  char dbuff[18];   /* "Date : dd-mmm-yy" */
  char tbuff[10];    /* "Type : X" */

  sprintf(tbuff, "Type : %s", memo->mim_MI.mi_Type);
  sprintf(dbuff, "Date : %s", memo->mim_MI.mi_Date);
  Query[3]=dbuff;
  Query[4]=tbuff;
  Query[5]=memo->mim_MI.mi_Text;
  return DisplayC(Query);
  }

/*------------------------------------------------------------------------
 * Some routines to set and remove the wait pointer.
 */

void SetWaitPointer(struct Window *wnd)
{
#if INCLUDE_VERSION >= 39
  if (IntuitionBase->LibNode.lib_Version < 39)
    SetPointer(wnd,waitspritedata,16,16,-5,0);
  else
    SetWindowPointer(wnd,
                     WA_BusyPointer, TRUE,
                     TAG_DONE);
#else
  SetPointer(wnd,waitspritedata,16,16,-5,0);
#endif
}

void ClearWaitPointer(struct Window *win)
{
#if INCLUDE_VERSION >= 39
  if (IntuitionBase->LibNode.lib_Version < 39)
    ClearPointer(win);
  else
    SetWindowPointerA(win,NULL);
#else
  ClearPointer(win);
#endif
}

void DisableGadgets(void)
{
  int counter;

  counter = MEMOS_IN_BLOCK-1;
  while (counter >= 0)
  {
    GT_SetGadgetAttrs(m_gad_checked[counter--],mm_w,0,
      GA_Disabled, TRUE,
      TAG_DONE);
  }
  GT_SetGadgetAttrs(MMGadgets[GDX_MoveBeginGad],mm_w,0,
      GA_Disabled, TRUE,
      TAG_DONE);
  GT_SetGadgetAttrs(MMGadgets[GDX_BackBlockGad],mm_w,0,
      GA_Disabled, TRUE,
      TAG_DONE);
  GT_SetGadgetAttrs(MMGadgets[GDX_BackGad],mm_w,0,
      GA_Disabled, TRUE,
      TAG_DONE);
  GT_SetGadgetAttrs(MMGadgets[GDX_ForwardGad],mm_w,0,
      GA_Disabled, TRUE,
      TAG_DONE);
  GT_SetGadgetAttrs(MMGadgets[GDX_ForwardBlockGad],mm_w,0,
      GA_Disabled, TRUE,
      TAG_DONE);
  GT_SetGadgetAttrs(MMGadgets[GDX_MoveEndGad],mm_w,0,
      GA_Disabled, TRUE,
      TAG_DONE);
  GT_SetGadgetAttrs(MMGadgets[GDX_AddGad],mm_w,0,
      GA_Disabled, TRUE,
      TAG_DONE);
  GT_SetGadgetAttrs(MMGadgets[GDX_DeleteGad],mm_w,0,
      GA_Disabled, TRUE,
      TAG_DONE);
  GT_SetGadgetAttrs(MMGadgets[GDX_EditGad],mm_w,0,
      GA_Disabled, TRUE,
      TAG_DONE);
  GT_SetGadgetAttrs(MMGadgets[GDX_CheckGad],mm_w,0,
      GA_Disabled, TRUE,
      TAG_DONE);
  GT_SetGadgetAttrs(MMGadgets[GDX_ShrinkGad],mm_w,0,
      GA_Disabled, TRUE,
      TAG_DONE);
  GT_SetGadgetAttrs(MMGadgets[GDX_HelpGad],mm_w,0,
      GA_Disabled, TRUE,
      TAG_DONE);
}

void EnableGadgets(void)
{
  GT_SetGadgetAttrs(MMGadgets[GDX_MoveBeginGad],mm_w,0,
      GA_Disabled, FALSE,
      TAG_DONE);
  GT_SetGadgetAttrs(MMGadgets[GDX_BackBlockGad],mm_w,0,
      GA_Disabled, FALSE,
      TAG_DONE);
  GT_SetGadgetAttrs(MMGadgets[GDX_BackGad],mm_w,0,
      GA_Disabled, FALSE,
      TAG_DONE);
  GT_SetGadgetAttrs(MMGadgets[GDX_ForwardGad],mm_w,0,
      GA_Disabled, FALSE,
      TAG_DONE);
  GT_SetGadgetAttrs(MMGadgets[GDX_ForwardBlockGad],mm_w,0,
      GA_Disabled, FALSE,
      TAG_DONE);
  GT_SetGadgetAttrs(MMGadgets[GDX_MoveEndGad],mm_w,0,
      GA_Disabled, FALSE,
      TAG_DONE);
  GT_SetGadgetAttrs(MMGadgets[GDX_AddGad],mm_w,0,
      GA_Disabled, FALSE,
      TAG_DONE);
  GT_SetGadgetAttrs(MMGadgets[GDX_DeleteGad],mm_w,0,
      GA_Disabled, FALSE,
      TAG_DONE);
  GT_SetGadgetAttrs(MMGadgets[GDX_EditGad],mm_w,0,
      GA_Disabled, FALSE,
      TAG_DONE);
  GT_SetGadgetAttrs(MMGadgets[GDX_CheckGad],mm_w,0,
      GA_Disabled, FALSE,
      TAG_DONE);
  GT_SetGadgetAttrs(MMGadgets[GDX_ShrinkGad],mm_w,0,
      GA_Disabled, FALSE,
      TAG_DONE);
  GT_SetGadgetAttrs(MMGadgets[GDX_HelpGad],mm_w,0,
      GA_Disabled, FALSE,
      TAG_DONE);

  Display_Block(DisplayFirst);
}
