#include <windows.h>
#include <memory.h>
#include "animate.h"

extern HANDLE ghBitmap;                        //handle to bitmap buffer

//WARNING!! - this work space may be inadequate for larger frames
//or for frames with many deltas;  the actual maximum size required
//FRAMEWIDTH/2*FRAMEHEIGHT*6 * FRAMEHEIGHT*2 + 2
BYTE   gabTempBuf[10000];		//Work space

/**************************************************************************
*  Function Name: LibMain
*  Purpose: Standard initialization routine for DLL
**************************************************************************/
int FAR LibMain (HANDLE hInstance, WORD wDataSeg, WORD wHeapSize, LPSTR lpszCmdLine)
{
    if (wHeapSize > 0)
    {
    } //End if (heap allocated)

#if defined(obd)


	MessageBox(NULL, "LibMain","",MB_ICONEXCLAMATION);

	
#endif

	 return 1;

} //End function (LibMain)

#if defined(obd)

VOID FAR WEP (bSystemExit)
int  bSystemExit;
{
    return;
}


#endif


/*************************** Function Header ********************************
 *   Function: anInit
 *   Description:  Load an animation bitmap and reduce to RLE frames
 *   Give the animation a context
 ***************************************************************************/
NPANIMATIONCONTEXT pBaseContext=NULL;
HANIMATION FAR anInit (LPSTR lpszFileName, int iFrameCount)
{
static int iCount = 0;                                 //count instances
static ANIMATIONCONTEXT *pContext;
static NPFRAME pFrame;
static int i;
static HANDLE hBitinfo, hPalette;

        //Load the bitmap frames into a buffer
    if (LoadBMPFile (lpszFileName, &hBitinfo, &hPalette) < 0)
    {   MessageBox(NULL, "Error loading bitmap","",MB_ICONEXCLAMATION);
        return NULL;
    } //End if (error loading bitmap)
        //Create a context for this animation
    if ((pContext = pAddContext (&pBaseContext)) == NULL)
    {   MessageBox(NULL, "Error creating context","",MB_ICONEXCLAMATION);
        return NULL;
    } //End if (error creating animation context)
    pContext->hId = ++iCount;
    pContext->hBitInfo = hBitinfo;
    pContext->hPalMem = hPalette;
    pContext->iFrameCount = iFrameCount;
        //Create delta records for each frame in the bitmap
    for (i=0;i<iFrameCount-1;i++)
    {   if ((pFrame = pAddFrame (pContext, i, i+1)) == NULL)
        {   MessageBox(NULL, "Error creating frame","",MB_ICONEXCLAMATION);
            return NULL;
        }//End if (error adding frame)
    } //End for (each frame in the bitmap)
        //Now compute the delta record between the last frame and
        //the first to complete the circular animation
        //allocate the frame
    if ((pFrame = pAddFrame (pContext, iFrameCount-1, 0)) == NULL)
    {   MessageBox(NULL, "Error creating frame","",MB_ICONEXCLAMATION);
        return NULL;
    }//End if (error adding frame)

        //We are done with the bitmap - free up memory
    GlobalFree (ghBitmap);
    return pContext->hId;
} //End function (anInit)
/*************************** Function Header ********************************
 *   Function: anClose
 *   Description:  Remove an animation
 ***************************************************************************/
int anClose (HANIMATION hId)
{
static NPANIMATIONCONTEXT pContext;
static NPFRAME pFrame, pFrame_;
    pContext = pBaseContext;
    while (pContext->hId != hId && pContext->pNext != NULL)
    {    pContext=pContext->pNext;
    } //End while (more contexts in chain)
        //free up all the frames
    pFrame = pContext->pFrame;
    while (pFrame != NULL)
    {   pFrame_ = pFrame->pNext;
        GlobalFree (pFrame->hDataMem);
	LocalUnlock (pFrame->hMem);
//XXX	LocalFree (pFrame->hMem);
        pFrame=pFrame_;
    } //End while (more frames in chain)
    LocalFree (pContext->hPalMem);
    LocalFree (pContext->hBitInfo);
    if (iDeleteContext (&pBaseContext, pContext) < 0)
    {   MessageBox(NULL, "Error deleting context","",MB_ICONEXCLAMATION);
        return -1;
    } //End if (error deleting context)
    return 0;

} //End function (anClose)
/*************************** Function Header ********************************
 *   Function: pAddContext
 *   Description:  Adds an animation context to the context chain
 *   given as a parameter.
 ***************************************************************************/
NPANIMATIONCONTEXT pAddContext (NPANIMATIONCONTEXT *pBase)
{
static NPANIMATIONCONTEXT pLink;
static HANDLE hMem;

    pLink= (*pBase);
    if (*pBase == NULL)
    {   hMem = LocalAlloc (LPTR, sizeof(ANIMATIONCONTEXT));
        *pBase = (NPANIMATIONCONTEXT)LocalLock (hMem);
        (*pBase)->hMem = hMem;
        (*pBase)->pNext = NULL;
        return *pBase;
    } /* endif (no base context defined) */
        //walk to the end of the context chain
    while (pLink->pNext != NULL) pLink=pLink->pNext;
    hMem = LocalAlloc (LPTR, sizeof(ANIMATIONCONTEXT));
    pLink->pNext = (NPANIMATIONCONTEXT)LocalLock (hMem);
    if (!pLink->pNext)
    { return NULL;
    } //endif (no memory for context)
    else
    {   pLink->pNext->hMem = hMem;
        pLink->pNext->pNext = NULL;
        return pLink->pNext;
    } /* endif (memory for context)*/
} //End function (pAddContext)
/*************************** Function Header ********************************
 *   Function: vDeleteContext
 *   Description:  Removes an animation context from the context chain
 *   given as a parameter.
 ***************************************************************************/
int iDeleteContext (NPANIMATIONCONTEXT *pBase, NPANIMATIONCONTEXT pContext)
{
static NPANIMATIONCONTEXT pLink;

    pLink= (*pBase);
    if ( (pContext == NULL) || (*pBase == NULL) )
    {  return -1;
    } /* endif (context not defined) */
    if ( (pContext == *pBase) && ((*pBase)->pNext != NULL))
    {   (*pBase) = (*pBase)->pNext;
        LocalFree (pLink->hMem);
        return 0;
    } /* endif (deleting base, but there are still other links) */
    if ( (pContext == *pBase) && ((*pBase)->pNext == NULL) )
    {	LocalUnlock ((*pBase)->hMem);
	LocalFree ((*pBase)->hMem);
        *pBase = NULL;
        return 0;
    } /* endif (deleting base context) */
        //walk the context chain until we come to the desired context
    while ( (pLink->pNext != pContext) && (pLink->pNext != NULL))
    {    pLink=pLink->pNext;
    } //End while (more contexts to walk)
    if (pLink->pNext != pContext)
    {   return -1;
    } /* endif (context not found) */
        //pLink now points to the context preceding the one we want to
        //delete
        //unlink the context from the chain
    pLink->pNext = pContext->pNext;
    LocalFree (pContext->hMem);
    return 0;
} //End function (vDeleteContext)
/*************************** Function Header ********************************
 *   Function: pAddFrame
 *   Description:  Adds a frame to the frame chain
 ***************************************************************************/
NPFRAME pAddFrame (NPANIMATIONCONTEXT pContext, int iFrame, int iNext)
{
static HANDLE hMem;
static NPFRAME pFrame;
static BYTE FAR *pPtr;
static int i;
        //allocate the frame
    if ((hMem = LocalAlloc(LMEM_MOVEABLE, sizeof(FRAME))) == NULL)
    {   MessageBox(NULL, "No memory","",MB_ICONEXCLAMATION);
        return NULL;
    } //End if (out of memory)
        //point to correct link in chain
    if (iFrame == 0)
    {   pContext->pFrame = (NPFRAME)LocalLock (hMem);
        pFrame = pContext->pFrame;
    } //End if (base frame)
    else
    {   pFrame = pContext->pFrame;
        while (pFrame->pNext != NULL) pFrame = pFrame->pNext;
        pFrame->pNext = (NPFRAME)LocalLock (hMem);
        pFrame = pFrame->pNext;
    } //End if (not base frame)
    pFrame->hMem = hMem;
    pFrame->pNext = NULL;
        //Compute the delta record between this frame and
        //the next
    pFrame->dwSize = FrameDelta (iFrame, iNext, pContext->hBitInfo, gabTempBuf);
        //allocate data space
    if ((pFrame->hDataMem=GlobalAlloc(GMEM_MOVEABLE,
                                          pFrame->dwSize))==NULL)
    {   MessageBox(NULL, "No memory","",MB_ICONEXCLAMATION);
        return NULL;
    } //End if (no memory)
        //point to data space
    if ((pPtr = (BYTE FAR *) GlobalLock (pFrame->hDataMem))
                                         ==NULL)
    {   MessageBox(NULL, "No memory","",MB_ICONEXCLAMATION);
        return NULL;
    } //End if (error locking memory)
        //Copy the delta record from the workspace to our list
    memcpy (pPtr, gabTempBuf, (WORD)pFrame->dwSize);
    GlobalUnlock (pFrame->hDataMem);
    return pFrame;
} //End function (pAddFrame)
