#define INCL_DOS
#define INCL_WIN

#include <os2.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "fm3dll.h"
#include "fm3dlg.h"
#include "fm3str.h"

#pragma data_seg(DATA1)
#pragma alloc_text(OBJCNR,ProcessDir,FillCnrs,ObjCnrDlgProc)

typedef struct {
  CHAR *filename;
  HWND  hwndCnr;
  CHAR *stopflag;
} DIRSIZE;

typedef struct {
  CHAR *dirname;
  CHAR  stopflag;
  BOOL  dying;
  BOOL  working;
} TEMP;

static HWND objcnrwnd = (HWND)0;


static VOID ProcessDir (HWND hwndCnr,CHAR *filename,PCNRITEM pciParent,
                        CHAR *stopflag) {

  CHAR          maskstr[CCHMAXPATH],*endpath,*p;
  ULONG         nm,ulM;
  HDIR          hdir;
  FILEFINDBUF3 *ffb,*fft;
  APIRET        rc;
  RECORDINSERT  ri;
  PCNRITEM      pciP;

  ffb = malloc(sizeof(FILEFINDBUF3));
  if(!ffb)
    return;
  strcpy(maskstr,filename);
  if(maskstr[strlen(maskstr) - 1] != '\\')
    strcat(maskstr,"\\");
  endpath = &maskstr[strlen(maskstr)];
  strcat(maskstr,"*");
  hdir = HDIR_CREATE;
  nm = 1L;
  rc = DosFindFirst(filename, &hdir,
                    FILE_NORMAL | FILE_READONLY | FILE_ARCHIVED |
                    FILE_SYSTEM | FILE_HIDDEN | MUST_HAVE_DIRECTORY,
                    ffb,sizeof(FILEFINDBUF3),&nm,FIL_STANDARD);
  if(!rc)
    DosFindClose(hdir);

  if(rc) {    /* work around furshluginer FAT bug... */
    if(IsRoot(filename))
      rc = 0;
  }

  if((!rc && (ffb->attrFile & FILE_DIRECTORY))) {
    pciP = WinSendMsg(hwndCnr,CM_ALLOCRECORD,MPFROMLONG(EXTRA_RECORD_BYTES2),
                      MPFROMLONG(1L));
    if(!pciP) {
      free(ffb);
      return;
    }
    strcpy(pciP->szFileName,filename);
    pciP->pszDispAttr = pciP->szDispAttr;
    pciP->pszSubject = pciP->subject;
    pciP->pszLongname = pciP->Longname;
    pciP->pszDispAttr = pciP->szDispAttr;
    *pciP->szDispAttr = *pciP->Longname = *pciP->subject = 0;
    if(strlen(filename) < 4)
      pciP->pszFileName = pciP->szFileName;
    else {
      p = strrchr(pciP->szFileName,'\\');
      if(!p)
        pciP->pszFileName = pciP->szFileName;
      else if(*(p + 1))
        p++;
      pciP->pszFileName = p;
    }
    pciP->rc.pszIcon = pciP->pszFileName;
    if(fForceUpper)
      strupr(pciP->szFileName);
    else if(fForceLower)
      strlwr(pciP->szFileName);
    pciP->rc.flRecordAttr |= CRA_RECORDREADONLY;
  }
  else {
    free(ffb);
    Dos_Error(MB_ENTER,
              rc,
              HWND_DESKTOP,
              __FILE__,
              __LINE__,
              GetPString(IDS_CANTFINDDIRTEXT),
              filename);
    return;
  }
  {
    HPOINTER hptr;

    hptr = WinLoadFileIcon(pciP->szFileName, FALSE);
    if(hptr)
      pciP->rc.hptrIcon = hptr;
  }
  if(!pciP->rc.hptrIcon || pciP->rc.hptrIcon == hptrFile) /* OS/2 bug bug bug bug */
    pciP->rc.hptrIcon = hptrDir;
  memset(&ri,0,sizeof(RECORDINSERT));
  ri.cb                 = sizeof(RECORDINSERT);
  ri.pRecordOrder       = (PRECORDCORE)CMA_END;
  ri.pRecordParent      = (PRECORDCORE)pciParent;
  ri.zOrder             = (USHORT)CMA_TOP;
  ri.cRecordsInsert     = 1L;
  ri.fInvalidateRecord  = TRUE;
  if(!WinSendMsg(hwndCnr,CM_INSERTRECORD,MPFROMP(pciP),MPFROMP(&ri))) {
    free(ffb);
    return;
  }
  hdir = HDIR_CREATE;
  if(!isalpha(*maskstr) || maskstr[1] != ':' || maskstr[2] != '\\' ||
     ((driveflags[toupper(*maskstr) - 'A'] & DRIVE_REMOTE) && fRemoteBug))
    ulM = 1L;
  else
    ulM = min(FilesToGet,225);
  if(ulM > 1L) {
    fft = realloc(ffb, sizeof(FILEFINDBUF3) * ulM);
    if(!fft)
      ulM = 1L;
    else
      ffb = fft;
  }
  nm = ulM;
  rc = DosFindFirst(maskstr, &hdir,
                    FILE_NORMAL | FILE_READONLY | FILE_ARCHIVED |
                    FILE_SYSTEM | FILE_HIDDEN | MUST_HAVE_DIRECTORY,ffb,
                    sizeof(FILEFINDBUF3) * ulM,&nm,FIL_STANDARD);
  if(!rc) {

    register PBYTE fb = (PBYTE)ffb;
    FILEFINDBUF3  *pffbFile;
    ULONG          x;

    while(!rc) {
      for(x = 0L;x < nm;x++) {
        pffbFile = (FILEFINDBUF3 *)fb;
        if(*stopflag)
          break;
        if((pffbFile->attrFile & FILE_DIRECTORY) &&
           (*pffbFile->achName != '.' || (pffbFile->achName[1] &&
            pffbFile->achName[1] != '.'))) {
          strcpy(endpath,pffbFile->achName);
          ProcessDir(hwndCnr,maskstr,pciP,stopflag);
        }
        if(!pffbFile->oNextEntryOffset)
          break;
        fb += pffbFile->oNextEntryOffset;
      }
      DosSleep(0L);
      if(*stopflag)
        break;
      nm = ulM;
      rc = DosFindNext(hdir,ffb,sizeof(FILEFINDBUF3) * ulM,&nm);
    }
    DosFindClose(hdir);
  }
  free(ffb);
  WinSendMsg(hwndCnr,CM_INVALIDATERECORD,MPFROMP(&pciP),
             MPFROM2SHORT(1,0));
}


static VOID FillCnrs (VOID *args) {

  HAB           hab;
  HMQ           hmq;
  DIRSIZE      *dirsize = (DIRSIZE *)args;

  if(!dirsize)
    return;

  DosError(FERR_DISABLEHARDERR);

  hab = WinInitialize(0);
  if(hab) {
    hmq = WinCreateMsgQueue(hab,0);
    if(hmq) {
      WinCancelShutdown(hmq,TRUE);
      ProcessDir(dirsize->hwndCnr,dirsize->filename,(PCNRITEM)NULL,
                 dirsize->stopflag);
      DosPostEventSem(CompactSem);
      WinDestroyMsgQueue(hmq);
    }
    WinTerminate(hab);
  }
  PostMsg(WinQueryWindow(dirsize->hwndCnr,QW_PARENT),UM_CONTAINER_FILLED,
             MPVOID,MPVOID);
  free(dirsize);
}


MRESULT EXPENTRY ObjCnrDlgProc (HWND hwnd,ULONG msg,MPARAM mp1,MPARAM mp2) {

  TEMP *data;

  switch(msg) {
    case WM_INITDLG:
      if(objcnrwnd || !mp2) {
        if(objcnrwnd) {
          WinSetWindowPos(objcnrwnd,HWND_TOP,0,0,0,0,
                          SWP_RESTORE | SWP_SHOW | SWP_ACTIVATE | SWP_ZORDER);
          DosBeep(1000,100);
        }
        else
          DosBeep(50,100);
        WinDismissDlg(hwnd,0);
        break;
      }
      objcnrwnd = hwnd;
      data = malloc(sizeof(TEMP));
      if(!data) {
        WinDismissDlg(hwnd,0);
        break;
      }
      memset(data,0,sizeof(TEMP));
      data->dirname = (CHAR *)mp2;
      WinSetWindowPtr(hwnd,0,(PVOID)data);
      if(*data->dirname)
        WinSetDlgItemText(hwnd,OBJCNR_DIR,data->dirname);
      {
        DIRSIZE *dirsize;

        dirsize = malloc(sizeof(DIRSIZE));
        if(!dirsize) {
          WinDismissDlg(hwnd,0);
          break;
        }
        dirsize->stopflag = (CHAR *)&data->stopflag;
        dirsize->filename = data->dirname;
        dirsize->hwndCnr = WinWindowFromID(hwnd,OBJCNR_CNR);
        if(_beginthread(FillCnrs,NULL,65536 * 8,(PVOID)dirsize) == -1) {
          free(dirsize);
          WinDismissDlg(hwnd,0);
          break;
        }
        else
          data->working = TRUE;
      }
      PostMsg(hwnd,UM_SETUP,MPVOID,MPVOID);
      break;

    case UM_SETUP:
//      WinEnableWindowUpdate(WinWindowFromID(hwnd,OBJCNR_CNR),FALSE);
      {
        CNRINFO    cnri;

        memset(&cnri,0,sizeof(CNRINFO));
        cnri.cb = sizeof(CNRINFO);
        WinSendDlgItemMsg(hwnd,OBJCNR_CNR,CM_QUERYCNRINFO,
                          MPFROMP(&cnri),MPFROMLONG(sizeof(CNRINFO)));
        cnri.cyLineSpacing = 0;
        cnri.cxTreeIndent = 12L;
        cnri.pszCnrTitle = GetPString(IDS_WORKINGTEXT);
        cnri.flWindowAttr = CV_TREE | CV_FLOW |
                            CA_CONTAINERTITLE | CA_TITLESEPARATOR |
                            CA_TREELINE;
        if(WinQueryWindowUShort(hwnd,QWS_ID) == QTREE_FRAME)
          cnri.flWindowAttr |= CV_MINI;
        WinSendDlgItemMsg(hwnd,OBJCNR_CNR,CM_SETCNRINFO,MPFROMP(&cnri),
                          MPFROMLONG(CMA_FLWINDOWATTR | CMA_LINESPACING |
                                     CMA_CXTREEINDENT));
      }
      return 0;

    case UM_CONTAINER_FILLED:
      WinSetDlgItemText(hwnd,
                        OBJCNR_NOTE,
                        NullStr);
//      WinEnableWindowUpdate(WinWindowFromID(hwnd,OBJCNR_CNR),TRUE);
      WinSendDlgItemMsg(hwnd,OBJCNR_CNR,CM_INVALIDATERECORD,MPVOID,
                        MPFROM2SHORT(0,CMA_ERASE | CMA_INVALIDATE));
      data = INSTDATA(hwnd);
      if(data) {
        data->working = FALSE;
        if(data->dying)
          WinDismissDlg(hwnd,0);
        {
          PCNRITEM pci;
          USHORT id;

          id = WinQueryWindowUShort(hwnd,QWS_ID);
          pci = (PCNRITEM)WinSendDlgItemMsg(hwnd,OBJCNR_CNR,
                                            CM_QUERYRECORD,
                                            MPVOID,
                                            MPFROM2SHORT(CMA_FIRST,
                                                         CMA_ITEMORDER));
          if(pci && (INT)pci != -1) {
            ExpandAll(WinWindowFromID(hwnd,OBJCNR_CNR),TRUE,pci);
            if(id == QTREE_FRAME)
              pci = (PCNRITEM)WinSendDlgItemMsg(hwnd,OBJCNR_CNR,
                                                CM_QUERYRECORD,
                                                MPFROMP(pci),
                                                MPFROM2SHORT(CMA_FIRSTCHILD,
                                                             CMA_ITEMORDER));
          }
          if((!pci || (INT)pci == -1) && id == QTREE_FRAME) {
            Notify(GetPString(IDS_NODIRSUNDERTEXT));
            WinDismissDlg(hwnd,0);
            break;
          }
        }
      }
      return 0;

    case WM_CONTROL:
      switch(SHORT1FROMMP(mp1)) {
        case OBJCNR_CNR:
          if(SHORT2FROMMP(mp1) == CN_ENTER) {

            PCNRITEM pci = (PCNRITEM)((PNOTIFYRECORDENTER)mp2)->pRecord;

            if(pci && (INT)pci != -1)
              WinSendDlgItemMsg(hwnd,DID_OK,BM_CLICK,MPVOID,MPVOID);
          }
          break;
      }
      return 0;

    case WM_COMMAND:
      switch(SHORT1FROMMP(mp1)) {
        case IDM_HELP:
          if(hwndHelp) {

            USHORT id;

            id = WinQueryWindowUShort(hwnd,QWS_ID);

            if(id == QTREE_FRAME)
              WinSendMsg(hwndHelp,HM_DISPLAY_HELP,
                         MPFROM2SHORT(HELP_QUICKTREE,0),
                         MPFROMSHORT(HM_RESOURCEID));
            else
              WinSendMsg(hwndHelp,HM_DISPLAY_HELP,
                         MPFROM2SHORT(HELP_OBJECTPATH,0),
                         MPFROMSHORT(HM_RESOURCEID));
          }
          break;

        case OBJCNR_DESKTOP:
        case DID_OK:
          data = INSTDATA(hwnd);
          if(data) {

            PCNRITEM pci;

            if(data->working) {
              DosBeep(50,100);
              break;
            }
            if(SHORT1FROMMP(mp1) == OBJCNR_DESKTOP) {
              WinDismissDlg(hwnd,2);
              break;
            }
            pci = (PCNRITEM)WinSendDlgItemMsg(hwnd,OBJCNR_CNR,
                                              CM_QUERYRECORDEMPHASIS,
                                              MPFROMLONG(CMA_FIRST),
                                              MPFROMSHORT(CRA_CURSORED));
            if(pci && (INT)pci != -1)
              strcpy(data->dirname,pci->szFileName);
            WinDismissDlg(hwnd,1);
          }
          break;

        case DID_CANCEL:
          data = INSTDATA(hwnd);
          if(data) {
            if(data->working) {
              data->dying = TRUE;
              data->stopflag = 0xff;
              DosBeep(1000,100);
              break;
            }
            WinDismissDlg(hwnd,0);
          }
          break;
      }
      return 0;

    case WM_DESTROY:
      objcnrwnd = (HWND)0;
      data = INSTDATA(hwnd);
      if(data)
        free(data);
      break;
  }
  return WinDefDlgProc(hwnd,msg,mp1,mp2);
}

