#include <clip.h>

#define APPNAME		"jpegwin"
#define SIZE_MAX	2048

//	#define FNAME	"douton_c.jpg"
	#define FNAME	"douton_g.jpg"

int win_scale;
int file_size;
unsigned char* file_data;

int img_w;
int img_h;
unsigned char img[SIZE_MAX][SIZE_MAX][3/*Y,Cb,Cr*/];

BITMAPINFOHEADER bi;
unsigned char* dib;

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

static void my_size_proc(int w, int h, void* user_data) {
	img_w = w;
	img_h = h;
}

static void my_draw_proc(int x, int y, int c, void* user_data) {
	int component = (int)user_data;
	if((component < 0) || (component > 2)) {
		DIE();
	}
	if(x < 0 || x > img_w - 1 || y < 0 || y > img_h - 1) {
		DIE();
	}
	if(c & ~255) {
		DIE();
	}
	img[y][x][component] = c;
}

int main(int argc, char* argv[]) {
	const char* fname;
	FILE* fp;
	int pitch;
	int i;
	int x;
	int y;
	HINSTANCE hInst;
	HWND hWnd;
	MSG msg;
	WNDCLASS wc;
	RECT rcWin;
	RECT rcCli;
	int ncW;
	int ncH;

	DEBUG_INIT();

	fname = (argc >= 1 + 1) ? argv[1] : FNAME;
	win_scale = (argc >= 1 + 2) ? atoi(argv[2]) : 1;
	if(win_scale < 1) win_scale = 1;

	fp = fopen(fname, "rb");
	if(!fp) {
		DIE();
	}
	fseek(fp, 0, SEEK_END);
	file_size = ftell(fp);
	rewind(fp);
	file_data = malloc(file_size);
	if(!file_data) {
		DIE();
	}
	fread(file_data, 1, file_size, fp);
	fclose(fp);

	memset(img, 128, sizeof img); /* Cb,Crが無かった場合のために、中間値としておく */
	for(i = 0; i < 3/*Y,Cb,Cr*/; i++) {
		jpeg_decode(file_data, i, my_size_proc, my_draw_proc, NULL, (void*)i);
	}

	bi.biSize = sizeof(BITMAPINFOHEADER);
	bi.biWidth = img_w;
	bi.biHeight = img_h;
	bi.biPlanes = 1;
	bi.biBitCount = 24;
	pitch = ((img_w * 3) + 3) & ~3;
	dib = malloc(pitch * img_h);
	if(!dib) {
		DIE();
	}
	for(y = 0; y < img_h; y++) {
		for(x = 0; x < img_w; x++) {
			int Y  = dib[y * pitch + x * 3 + 0] = img[img_h - 1 - y][x][0];
			int Cb = dib[y * pitch + x * 3 + 1] = img[img_h - 1 - y][x][1];
			int Cr = dib[y * pitch + x * 3 + 2] = img[img_h - 1 - y][x][2];
			int R = Y                        + 1.402   * (Cr - 128);
			int G = Y - 0.34414 * (Cb - 128) - 0.71414 * (Cr - 128);
			int B = Y + 1.772   * (Cb - 128);
			if(R < 0) R = 0; if(R > 255) R = 255;
			if(G < 0) G = 0; if(G > 255) G = 255;
			if(B < 0) B = 0; if(B > 255) B = 255;
			dib[y * pitch + x * 3 + 0] = img[img_h - 1 - y][x][0] = B;
			dib[y * pitch + x * 3 + 1] = img[img_h - 1 - y][x][1] = G;
			dib[y * pitch + x * 3 + 2] = img[img_h - 1 - y][x][2] = R;
		}
	}

	hInst = GetModuleHandle(NULL);
	memset(&wc, 0, sizeof wc);
	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc = WndProc;
	wc.hInstance = hInst;
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.lpszClassName = APPNAME;
	RegisterClass(&wc);
	hWnd = CreateWindow(APPNAME, APPNAME,
		WS_POPUP,
		CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
		NULL, NULL, hInst, NULL);
	GetWindowRect(hWnd, &rcWin);
	GetClientRect(hWnd, &rcCli);
	ncW = (rcWin.right - rcWin.left) - (rcCli.right - rcCli.left);
	ncH = (rcWin.bottom - rcWin.top) - (rcCli.bottom - rcCli.top);
	MoveWindow(hWnd, 0, 0, ncW + img_w * win_scale, ncH + img_h * win_scale, FALSE);
	ShowWindow(hWnd, SW_SHOW);
	UpdateWindow(hWnd);

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

	free(file_data);
	free(dib);

	return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
	HDC hDC;
	PAINTSTRUCT ps;

	switch(msg) {
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	case WM_KEYDOWN:
		if(wParam == VK_ESCAPE) {
			SendMessage(hWnd, WM_CLOSE, 0, 0);
			return 0;
		}
		return 0;
	case WM_PAINT:
		hDC = BeginPaint(hWnd, &ps);
		StretchDIBits(hDC,
			0, 0, bi.biWidth * win_scale, bi.biHeight * win_scale,
			0, 0, bi.biWidth, bi.biHeight,
			dib, (BITMAPINFO*)&bi, DIB_RGB_COLORS, SRCCOPY);
		EndPaint(hWnd, &ps);
		return 0;
	}
	return DefWindowProc(hWnd, msg, wParam, lParam);
}

