#include <windows.h>
#include "w32dry.h"

// a small program that does something interesting in Win32

int counter = 0;
enum { maxsize = 505 };
int y = 0, mousex = 0, mousey = 0;

void draw_in(HWND hWnd) {
  HDC hDC = pcheck(GetDC(hWnd), HDC);

  // double buffer one scan line
  HDC hDCBuffer = pcheck(CreateCompatibleDC(hDC), HDC);
  HBITMAP hbmBuffer = pcheck(CreateCompatibleBitmap(hDC, maxsize, 1), HBITMAP);
  HBITMAP hbmOldBuffer = pcheck(SelectObject(hDCBuffer, hbmBuffer), HBITMAP);

  int x;
  for (x = 0; x < maxsize; x++) {
    int dx = x - mousex;
    int dy = y - mousey;
    // YES this is a slow way of doing it; less than a megapixel per
    // second on my laptop.  Double buffering doesn't help much.
    // Sometimes, apparently at random, this call returns false (in
    // WINE).  I don't know why.  So I don't check the result.
    SetPixel(hDCBuffer, x, 0, (COLORREF)(dx*dx + dy*dy + counter));
    counter = (counter + 1) & 0xffffff;
  }

  check(BitBlt(hDC,  0, y, maxsize, 1,  hDCBuffer, 0, 0,  SRCCOPY));

  y = (y + 1) % maxsize;

  check(SelectObject(hDCBuffer, hbmOldBuffer));
  check(DeleteObject(hbmBuffer));
  check(DeleteDC(hDCBuffer));
  check(ReleaseDC(hWnd, hDC));
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 
{
  switch(msg) {
  case WM_MOUSEMOVE: 
    mousex = LOWORD(lParam);
    mousey = HIWORD(lParam);
    break;
  case WM_DESTROY:
    PostQuitMessage(0);
    break;
  default:
    return DefWindowProc(hWnd, msg, wParam, lParam);
  }
  return 0;
}

int my_message_loop(window_instance *win)
{
  MSG msg;
  for (;;) {
    // PM_NOYIELD means don't block.
    int rv = PeekMessage(&msg, NULL, 0, 0, PM_NOYIELD);
    if (!rv) draw_in(win->hWnd);  // no messages pending
    else if (msg.message == WM_QUIT) return msg.wParam;
    else {
      // I hope this second PeekMessage is guaranteed to work, and get
      // the same message.
      check(PeekMessage(&msg, NULL, 0, 0, PM_NOYIELD | PM_REMOVE));
      TranslateMessage(&msg);
      DispatchMessage(&msg);
    }
  }
}

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR lpCmdLine,
                     int nCmdShow)
{
  WNDCLASSEX windowClass;
  window_instance win;

  init_window_classex(&windowClass, &win, hInstance, WndProc, "AClass");
  windowClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
  check(RegisterClassEx(&windowClass));

  win.title = "hello, world";
  check(create_window(&win, maxsize, maxsize));
  ShowWindow(win.hWnd, nCmdShow);

  return my_message_loop(&win);
}
