#include <debug.h>
#include <intuition/intuition.h>
#include <graphics/text.h>
#include "mpp.h"
#include <intuition/intuitionbase.h>
#include <exec/execbase.h>
#include <clib/extras_protos.h>
#include <stdio.h>
#include <math.h>
#include <dos/dosextens.h>

#define LGD_LIST    0
#define LGD_OK      1
#define LGD_CANCEL  2

struct ListRequester
{
  struct Window     *lr_Window;
  APTR               lr_VisualInfo;
  struct LG_Control *lr_GadControl;
  struct List       *lr_List;
  BOOL   lr_RetVal;
};

void CreateDefaultModeList(struct List *List);
struct ModeNode *CreateModeNode(ULONG ID);
//void FreeDefaultModeList(struct List *List);

struct Gadget  *MakeListGadget  (struct List *List);
         void  RemListGadget    (void);

extern struct Screen *Scr;
extern struct ExecBase *SysBase;
extern struct IntuitionBase *IntuitionBase;
extern struct TextAttr *TAttr;
extern struct Window *Win;

BOOL SelectName(struct DefaultNode *DN)
{
  STRPTR name,namework;
  struct List namelist,*tasklist;
  struct Node *namenode,*execnode;
  struct Screen *scr;
  struct Task   *task;
  LONG l,
       ok=TRUE,
       lock,
       item;
  BOOL rv=FALSE;
  ULONG type;
  UBYTE cliname[256];
  
  if(DN)
  {
    NewList(&namelist);
    if(DN->Type<3)
    {
      switch(DN->Type)
      {
        case 0:
          // Create a list of program names
          Disable();
          tasklist=&SysBase->TaskReady;
          for(l=0;l<2;l++)
          {
            task=(struct Task *)tasklist[l].lh_Head;

            while(task->tc_Node.ln_Succ)
            {
              execnode=(struct Node *)task;
              name=execnode->ln_Name;
              type=execnode->ln_Type;
              
              if(type==NT_PROCESS)
              {
                struct Process *proc;
                struct CommandLineInterface *cli;
                
                //kprintf("Process ");
                
                proc=(struct Process *)task;
                
                if(proc->pr_CLI)
                {
                  cli=(struct CommandLineInterface *)BADDR(proc->pr_CLI);
                  namework=(STRPTR)BADDR(cli->cli_CommandName);
                  if(namework[0])
                  {
                    strncpy(cliname,&namework[1],namework[0]);
                    cliname[namework[0]]=0;
                    name=cliname;
                  }
                }
              }
              //else
                //kprintf("Task    ");
                
              //kprintf("%s %ld\n",name,type);  
              
              if(name)
              {
                if(namenode=AllocNameNode(name))
                {
                  namenode->ln_Type=type;
                  namenode->ln_Pri=execnode->ln_Pri;
                  EnqueueName(&namelist,namenode);
                  
                }
                //else
                //  ok=FALSE;
              }
              task=(struct Task *)task->tc_Node.ln_Succ;
            }
          }
          Enable();
          break;
        case 1:          
          // Create a list of screens
          lock=LockIBase(0);
          scr=IntuitionBase->FirstScreen;
          while(scr && ok)
          {
            if(scr->Title)
            {
              if(namenode=AllocNameNode(scr->Title))
                EnqueueName(&namelist,namenode);
              else
                ok=FALSE;
            }
            scr=scr->NextScreen;
          }
          UnlockIBase(lock);
          break;
        case 2:
          CreateDefaultModeList(&namelist);
          break;
      }
      if((item=SelectReq(&namelist,GetString(MSG_SELWIN_PROGRAMS + DN->Type))) >=0)
      {
        STRPTR dummy;
        
        namenode=namelist.lh_Head;
        while(item)
        {
          namenode=namenode->ln_Succ;
          item--;
        }
        dummy=DN->Def_Node.ln_Name;
        // The old name will be freed with FreeNameNodes()
        DN->Def_Node.ln_Name=namenode->ln_Name;
        namenode->ln_Name=dummy;
        if(DN->Type==2)
          DN->OrigDisplayID=((struct ModeNode *)namenode)->mn_DisplayID;
        rv=TRUE;
      }
      FreeNameNodes(&namelist);
    }
    /*
    else // dn->Type==2
    {
      if(DN->Type==2)
      {
        STRPTR scrname;
        
        if(SelectScreenMode(Win,DN,TRUE))
        {
          if(scrname=GetModeName(DN->OrigDisplayID))
          {
            FreeVec(DN->Def_Node.ln_Name);
            DN->Def_Node.ln_Name=scrname;
            rv=TRUE;
          }
        }
      }
    }*/
  }
  return(rv);
}

struct Node *AllocNameNode(STRPTR Name)
{
  struct Node *n;
  LONG l;
  
  if(n=AllocVec(sizeof(struct Node),MEMF_PUBLIC|MEMF_NO_EXPUNGE|MEMF_CLEAR))
  {
    n->ln_Pri=0;
    l=strlen(Name);
    if(n->ln_Name=AllocVec(l+1,MEMF_PUBLIC|MEMF_NO_EXPUNGE))
    {
      strncpy(n->ln_Name,Name,l);
      n->ln_Name[l]=0;
      return(n);
    }
    FreeVec(n);
  }
  return(0);
}

void FreeNameNodes(struct List *List)
{
  struct Node *n;
  
  while(n=RemHead(List))
  {
    FreeVec(n->ln_Name);
    FreeVec(n);
  }
}

WORD ListWinLeft,ListWinTop,ListWinWidth,ListWinHeight;
BOOL ListFirstTime=TRUE;
APTR ListVI;
ULONG ListGadCount;
struct Window *ListWin;
struct Gadget *ListContext,*ListLV;

/* Opens the list requester */
LONG SelectReq(struct List *List, STRPTR WinTitle)
{
  LOMG nodes;
  struct Requester *req;
  LONG rv=-1;
  struct IntuiMessage *imsg;
  BOOL ok=TRUE;
  WORD x1,y1,x2,y2;
  LONG PrevSeconds =0,
       PrevMicros  =0,
       PrevCode    =-1;
  
  if(ListFirstTime)
  {
    ListWinWidth=   Win->Width/2;
    ListWinHeight=  Win->Height-16;
    ListWinLeft=    Win->LeftEdge+Win->Width/2-ListWinWidth/2;
    ListWinTop=     Win->TopEdge+8;
    ListWinWidth=   max(ListWinWidth,50);
    ListWinHeight=  max(ListWinHeight,50);
    ListFirstTime=FALSE;
  }
  
  req=Busy(Win);
  if(ListWin=OpenWindowTags(0,WA_Left,          ListWinLeft,
                              WA_Top,           ListWinTop,
                              WA_Width,         ListWinWidth,
                              WA_Height,        ListWinHeight,
                              WA_MinWidth,      50,
                              WA_MinHeight,     50,
                              WA_MaxWidth,      -1,
                              WA_MaxHeight,     -1,
                              WA_Title,         WinTitle,
                              WA_DragBar,       TRUE,
                              WA_SizeGadget,    TRUE,
                              WA_SizeBBottom,   TRUE,
                              WA_DepthGadget,   TRUE,
                              WA_SimpleRefresh, TRUE    ,
                              WA_CloseGadget,   TRUE,
                              WA_CustomScreen,  Scr,
                              WA_Activate,      TRUE,
                              WA_IDCMP,         IDCMP_REFRESHWINDOW |
                                                IDCMP_CLOSEWINDOW   |
                                                IDCMP_NEWSIZE       |
                                                IDCMP_VANILLAKEY    |
                                                IDCMP_RAWKEY        |
                                                LISTVIEWIDCMP,
                              TAG_DONE))
  {
    x1=ListWin->BorderLeft;
    y1=ListWin->BorderTop;
    if(ListVI=GetVisualInfo(ListWin->WScreen,0))
    {
      if(MakeListGadget(List))
      {
        nodes=CountNodes(List);
        while(ok)
        {
          WaitPort(ListWin->UserPort);
          while(imsg=GT_GetIMsg(ListWin->UserPort))
          {
            switch(imsg->Class)
            {
              case IDCMP_REFRESHWINDOW:
                GT_BeginRefresh(ListWin);
                GT_EndRefresh(ListWin,TRUE);
                break;
              case IDCMP_CLOSEWINDOW:
                ok=FALSE;
                rv=-1;
                break;
              case IDCMP_GADGETUP:
                if(DoubleClick(PrevSeconds,PrevMicros,imsg->Seconds,imsg->Micros) 
                   && PrevCode==imsg->Code)
                {
                  ok=FALSE;
                  rv=imsg->Code;
                }
                else
                {
                  PrevSeconds=imsg->Seconds;
                  PrevMicros =imsg->Micros;
                  PrevCode   =imsg->Code;
                }
                break;
              case IDCMP_NEWSIZE:
                x2=ListWin->Width -ListWin->BorderRight-1;
                y2=ListWin->Height-ListWin->BorderBottom-1;
                RemListGadget();
                if(x2>x1 && y2>y1)
                  EraseRect(ListWin->RPort,x1,y1,x2,y2);
                RefreshWindowFrame(ListWin);
                if(!MakeListGadget(List))
                { 
                  ok=FALSE;
                  rv=-1;
                }
                else
                {
                  ListWinWidth=   ListWin->Width;
                  ListWinHeight=  ListWin->Height;
                  ListWinLeft=    ListWin->LeftEdge;
                  ListWinTop=     ListWin->TopEdge;
                }
                break;
              case IDCMP_RAWKEY:
                switch(imsg->Code)
                {
                  case CURSORUP:
                    PrevCode--;
                    if(PrevCode<0)
                      PrevCode=nodes-1;
                    break;
                  case CURSORDOWN:
                    PrevCode++;
                    if(PrevCode>=nodes)
                      PrevCode=0;
                    break;
                }
                GT_SetGadgetAttrs(
                    
            }
            GT_ReplyIMsg(imsg);
          }
        }
        RemListGadget();
      }
      FreeVisualInfo(ListVI);
    }
    CloseWindow(ListWin);
  }
  NotBusy(Win,req);
  return(rv);
}

struct Gadget *MakeListGadget(struct List *List)
{
  struct Gadget *gad;
  struct NewGadget listng={0};
 
  listng.ng_VisualInfo=ListVI;
  listng.ng_TextAttr  =TAttr;
  listng.ng_LeftEdge  =ListWin->BorderLeft  +4;
  listng.ng_TopEdge   =ListWin->BorderTop   +4;
  listng.ng_Width     =ListWin->Width-ListWin->BorderLeft-ListWin->BorderRight-8;
  listng.ng_Height    =ListWin->Height-ListWin->BorderTop-ListWin->BorderBottom-8;
  
  gad=CreateContext(&ListContext);

  ListLV=gad=CreateGadget(LISTVIEW_KIND, gad, &listng,
                          GTLV_Labels           ,List,
                          GTLV_ShowSelected     ,0,
                          TAG_DONE);
  if(!gad)
  {
    FreeGadgets(ListContext);
    ListContext=0;
    return(0);
  }
  else
  {
    struct Gadget *cgad;
    
    ListGadCount=0;
    cgad=ListContext;
    
    while(cgad)
    {
      ListGadCount++;
      cgad=cgad->NextGadget;
    }
    
    AddGList(ListWin,ListContext,-1,-1,0);
    RefreshGList(ListContext,ListWin,0,ListGadCount);
    GT_RefreshWindow(ListWin,NULL);
  }
  return(gad);
}

void RemListGadget(void)
{
  if(ListContext)
  {
    RemoveGList(ListWin,ListContext,ListGadCount);
    FreeGadgets(ListContext);
    ListContext=0;
  }
}


void CreateDefaultModeList(struct List *List)
{
  struct DisplayInfo di;
  struct ModeNode    *mn;
  ULONG previd=MONITOR_ID_MASK,id;
  
  id=NextDisplayInfo(INVALID_ID);

  while(id!=INVALID_ID)
  {
    if(previd != (id & MONITOR_ID_MASK))
    { // create an entry for all screen modes.
      previd=(id & MONITOR_ID_MASK);
      if(mn=CreateModeNode(id | ALL_MODES))
        EnqueueName(List,(struct Node *)mn);      
    } 
    
    if(GetDisplayInfoData(0,(UBYTE *)&di,sizeof(di),DTAG_DISP,id))
    if(!(di.PropertyFlags & SPECIAL_FLAGS)) // no HAM, EHB, 2PF etc.
    {
      if(mn=CreateModeNode(id))
      
      if(mn=AllocVec(sizeof(struct ModeNode),MEMF_PUBLIC|MEMF_CLEAR))
      {
        if(mn->mn_Node.ln_Name=GetModeName(id))
          EnqueueName(List,(struct Node *)mn);
      }
    }
    id=NextDisplayInfo(id);
  }
}

struct ModeNode *CreateModeNode(ULONG ID)
{
  struct ModeNode *mn;
  
  if(mn=AllocVec(sizeof(struct ModeNode),MEMF_PUBLIC|MEMF_CLEAR))
  {
    if(mn->mn_Node.ln_Name=GetModeName(ID))
    {
      mn->mn_DisplayID=ID;
      return(mn);
    }
    FreeVec(mn);
  }
  return(0);
}


struct LG_Control *LayoutListGads(struct ListRequester *LReq)
{
  WORD width,height,
  struct LG_Control *lr_control=0;
  //STRPTR ok,cancel;

  if(LReq)
  {
    if(LReq->lr_VisualInfo && LReq->lr_Window)
    {
      rp=LReq->lr_Window->RPort; 
 
      width =LReq->lr_Window->Width  - LReq->lr_Window->BorderLeft- LReq->lr_Window->BorderRight  - 8;
      height=LReq->lr_Window->Height - LReq->lr_Window->BorderTop - LReq->lr_Window->BorderBottom - 8;
 
      lr_control=LG_CreateGadgets( LG_VisualInfo        ,LReq->lr_VisualInfo,
                                   LG_UseWindowOffsets  ,PWin,
                                   LG_EraseRemoved      ,FALSE,
                                   LG_OffsetX           ,4,
                                   LG_OffsetY           ,4,
                                   LG_TextAttr          ,TAttr,
                                   
                                   /* List Gadget */
                                   LG_GadgetKind        ,LISTVIEW_KIND,
                                   LG_GadgetID          ,LGD_LIST,
                                   LG_Width             ,width,
                                   LG_Height            ,height,
                                   LG_GadgetTags        ,2,
                                   GTLV_Labels          ,List,
                                   GTLV_ShowSelected    ,0,
                                   LG_CreateGadget      ,0,
                                 
                                   TAG_DONE);
    }
  }
  return(lr_control);
}                                 
