#include "resman.h"

struct MenuNode  *LoadMenu(char *);
BOOL              FindFunc(char *,struct FuncName *,int,USHORT *,UBYTE *);
int               ReadMenuFuncs(char *,struct FuncName **);
void              RMFreeMenu(struct MenuNode *);
void              RemFromPorts(struct MenuNode *);
void              LoadCustomMenu(struct PortNode *,UBYTE,char *);
void              FreeCustomMenu(struct PortNode *);

/// LoadMenu
struct MenuNode *LoadMenu(char *name)
{BPTR                      mfd;
 struct FuncName          *funclist;
 struct MenuNode          *mun;
 struct CompiledMenuEntry *cme;
 struct BatchEntry        *be;
 struct BatchEntry         dbe;
 struct MenuHeader         mh;
 struct MenuEntry          me;

 int    numfuncs;
 ULONG  size;
 long   count;
 char   filename[80];

 ASPrintf(NULL, filename, "DLGConfig:Menu/%s.menun", name);
 if (FileSize(filename, &size)==-1)  return(NULL);
 if (!size)                          return(NULL);

 mfd = Open(filename, MODE_OLDFILE);
 if (!mfd)  return(NULL);
 Read(mfd, &mh, sizeof(struct MenuHeader));

 mun = (struct MenuNode *)malloc(sizeof(struct MenuNode) + strlen(name) + strlen(mh.prompt) + 2);
 if (!mun)
    {Close(mfd);
     return(NULL);
    }

 mun->mn.users        = 0;
 mun->mn.type         = 0;
 mun->mn.node.ln_Type = NODE_MENU;

 mun->numentries      = (size-sizeof(struct MenuHeader))/sizeof(struct MenuEntry);
 mun->entries         =  malloc(mun->numentries * sizeof(struct CompiledMenuEntry));

 mun->mn.node.ln_Name = (char *)mun + sizeof(struct MenuNode);
 mun->prompt          =  stpcpy(mun->mn.node.ln_Name, name);
                         strcpy(++mun->prompt, mh.prompt);

 mun->name = NULL;
 if (*mh.name)
    {mun->name = malloc(strlen(mh.name) + 1);
     strcpy(mun->name, mh.name);
    }

 mun->action   = NULL;
 mun->numentry = mh.numentry;
 mun->columns  = mh.columns;

 InitList(&(mun->mn.activelocks));
 InitList(&(mun->mn.locklist));

 ASPrintf(NULL, filename, "DLGConfig:Menu/Funcs/%s.funcs", mh.module);
 numfuncs = ReadMenuFuncs(filename, &funclist);

 for(count = 0, cme = mun->entries; count < mun->numentries; cme++, count++)
    {Read(mfd, &me, sizeof(struct MenuEntry));

     cme->command    = me.command;
     cme->visibility = me.visibility;
     cme->logvalue   = me.logvalue;
     cme->cost       = me.cost;
     cme->blist      = NULL;

     cme->description = NULL;
     if (*me.description)
        {cme->description = (char *)malloc(strlen(me.description)+1);
         strcpy(cme->description, me.description);
        }

     cme->helpfile = NULL;
     if (*me.helpfile)
        {cme->helpfile = (char *)malloc(strlen(me.helpfile)+1);
         strcpy(cme->helpfile,me.helpfile);
        }

     dbe.type     = me.type;
     dbe.llev     = me.llev;
     dbe.ulev     = me.ulev;
     dbe.flags    = me.flags;
     dbe.rate     = me.rate;
     dbe.maxtime  = me.maxtime;
     dbe.priority = me.priority;

     if (me.type != MENU_DLGBATCH)
        {cme->blist = (struct BatchEntry *)malloc(sizeof(struct BatchEntry));
         be         =  cme->blist;

         movmem(&dbe, be, sizeof(struct BatchEntry));

         be->action = NULL;
         if (*me.action)
            {be->action = (char *)malloc(strlen(me.action)+1);
             strcpy(be->action, me.action);
            }

         be->program = NULL;
         if (*me.program)
            {if (be->type==MENU_BUILTIN)
           {FindFunc(me.program,funclist,numfuncs,&(be->function),&(be->functype));
            be->program = NULL;
                }
              else
                {be->program = (char *)malloc(strlen(me.program)+1);
                 strcpy(be->program,me.program);
                }
            }

         be->next = NULL;
        }
      else
        {if (!ReadDLGBatch(&(cme->blist),&dbe,me.program,me.action,funclist,numfuncs))
            {cme->blist = NULL;
            }
        }
    }

 AddTail(&ResourceList,(struct Node *)mun);
 Close(mfd);
 if (numfuncs)  free(funclist);
 return(mun);
}
//-

/// FindFunc
BOOL FindFunc(char *fname,struct FuncName *funclist,int numfuncs,USHORT *function,UBYTE *functype)
{char *fn;

 if (numfuncs)
    {fn = DLGBinSearch((char *)funclist, fname, sizeof(struct FuncName), sizeof(struct FuncName), numfuncs);
     if (fn)
        {*functype =  1;
         *function = (fn - (char *)funclist) / sizeof(struct FuncName);
         return(TRUE);
        }
    }

 fn = DLGBinSearch((char *)internalfuncs, fname, sizeof(struct FuncName), sizeof(struct FuncName), NUMINTERNAL);
 if (fn)
    {*functype =  0;
     *function = (fn - (char *)internalfuncs) / sizeof(struct FuncName);
     return(TRUE);
    }

 return(FALSE);
}
//-

/// ReadMenuFuncs
int ReadMenuFuncs(char *filename,struct FuncName **funclist)

{BPTR   ffp;
 struct FuncName *fname;
 long   number;
 long   len;
 ULONG  size;
 char   buf[64];

 if (FileSize(filename, &size)==-1)   return(0);
 if (!size)                           return(0);

 ffp = Open(filename, MODE_OLDFILE);
 if (!ffp)  return(0);

 *funclist  = NULL;
 number     =  0;
 while(FGets(ffp, buf, 64))
       number++;

 if (number)
    {fname    = malloc(number * sizeof(struct FuncName));
    *funclist = fname;
     Seek(ffp, 0, OFFSET_BEGINNING);

     while(FGets(ffp, buf, 64))
          {len      = strlen(buf) - 1;
           buf[len] = 0;
           strcpy(fname->name, buf);
           fname++;
          }
    }

 Close(ffp);
 return(number);
}
//-

/// RMFreeMenu
void RMFreeMenu(struct MenuNode *mun)

{struct CompiledMenuEntry *cme;
 struct BatchEntry        *be;
 struct BatchEntry        *tbe;
 UBYTE  count;

 for(count = 0, cme = mun->entries; count < mun->numentries; cme++, count++)
    {if (cme->description)  free(cme->description);
     if (cme->helpfile)     free(cme->helpfile);

     be = cme->blist;
     while(be)
          {if (be->program)  free(be->program);
           if (be->action)   free(be->action);
           tbe = be;
           be  = be->next;
           free(tbe);
          }
    }


 Remove((struct Node *)mun);

 if (mun->name)    free(mun->name);
 if (mun->action)  free(mun->action);

 free(mun->entries);
 free(mun);
}
//-

/// RemFromPorts
void RemFromPorts(struct MenuNode *mun)

{struct Node     *nd;
 struct PortNode *pn;

 nd = ResourceList.lh_Head;
 while(nd->ln_Succ)
      {if (nd->ln_Type==NODE_PORT)
          {pn = (struct PortNode *)nd;
           if (pn->menu==mun)
              {pn->menu = NULL;
               if (pn->custnum)  FreeCustomMenu(pn);
              }
          }
       nd = nd->ln_Succ;
      }
}
//-

/// LoadCustomMenu
void LoadCustomMenu(struct PortNode *port,UBYTE number,char *name)

{char  filename[64];
 ULONG size;

 port->custnov = NULL;
 port->custint = NULL;

 ASPrintf(NULL, filename, "DLGConfig:menu/%s.nov.%d", name, number);
 if (FileSize(filename, &size)!=-1)
    {if (port->custnov = malloc(size+1))
        {if (GetFirstStruct(filename, port->custnov, size)==-1)
            {free(port->custnov);
             port->custnov = NULL;
            }
          else
            {port->custnov[size] = 0;
            }
        }
    }

 ASPrintf(NULL, filename, "DLGConfig:menu/%s.int.%d", name, number);
 if (FileSize(filename, &size)!=-1)
    {if (port->custint = malloc(size+1))
        {if (GetFirstStruct(filename, port->custint, size)==-1)
            {free(port->custint);
        port->custint = NULL;
            }
          else
            {port->custint[size] = 0;
            }
        }
    }

 if (port->custnov || port->custint)  port->custnum=number;
}
//-

/// FreeCustomMenu
void FreeCustomMenu(struct PortNode *port)

{if (port->custnov)  free(port->custnov);
 if (port->custint)  free(port->custint);

 port->custnov = NULL;
 port->custint = NULL;
 port->custnum = -1;
}
//-
