/**************************************************************************
 *  File name  :  dragheap.c
 *
 *  Description:  This file contains all file and memory management
 *                functions for the Drag/Drop sample.
 *
 *                This source file contains the following functions:
 *
 *                FindFilePurge()
 *                FindFileFirst(pszFilename, ulAttributes)
 *                FindFileNext(pInput)
 *                FindFileName(pszName)
 *                AllocAppDraginfo(hwndClient, pDraginfo)
 *                FreeAppDraginfo(pAppDraginfo)
 *                FindAppDraginfo(pDraginfo)
 *                AllocAppDragitem(pDraginfo, pFile)
 *                FreeAppDragitem(pAppDragitem)
 *                FindDraginfo(pAppDragitem)
 *                FindDragitemFile(pAppDragitem)
 *
 *  Concepts   :  memory management
 *
 *  API's      :  DosSubFreeMem
 *                DosGetNamedSharedMem
 *                DosAllocSharedMem
 *                DosSubSetMem
 *                DosFindFirst
 *                DosSubAllocMem
 *                DosFindNext
 *                DosFindClose
 *                DrgQueryDragitemCount
 *
 *  Required
 *    Files    :  OS2.H, STRING.H, DRAGDROP.H
 *
 *  Copyright (C) 1991 IBM Corporation
 *
 *      DISCLAIMER OF WARRANTIES.  The following [enclosed] code is
 *      sample code created by IBM Corporation. This sample code is not
 *      part of any standard or IBM product and is provided to you solely
 *      for  the purpose of assisting you in the development of your
 *      applications.  The code is provided "AS IS", without
 *      warranty of any kind.  IBM shall not be liable for any damages
 *      arising out of your use of the sample code, even if they have been
 *      advised of the possibility of such damages.                                                    *
 *************************************************************************/

/*
 *        Include the required sections from the PM header file
 */
#define INCL_DOSERRORS
#define INCL_DOSFILEMGR
#define INCL_WIN
#define INCL_WINSTDDRAG

/*
 *                     Include the PM header file
 */
#include <os2.h>

/*
 *                  Include the C library header files
 */
#include <string.h>

/*
 *                 Include the application header files
 */
#include "dragdrop.h"

/*
 * Variables global to file
 */

static PBYTE            hHeap     = NULL;   /* heap from which elements are */
                                            /* allocated                    */
static PPUBFILEFINDBUF  pFirst    = NULL;   /* anchor to list of elements   */
static PAPPDRAGINFO     pFirstAppDraginfo = NULL;
                                            /* pointer to chain of source   */
                                            /* that contain information     */
                                            /* for each drag in progress    */

/**************************************************************************
 *
 *  Name       : FindFilePurge
 *
 *  Description: Removes all entries in the list.  The function is
 *               invoked from FileFindFirst to remove the old list if
 *               one is present.
 *
 *  Concepts   :
 *
 *  API's      :  DosSubFreeMem
 *
 *  Parameters :  [none]
 *
 *  Return     :  TRUE  = list was purged
 *                FALSE = purge of list was unsuccessful
 *************************************************************************/
BOOL FindFilePurge(VOID)
{
   PPUBFILEFINDBUF pList, pListNext;

   for (pList = pFirst; pList != NULL; pList = pListNext)
   {
      pListNext = pList->pNext;
      if(NO_ERROR !=
            DosSubFreeMem(hHeap, (NPBYTE)pList, sizeof(PUBFILEFINDBUF)))
         return FALSE;
   }
   pFirst = NULL;                                  /* indicate list is empty */
   return TRUE;
}


/**************************************************************************
 *
 *  Name       : FindFileFirst
 *
 *  Description: Finds all files in the input subdirectory, creating
 *               a list of these files in the heap.  It then returns
 *               the first file found onthe queue that matches the
 *               input attributes.
 *
 *  Concepts   :
 *
 *  API's      :  DosGetNamedSharedMem
 *                DosAllocSharedMem
 *                DosSubSetMem
 *                DosFindFirst
 *                DosSubAllocMem
 *                DosFindNext
 *                DosFindClose
 *
 *  Parameters :  pszFilename = the name of the file
 *                ulAttributes = attribute flags
 *
 *  Return     :  address of the first list element that matches the
 *                input attributes, or
 *                NULL = no file matched the input attributes
 *************************************************************************/
PPUBFILEFINDBUF FindFileFirst (PSZ pszFilename, ULONG ulAttributes)
{
   FILEFINDBUF3    ffbFile;
   ULONG           rc;
   ULONG           cFile;
   PPUBFILEFINDBUF pAlloc, pTail;
   NPBYTE          npBuffer;
   HDIR            hDir;
   PVOID           phHeap;

   if (!hHeap)
   {
     /*
      * Initialize the heap that will be used to contain the queue elements
      * for the files in the subdirectory
      */
     rc = DosGetNamedSharedMem((PPVOID)&hHeap, (PSZ)"\\sharemem\\dragmem",
                               PAG_READ | PAG_WRITE);
     if (rc != 0L)
     {
        rc = DosAllocSharedMem((PPVOID)&hHeap, (PSZ)"\\sharemem\\dragmem",
                             65535LU,  PAG_COMMIT | PAG_READ | PAG_WRITE);

        if(rc != 0L ||    /* Initialize the heap.                 */
           (NO_ERROR != DosSubSetMem((PVOID)hHeap, 1, 65535)))
        {
          /*
           * Heap initialization failed.
           */
          MessageBox(HWND_DESKTOP,
                    IDMSG_HEAPERROR,
                    MB_OK | MB_ERROR,
                    TRUE);
          return NULL;
        }
         /*
          * Heap is initialized - set anchor to NULL.
          */
        pFirst = NULL;
     }
   }

   /*
    * heap now initialized
    *
    * free the entries currently on the list and create the new list
    */
   if(!FindFilePurge())                        /* empty the current list   */
   {
      MessageBox(HWND_DESKTOP,
                    IDMSG_MEMFREEERROR,
                    MB_OK | MB_ERROR,
                    TRUE);
      return NULL;
   }

   cFile = 1;                                  /* buffer is large enough   */
                                               /* to contain info for 1    */
                                               /* file                     */
   hDir = HDIR_CREATE;                         /* allocate DosFind handle  */
   rc = DosFindFirst(pszFilename, &hDir, ulAttributes, &ffbFile,
                     sizeof(ffbFile), &cFile, 1);
   while (!rc)
   {
    /*
     * if we couldn't allocate a buffer from the heap, display an
     * error message and set the flag that will terminate the loop
     */
      if((NO_ERROR !=
        DosSubAllocMem((PVOID)hHeap, (PPVOID)&npBuffer, sizeof(PUBFILEFINDBUF)))
               ||     !npBuffer)
      {
         MessageBox(HWND_DESKTOP,
                    IDMSG_HEAPALLOCERROR,
                    MB_OK | MB_ERROR,
                    TRUE);
         rc = 1;
      }

    /*
     * otherwise, add the found entry to the list
     */
      else
      {
         phHeap = hHeap;
         pAlloc = (PPUBFILEFINDBUF) npBuffer;
         pAlloc->pNext = NULL;

      /*
       * if this is the first one in the list, update the head pointer
       */
         if (pFirst == NULL)
            pFirst = pAlloc;

      /*
       * otherwise, add it to the end of the list
       */
         else
           pTail ->pNext = pAlloc;

         pTail = pAlloc;                    /* update the tail pointer      */

      /*
       * copy portions of file find buffer that will be kept to the
       * buffer that we allocated.
       */
         if (ffbFile.attrFile & FILE_DIRECTORY)
            strcpy (pAlloc->achName, "\\");     /* add '\\' before directory  */
         else
            pAlloc->achName[0] = '\0';          /* just a file                */

         strcat (pAlloc->achName, ffbFile.achName);
         pAlloc->fdateLastWrite = ffbFile.fdateLastWrite;
         pAlloc->ftimeLastWrite = ffbFile.ftimeLastWrite;
         pAlloc->cbFileAlloc    = ffbFile.cbFileAlloc;
         pAlloc->attrFile       = ffbFile.attrFile;

      /*
       * get next file
       */
         rc = DosFindNext (hDir, &ffbFile, (LONG)(sizeof(ffbFile)), &cFile);
      }
   }

  /*
   * All files have been found. Free the file find handle and send the
   * appropriate return code.
   */
   DosFindClose (hDir);
   return (pFirst);
}


/**************************************************************************
 *
 *  Name       : FindFileNext
 *
 *  Description: Finds the next file int eh input subdirectory
 *
 *  Concepts   :
 *
 *  API's      :  [none]
 *
 *  Parameters :  pInput = a pointer to the input file-find buffer
 *
 *  Return     :  address of the next file that matches the
 *                input attributes, or
 *                NULL = no file matched the input attributes before
 *                       reaching the end of the list
 *************************************************************************/
PPUBFILEFINDBUF FindFileNext(PPUBFILEFINDBUF pInput)
{
   return ((pInput != NULL) ? pInput->pNext : (PPUBFILEFINDBUF)NULL);
}

/**************************************************************************
 *
 *  Name       : FindFileName
 *
 *  Description: Finds the next file in the input subdirectory
 *
 *  Concepts   :
 *
 *  API's      :  [none]
 *
 *  Parameters :  pszName = a pointer to the file name string
 *
 *  Return     :  address of the next file that matches the
 *                input file name, or
 *                NULL = no file matched the input name
 *************************************************************************/
PPUBFILEFINDBUF FindFileName (PSZ pszName)
{
   PPUBFILEFINDBUF       pList;

   pList = pFirst;

   while (pList != NULL)
   {
      if (strcmp (pList->achName, pszName) == 0)
         break;

      pList = pList -> pNext;
   }

   return pList;
}

/**************************************************************************
 *
 *  Name       : AllocAppDraginfo
 *
 *  Description: Allocates an APPDRAGINFO control block and places
 *               it on a queue to be found by the application later.
 *               The APPDRAGINFO is initialized.
 *
 *  Concepts   : drag information
 *
 *  API's      :  DosSubAllocMem
 *                DrgQueryDragitemCount
 *
 *  Parameters :  pszName = a pointer to the file name string
 *
 *  Return     :  address of the APPDRAGINFO, or
 *                NULL = the allocation failed
 *************************************************************************/
PAPPDRAGINFO AllocAppDraginfo (HWND hwndClient, PDRAGINFO pDraginfo)
{
   NPBYTE          npBuffer;
   PAPPDRAGINFO    pAlloc;
   PVOID           phHeap;

  /*
   * if we couldn't allocate a buffer from
   * the heap, display a message and abort
   */
   if(NO_ERROR != DosSubAllocMem(hHeap, (PPVOID)&npBuffer, sizeof(APPDRAGINFO)))
   {
      MessageBox(HWND_DESKTOP,
                 IDMSG_ALLOCDRAGINFO,
                 MB_OK | MB_ERROR,
                 TRUE);
      return NULL;
   }
   else
   {
    /*
     * Add entry to list.
     */
      phHeap = hHeap;
      pAlloc = (PAPPDRAGINFO) npBuffer;
      pAlloc->pNextAppDraginfo = pFirstAppDraginfo;
      pFirstAppDraginfo = pAlloc;

    /*
     * Initialize the new entry.
     */
      pAlloc->pDraginfo      = pDraginfo;
      pAlloc->hwndClient     = hwndClient;
      pAlloc->usItemsDragged = DrgQueryDragitemCount(pDraginfo);
      return pAlloc;
   }
}

/**************************************************************************
 *
 *  Name       : FreeAppDraginfo
 *
 *  Description: Removes an APPDRAGINFO from the queue and
 *               deallocates the memory it was using.
 *
 *  Concepts   : drag information
 *
 *  API's      :  DosSubFreeMem
 *
 *  Parameters :  pAppDraginfo = pointer to the drag information
 *
 *  Return     :  TRUE = memory was successfullly deallocated
 *                FALSE = the deallocation failed
 *************************************************************************/
BOOL FreeAppDraginfo(PAPPDRAGINFO pAppDraginfo)
{
   PAPPDRAGINFO    pPrevious, pCurrent;

   pPrevious = NULL;
   pCurrent = pFirstAppDraginfo;

   while (pCurrent != NULL)
   {
      if (pCurrent == pAppDraginfo)
         break;
      else
      {
         pPrevious = pCurrent;
         pCurrent = pCurrent->pNextAppDraginfo;
      }
   }

   if (pCurrent != NULL)
   {
      if (pPrevious == NULL)
         pFirstAppDraginfo = pCurrent->pNextAppDraginfo;
      else
         pPrevious->pNextAppDraginfo = pCurrent->pNextAppDraginfo;

      if (NO_ERROR ==
             DosSubFreeMem(hHeap, (NPBYTE)pAppDraginfo, sizeof(APPDRAGINFO)))
         return TRUE;
      else
         return FALSE;
   }
   else
   {
      return FALSE;
   }
}

/**************************************************************************
 *
 *  Name       : FindAppDraginfo
 *
 *  Description: Finds an APPDRAGINFO, given the address of a DRAGINFO
 *
 *  Concepts   : drag information
 *
 *  API's      :  [none]
 *
 *  Parameters :  pDraginfo = pointer to the drag information
 *
 *  Return     :  NULL = unable to find the APPDRAGINFO
 *                otherwise, the address of the APPDRAGINFO
 *************************************************************************/
PAPPDRAGINFO FindAppDraginfo(PDRAGINFO pDraginfo)
{
   PAPPDRAGINFO    pCurrent;

   pCurrent = pFirstAppDraginfo;

   while (pCurrent != NULL)
   {
     if (pCurrent->pDraginfo == pDraginfo)
        break;
     else
        pCurrent = pCurrent->pNextAppDraginfo;
   }

   return pCurrent;
}


/**************************************************************************
 *
 *  Name       : AllocAppDragitem
 *
 *  Description: Allocates an APPDRAGITEM control block and initializes it
 *
 *  Concepts   : drag information
 *
 *  API's      :  DosSubAllocMem
 *
 *  Parameters :  pDraginfo = pointer to the drag information
 *                pFile = file pointer
 *
 *  Return     :  NULL = allocation failed
 *                otherwise, the address of the APPDRAGINFO
 *************************************************************************/
PAPPDRAGITEM AllocAppDragitem(PDRAGINFO pDraginfo, PPUBFILEFINDBUF pFile)
{
   NPBYTE          npBuffer;
   PAPPDRAGITEM    pAlloc;
   PVOID           phHeap;

   if(NO_ERROR != DosSubAllocMem(hHeap, (PPVOID)&npBuffer, sizeof(APPDRAGITEM)))
   {
       MessageBox(HWND_DESKTOP,
                    IDMSG_HEAPALLOCERROR,
                    MB_OK | MB_ERROR,
                    TRUE);
       return NULL;
   }
   else
   {
     /*
      * initialize the new entry
      */
      phHeap = &hHeap;
      pAlloc = (PAPPDRAGITEM)npBuffer;
      pAlloc->pDraginfo = pDraginfo;
      pAlloc->pFile     = pFile;
      return pAlloc;
   }
}

/**************************************************************************
 *
 *  Name       : FreeAppDragitem
 *
 *  Description: Frees an APPDRAGITEM
 *
 *  Concepts   : drag information
 *
 *  API's      :  DosSubFreeMem
 *
 *  Parameters :  pAppDragitem = pointer to the drag item
 *
 *  Return     :  TRUE = memory was successfully deallocated
 *                FALSE = an error occurred
 *************************************************************************/
BOOL FreeAppDragitem(PAPPDRAGITEM pAppDragitem)
{
   return (NO_ERROR ==
         DosSubFreeMem(hHeap, (NPBYTE)pAppDragitem, sizeof(APPDRAGITEM)));
}


/**************************************************************************
 *
 *  Name       : FindDragInfo
 *
 *  Description: Finds the PDRAGINFO for a drag operation, given the
 *               address of an APPDRAGITEM
 *
 *  Concepts   : drag information
 *
 *  API's      :  [none]
 *
 *  Parameters :  pAppDragitem = pointer to the application drag item
 *
 *  Return     :  NULL = unable to find the drag information
 *                otherwise, the address of the drag information used
 *                to drag this item
 *************************************************************************/
PDRAGINFO FindDraginfo(PAPPDRAGITEM pAppDragitem)
{
   return pAppDragitem->pDraginfo;
}

/**************************************************************************
 *
 *  Name       : FindDragItemFile
 *
 *  Description: Finds the PPUBFILEFINDBUF for a drag operation, given the
 *               address of an APPDRAGITEM
 *
 *  Concepts   : drag information
 *
 *  API's      :  [none]
 *
 *  Parameters :  pAppDragitem = pointer to the drag item
 *
 *  Return     :  NULL = unable to find the PPUBFILEFINDBUF
 *                otherwise, the address of the PPUBFILEFINDBUF for the
 *                item being dragged
 *************************************************************************/
PPUBFILEFINDBUF FindDragitemFile (PAPPDRAGITEM pAppDragitem)
{
   return pAppDragitem->pFile;
}
/***************************  End of dragheap.c  *************************/
