/******************************************************************************/
/* FILE           : Splash.c  -  Splash screen functions                      */
/* DESCRIPTION    : Functions for splash screen                               */
/* LANGUAGE       : "C"                                                       */
/* PLATFORM       : Windows 95/98/98SE/ME/NT4/2000                            */
/* AUTHOR         : Andrea Binello  <andrea.binello@tiscalinet.it>            */
/* LICENSE        : Freeware - Open Source                                    */
/* LAST UPDATE    : May 06, 2001                                              */
/******************************************************************************/

/* DAL - modified to print version in lower right corner */
#define STRICT
#include <windows.h>
#include "splash.h"
#include "..\version.h"

#define SPLASH_CLASS    "AbSplashScreenWndClass"

typedef struct
{
   LPBYTE   lpBuffer;
   INT      iWidth;
   INT      iHeight;
} SPLASH2, FAR* LPSPLASH2;

/*****************************************************************************/
static unsigned char * SplashScreen_LoadBmp (HINSTANCE hInstance, LPSTR lpszResource, LPINT lpiWidth, LPINT lpiHeight)
{
   DWORD                dwLen;
   HRSRC                hResource;
   HGLOBAL              hGlobal;
   HGLOBAL              hGlobalRet=NULL;
   LPVOID               lpBuffer=NULL;
   LPVOID               lpbits ;
   LPBITMAPFILEHEADER   lpbfh;
   LPBITMAPINFOHEADER   lpbih;
   hResource = FindResource (hInstance, lpszResource, "SPLASH");

   if (hResource != NULL)
   {
      dwLen = SizeofResource (hInstance, hResource);

      if (dwLen != 0)
      {
         hGlobal = LoadResource (hInstance, hResource);

         if (hGlobal != NULL)
         {
            lpBuffer = LockResource (hGlobal);
            // The next line unzips the first item in a zip file,
            // and assumes it is a bitmap.  Comment out if the SPLASH
            // resource is a plain bitmap
            lpBuffer = InflateWrap(lpBuffer) ;

            if (lpBuffer != NULL)
            {
               lpbfh = (LPBITMAPFILEHEADER) lpBuffer;
               lpbih = (LPBITMAPINFOHEADER) (((LPBYTE) lpBuffer) +
                       sizeof (BITMAPFILEHEADER));

               if (lpbfh->bfType == 0x4D42)
               {
                  hGlobalRet = hGlobal;

                  *lpiWidth = (INT) lpbih->biWidth >= 0 ?
                              lpbih->biWidth  : -lpbih->biWidth;
                  *lpiHeight = (INT) lpbih->biHeight >= 0 ?
                               lpbih->biHeight : -lpbih->biHeight;
               }
            }
         }
      }
   }

   return lpBuffer;
}

/*****************************************************************************/
static VOID SplashScreen_Paint (HWND hWnd)
{
   char                 buf[256] ;
   LPSPLASH2            lpSplash2;
   HDC                  hdc;
   PAINTSTRUCT          ps;
   LPBITMAPINFOHEADER   lpbih;
   LPVOID               lpbits=NULL;
   SIZE                 size ;
   lpSplash2 = (LPSPLASH2) GetWindowLong (hWnd, GWL_USERDATA);

   hdc = BeginPaint (hWnd, &ps);

   if (lpSplash2 != NULL && lpSplash2->lpBuffer != NULL)
   {
      HDC hdcMem = CreateCompatibleDC(hdc) ;
      HBITMAP bmp = CreateCompatibleBitmap(hdc, lpSplash2->iWidth, lpSplash2->iHeight) ;
      lpbih = (LPBITMAPINFOHEADER) (lpSplash2->lpBuffer + sizeof (BITMAPFILEHEADER));
      if (lpbih->biBitCount == 24)
         lpbits = ((LPBYTE) lpbih) + lpbih->biSize;
      else if (lpbih->biBitCount == 8)
         lpbits = ((LPBYTE) lpbih) + lpbih->biSize + sizeof (RGBQUAD)*256;
      else if (lpbih->biBitCount == 4)
         lpbits = ((LPBYTE) lpbih) + lpbih->biSize + sizeof (RGBQUAD)*16;
      else if (lpbih->biBitCount == 1)
         lpbits = ((LPBYTE) lpbih) + lpbih->biSize + sizeof (RGBQUAD)*2;
      SetDIBits(hdcMem,bmp,0,lpSplash2->iHeight, lpbits, lpbih,DIB_RGB_COLORS) ;
      SelectObject(hdcMem, bmp) ;
      BitBlt (hdc, 0, 0, lpSplash2->iWidth, lpSplash2->iHeight,
                      hdcMem, 0, 0, SRCCOPY);
      DeleteObject(hdcMem) ;
   }
   sprintf(buf,"Version %s",CCIDE_STRING_VERSION) ;
   GetTextExtentPoint32(hdc,buf,strlen(buf),&size) ;
   SetBkMode(hdc, TRANSPARENT) ;
   TextOut(hdc,lpSplash2->iWidth - size.cx-4,lpSplash2->iHeight-size.cy-4,buf,strlen(buf));

   EndPaint (hWnd, &ps);
}

/*****************************************************************************/
static LRESULT CALLBACK SplashScreen_Proc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
   LPSPLASH2            lpSplash2;
   switch (msg)
   {
      case WM_PAINT:
         SplashScreen_Paint (hWnd);
         return 0L;

      case WM_ERASEBKGND:
         return 1L;

      case WM_TIMER:
         KillTimer (hWnd, (UINT) wParam);
         SendMessage (hWnd, WM_CLOSE, 0, 0L);
         return 0L;

      case WM_CLOSE:
         lpSplash2 = (LPSPLASH2) GetWindowLong (hWnd, GWL_USERDATA);
         free(lpSplash2->lpBuffer) ;
         break ;

      case WM_DESTROY:
         PostQuitMessage (0);
         return 0L;
   }

   return (DefWindowProc (hWnd, msg, wParam, lParam));
}

/******************************************************************************/
static VOID SplashScreen_Thread (LPSPLASH lpSplash)
{
   HGLOBAL     hGlobal;
   LPBYTE      lpBuffer;
   WNDCLASSEX  wcx;
   BOOL        bReg;
   DWORD       dwExStyles;
   INT         iWidth, iHeight, iScrWidth, iScrHeight, iPosX, iPosY;
   SPLASH2     splash2;
   HWND        hWnd;
   UINT        uTimerId;
   MSG         msg;
   {
      lpBuffer = SplashScreen_LoadBmp (lpSplash->hInstanceRes,
                                      lpSplash->lpszResource,
                                      &iWidth, &iHeight);


         if (lpBuffer != NULL)
         {
            bReg = FALSE;

            if (GetClassInfoEx (lpSplash->hInstance, SPLASH_CLASS, &wcx))
               bReg = TRUE;
            else
            {
               memset(&wcx,0,sizeof(wcx)) ;
               wcx.cbSize        = sizeof (wcx);
               wcx.style         = 0;
               wcx.lpfnWndProc   = (WNDPROC) SplashScreen_Proc;
               wcx.cbClsExtra    = 0;
               wcx.cbWndExtra    = 0;
               wcx.hInstance     = lpSplash->hInstance;
               wcx.hIcon         = NULL;
               wcx.hIconSm       = NULL;
               wcx.hCursor       = LoadCursor (NULL, IDC_ARROW);
               wcx.hbrBackground = NULL;
               wcx.lpszMenuName  = NULL;
               wcx.lpszClassName = SPLASH_CLASS;

               if (RegisterClassEx (&wcx))
                  bReg = TRUE;
            }

            if (bReg)
            {
               if (lpSplash->bCentered)
               {
                  iScrWidth = GetSystemMetrics (SM_CXSCREEN);
                  iScrHeight = GetSystemMetrics (SM_CYSCREEN);

                  iPosX = (iScrWidth - iWidth) / 2;
                  iPosY = (iScrHeight - iHeight) / 2;
               }
               else
               {
                  iPosX = lpSplash->iPosX - iWidth / 2;
                  iPosY = lpSplash->iPosY - iHeight / 2;
               }

               dwExStyles = WS_EX_TOOLWINDOW;

               if (lpSplash->bTopmost)
                  dwExStyles |= WS_EX_TOPMOST;

               hWnd = CreateWindowEx (dwExStyles, SPLASH_CLASS, "",
                                      WS_POPUP, iPosX, iPosY, iWidth, iHeight,
                                      lpSplash->hWndOwner, NULL,
                                      lpSplash->hInstance, NULL);

               splash2.lpBuffer = lpBuffer;
               splash2.iWidth   = iWidth;
               splash2.iHeight  = iHeight;

               SetWindowLong (hWnd, GWL_USERDATA, (LONG) &splash2);

               uTimerId = SetTimer (hWnd, 1, (UINT) lpSplash->uTime, NULL);

               if (uTimerId != 0)
                  ShowWindow (hWnd, SW_SHOW);
               else
                  PostMessage (hWnd, WM_CLOSE, 0, 0L);

               while (GetMessage (&msg, NULL, 0, 0))
               {
                  TranslateMessage (&msg);
                  DispatchMessage (&msg);
               }
            }
         }

   }

   GlobalFree ((HGLOBAL) lpSplash);
}

/******************************************************************************/
VOID WINAPI SplashScreen (LPSPLASH lpSplash)
{
   HANDLE      hThread;
   DWORD       dwTid;
   LPSPLASH    lpSplash_t;

   lpSplash_t = (LPSPLASH) GlobalAlloc (GPTR, sizeof (SPLASH));

   if (lpSplash_t != NULL)
   {
      memcpy (lpSplash_t, lpSplash, sizeof (SPLASH));

      hThread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) SplashScreen_Thread,
                              (LPVOID) lpSplash_t, 0, &dwTid);

      if (lpSplash->bWait && hThread != NULL)
         WaitForSingleObject (hThread, INFINITE);
   }
}