//====START_GENERATED_PROLOG======================================
//
//
//   COMPONENT_NAME: odbitmappart
//
//   CLASSES: none
//
//   ORIGINS: 82,27
//
//
//   (C) COPYRIGHT International Business Machines Corp. 1995,1996
//   All Rights Reserved
//   Licensed Materials - Property of IBM
//   US Government Users Restricted Rights - Use, duplication or
//   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
//   	
//   IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
//   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//   PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
//   CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
//   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
//   OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
//   OR PERFORMANCE OF THIS SOFTWARE.
//
//====END_GENERATED_PROLOG========================================
//

// @(#) 1.3 nt/src/samples/bitmap/bitplat.cpp, odbitmappart, od96nt, odnt9712d 3/7/97 13:13:02 [3/21/97 17:47:43]

// This code provides the implementation of functions that require platform-
// specific APIs.  Each platform which the BitmapPart is implemented on will
// have a different bitplat.cpp file.  The iodbitmp.cpp file is common to
// all platforms; any platform-specific code in iodbitmp.cpp must be bracketed
// by #ifdef <platform> and #endif statements.

#   include <windows.h>
#   include <winuser.h>
#   include <wingdi.h>

// PubUtil for help with debugging (such as logging)
// Also includes basic OpenDoc types
#include "ODDebug.h"

#define CLR_BLACK         0x00000000

// Including the following line allows us to load bitmaps using OpenClass.
// The raw GDI way only supports Device Independent Bitmap (DIB) formats,
// but OpenClass supports formats other than BMPs.
#define USE_OPENCLASS_TO_LOAD_BITMAPS

#ifdef USE_OPENCLASS_TO_LOAD_BITMAPS
#include <IGBitmap.hpp>
#include <IString.hpp>
#endif

//------------------------------------------------------------------------------
//                          PlatOpenDlg
//
// - invokes the common Windows Open File dialog box to open a bitmap file.
// - returns the name of the file selected.
//------------------------------------------------------------------------------
ODBoolean PlatOpenDlg(HWND hwnd, char* docName)
{
    char         szFile[MAX_PATH];
    OPENFILENAME of;

// #if defined(__IBMCPP__) || defined(_IBMR2)
//    nl_catd BM_NLSCat;       // NLS message catalog handle
//    char *filterText;       // pointer for NLS message
//    char *dialogText;       // pointer for NLS message
//    setlocale(LC_ALL,"");

//    bitNLSCat=catopen(BM_NLS_CATALOG, NL_CAT_LOCALE); // Open NLS message catalog

//    filterText = catgets(BM_NLSCat, BM_MSG_SET,
//                         BM_MSG_DLG_FILTER, "All (*.*)\0*.*\0\0");
//    dialogText = catgets(BM_NLSCat, BM_MSG_SET, BM_MSG_OPEN_DLG, "Open Bitmap");
//#else
    char filterText[256] = "Bitmaps\0 *.BMP\0\0";
    char dialogText[256] = "Open Bitmap";
//#endif

    // Initialize the OPENFILENAME control block to pass to the
    // File Open Dialog
    memset( &of, '\0', sizeof( of ) );
    of.lStructSize      = sizeof( OPENFILENAME );
    of.hwndOwner        = hwnd;

    // Set the initial file filter from the message catalog.  The
    // default is to display BMP files (*.BMP).
    of.lpstrFilter      = (LPSTR) filterText;
    of.nFilterIndex     = 1; // Display first filter
    of.lpstrInitialDir  = NULL;  // default to current directory

    // Indicate to the API to fill in the file name before
    // returning.
    lstrcpy( szFile, "*.*" );
    of.lpstrFile        = (LPSTR) szFile;
    of.nMaxFile         = sizeof(szFile);
    of.lpstrDefExt      = NULL;  // Don't append a default extension

    // Fill in the File Dialog title.
    of.lpstrTitle       = (LPSTR) dialogText;

    // Fill in the flags
    of.Flags            = OFN_FILEMUSTEXIST; // File must already exist

    // Now we're ready to ask for the filename to import

    if (GetOpenFileName(&of))
    {
      lstrcpy((LPSTR) docName, of.lpstrFile);
#ifdef ODDebug
      PRINT ("Document Name is %s\n",docName);
#endif
      return kODTrue;
    } // endif GetOpenFileName
    else
       return kODFalse;
}

//------------------------------------------------------------------------------
//                          PlatReadFile
//
// - reads the input filename into the given buffer.
// - returns the size of the file specified.
//------------------------------------------------------------------------------
ODBoolean PlatReadFile(char* docName, char* &buffer, ODULong &bytesRead)
{
    HANDLE hFile;
    DWORD dwFileSize;
    DWORD dwBytesRead;

    // If no file is read in, buffer will be empty
    buffer = NULL;
    dwBytesRead = 0;

    // Open the file.
    if ((hFile = CreateFile((LPCTSTR) docName,
          GENERIC_READ,
          FILE_SHARE_READ,
          NULL,
          OPEN_EXISTING,
          FILE_ATTRIBUTE_READONLY,
          (HANDLE)NULL))  // Win95 requires this be null.
       == INVALID_HANDLE_VALUE)
    {
#ifdef ODDebug
      PRINT ("File open failed for %s\n",docName);
#endif
      return kODFalse;
    }

    // Get the size of the file.
    dwFileSize = GetFileSize(hFile, NULL);
    if (dwFileSize == 0xFFFFFFFF)
    {
#ifdef ODDebug
      PRINT ("GetFileSize failed for %s\n",docName);
#endif
      return kODFalse;
    }

    // Allocate a buffer for the file to be read into.
    buffer = (char *)SOMMalloc(dwFileSize);
    if (buffer == NULL)
    {
#ifdef ODDebug
      PRINT ("SOMMalloc failed!\n");
#endif
      CloseHandle( hFile );
      return kODFalse;
    }


    // Read the file contents into a buffer.
    ReadFile(hFile,(LPVOID)buffer, dwFileSize, &dwBytesRead, NULL);
    bytesRead = dwBytesRead;

    if (dwBytesRead == 0)
    {
#ifdef ODDebug
      PRINT ("Zero bytes read.\n");
#endif
      CloseHandle( hFile );
      SOMFree(buffer);
      buffer = NULL;
      return kODFalse;
    }

    // Close the file
    CloseHandle( hFile );
    return kODTrue;
}


//------------------------------------------------------------------------------
//                          PlatCreateBitmap
//
// - creates a bitmap from the input filename or buffer.
// - returns the bitmap handle.
//------------------------------------------------------------------------------
HBITMAP  PlatCreateBitmap(char* fileName, char* buffer, HDC hdcMemory)
{
   HBITMAP bitmapHandle = NULL;
   SIZE BitmapDimensions;

#ifdef USE_OPENCLASS_TO_LOAD_BITMAPS
if (fileName) {
   // Let OpenClass do it - buys us formats other than *.BMP.
   // Restricts us to reading bitmap from file, not from our buffer.
   IString OpenClassString(fileName);
   IGBitmap *OpenClassBitmap = new IGBitmap(OpenClassString);
   if (OpenClassBitmap) {
      ISize size = OpenClassBitmap->size();
      BitmapDimensions.cx = size.width();
      BitmapDimensions.cy = size.height();
      bitmapHandle = OpenClassBitmap->handle();
   }
} else
#endif // use platform-specific APIs to create the bitmap
   {
  /*  A windows bitmap file has 3 parts, the bitmap file header,
   *  then the bitmap information header along with the color table,
   *  and finally the actual bit data, to a total of dwFileSize bytes.
   *    1.  BITMAPFILEHEADER
   *    2.  BITMAPINFOHEADER + RGBQUAD(colors)
   *    3.  BYTE(pixels)
   */
   PBITMAPFILEHEADER pbmFileHeader;
   PBITMAPINFOHEADER pbmInfoHeader;
   PBYTE             pBits;
   int               bfOffBits;

   pbmFileHeader = (PBITMAPFILEHEADER) buffer;
   bfOffBits = pbmFileHeader->bfOffBits;
   pbmInfoHeader = (PBITMAPINFOHEADER) (buffer + sizeof(BITMAPFILEHEADER));
   pBits = (PBYTE) buffer + bfOffBits;

#ifdef ODDebug
      char c1 = *buffer;
      char c2 = *(buffer+1);
      if (c1 != 'B' || c2 != 'M')
         PRINT("File is not a valid DIB format.\n");
      else {
         PRINT("Bitmap pixels are offset %d into file.\n", bfOffBits);
      }
#endif
   BitmapDimensions.cx = pbmInfoHeader->biWidth;
   BitmapDimensions.cy = pbmInfoHeader->biHeight;

   // Create the bitmap, use CBM_INIT to indicate that the bits to initialize
   // the bitmap are provided.
   bitmapHandle = CreateDIBitmap (hdcMemory, pbmInfoHeader, CBM_INIT,
                         pBits, (PBITMAPINFO) pbmInfoHeader, DIB_RGB_COLORS);
   } // end non-OpenClass bitmap creation

   if (bitmapHandle) {
      SetBitmapDimensionEx(bitmapHandle, BitmapDimensions.cx,
                           BitmapDimensions.cy, kODNULL);
      SelectObject(hdcMemory, bitmapHandle);
   } else {
      DWORD error = GetLastError();
#ifdef ODDebug
      PRINT("Error %d creating bitmap. \n", error);
#endif
   } /* endif */

   return(bitmapHandle);
}

//------------------------------------------------------------------------------
//                          PlatDrawBitmap
//
// - draws the input bitmap
//------------------------------------------------------------------------------
void  PlatDrawBitmap(HDC hdcDraw, HDC hdcMemory, RECT frameRect, HBITMAP hbm, ODBoolean negative)
{
   SIZE dimensions;

   // Create a solid brush
   // HBRUSH hbr = CreateSolidBrush (CLR_BLACK);
   // Fill the rectangle with the brush
   // FillRect (hdcDraw, &frameRect, hbr);
   // Get rid of the brush
   // DeleteObject (hbr);

   GetBitmapDimensionEx(hbm, &dimensions);

   SetStretchBltMode(hdcDraw, STRETCH_DELETESCANS);  // Preserve bitmap color
   StretchBlt(hdcDraw, 0, 0, frameRect.right-frameRect.left,
              frameRect.bottom-frameRect.top,
              hdcMemory, 0, 0, dimensions.cx, dimensions.cy,
              negative ? NOTSRCCOPY : SRCCOPY);

}


//------------------------------------------------------------------------------
//                          PlatCreatePalette
//
// - creates a palette from the input file buffer
//------------------------------------------------------------------------------
HPALETTE PlatCreatePalette(char* buffer)
{
   PBITMAPINFOHEADER pbmih = (PBITMAPINFOHEADER) (buffer + sizeof(BITMAPFILEHEADER));
   HPALETTE newPalette = NULL;
   int colors;

   if (pbmih->biClrUsed)
      colors = pbmih->biClrUsed;
   else
      switch(pbmih->biBitCount) {
      case 1 :
         colors = 2;     break;  // Monochrome
      case 4 :
         colors = 16;    break;  // VGA
      case 8 :
         colors = 256;   break;  // SVGA
      case 24:
         colors = 0;     break;  // True Color
      default:
         colors = 257;
      }

   if (colors > 256)
      return NULL;  // Invalid bitmap format

   RGBQUAD* rgbquad = (RGBQUAD*) (pbmih + sizeof(pbmih));
   LOGPALETTE* logpal = (LOGPALETTE*) new char[sizeof(LOGPALETTE) +
                                               sizeof(PALETTEENTRY) * colors];
   logpal->palVersion = 0x300;
   logpal->palNumEntries = (WORD) colors;
   for (int i=0; i < colors; i++) {
      logpal->palPalEntry[i].peRed = rgbquad[i].rgbRed;
      logpal->palPalEntry[i].peGreen = rgbquad[i].rgbGreen;
      logpal->palPalEntry[i].peBlue = rgbquad[i].rgbBlue;
      logpal->palPalEntry[i].peFlags = 0;
   }

   // Create a new palette with the logical palette entries.
   newPalette = CreatePalette(logpal);
   delete logpal;

   return(newPalette);
}
