#include <ddraw.h>
#include <ddutil.h>
#include <assert.h>

extern "C" {
	
	extern void printDDError (char *, HRESULT code);
    
    extern LPDIRECTDRAW GetDirectDrawInterface (int iWndIndex);
    extern LPDIRECTDRAWSURFACE GetBackBuffer (int iWndIndex);
    extern printf (const char *, ...);
    
    LPDIRECTDRAW lpDD = 0;
    LPDIRECTDRAWSURFACE lpBack = 0;
    LPDIRECTDRAWSURFACE lpFront = 0;
    static BOOL bFirstTime = TRUE;
    
    LPDIRECTDRAWSURFACE
		LoadACMBitmap (char *szBitmap, int * width, int * height)
    {
		HBITMAP	hbm;
		DDSURFACEDESC ddsd;
		LPDIRECTDRAWSURFACE lpDDS;
		LPDIRECTDRAWPALETTE lpDDPal;
		HRESULT	ddrval;
		BITMAP              bm;
		
		// Lazy initialization
		
		if (!lpDD) {
			lpDD = GetDirectDrawInterface ( 0 );
		}
		
		// Load bitmap and get dimensions
		
		hbm = (HBITMAP) LoadImage (GetModuleHandle(NULL), szBitmap,
			IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
		
		if (hbm == NULL) {
			return NULL;
		}
		
		GetObject(hbm, sizeof(bm), &bm);    // get size of bitmap
		*width = bm.bmWidth;
		*height = bm.bmHeight;
		
		// Create an off-screen bitmap.
		ZeroMemory(&ddsd, sizeof(ddsd));
		ddsd.dwSize = sizeof(ddsd);
		ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT |DDSD_WIDTH;
		ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
		ddsd.dwWidth = *width;
		ddsd.dwHeight = *height;
		ddrval = lpDD->CreateSurface(&ddsd, &lpDDS, NULL);
		if (ddrval != DD_OK) {
			printDDError("Creating bitmap surface", ddrval);
		}
		
		if(ddrval != DD_OK) {
			*width = *height = 0;
			return NULL;
		}
		
		/*
		*  Get the standard 16 colors used for the bitmaps into the palette
		*  TODO:  If multiple windows are ever used, this will need to be modified
		*  to update the palette in each window.
		*/
		
		if (bFirstTime) {
			lpDDPal = DDLoadPalette(lpDD, szBitmap);
			if (lpDDPal) {
				ddrval = lpDDS->SetPalette (lpDDPal);
				if (ddrval != DD_OK) {
					printf ("Error setting palette %d\n", ddrval);
				}
			}
			//bFirstTime = FALSE;
		}
		
		DDCopyBitmap(lpDDS, hbm, 0, 0, *width, *height);
		
		DeleteObject(hbm);
		
		return lpDDS;
    }
    
    void
		PutACMBitmap (LPDIRECTDRAWSURFACE bm, char *szBitmap,
			int w, int h, int x, int y, int len)
    {
		RECT        rcRect;
		HRESULT	ddrval;
		
		if (!lpBack) {
			lpBack = GetBackBuffer (0);
		}
		
		rcRect.left = 0;
		rcRect.top = 0;
		rcRect.right = w;
		rcRect.bottom = h;
		while(1) {
			ddrval = lpBack->BltFast(x, y, bm, &rcRect, FALSE);
			if(ddrval == DD_OK) {
				break;
			}
			else if (ddrval == DDERR_SURFACELOST) {
				HBITMAP hbm;

				ddrval = bm->Restore();
				if (ddrval != DD_OK) {
					printDDError ("Attempting to Restore() bitmap surface", ddrval);
					exit (1);
				}

				hbm = (HBITMAP) LoadImage (GetModuleHandle(NULL), szBitmap,
					IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
		
				if (hbm == NULL) {
					printf ("Unable reload bitmap: returned null\n");
					exit (1);
				}

				DDCopyBitmap(bm, hbm, 0, 0, 0, 0);
		
				DeleteObject(hbm);
				printf ("reloaded bitmap %x\n", szBitmap);
			}
			else {
				printDDError ("In BltFast code", ddrval);
				exit (1);
			}
		}
    }
    
    
}

