/* Functions Graph version 1.02 for Windows, 28-07-2004
 *
 * Draw mathematical functions in a coordinate system.
 */

#include <windows.h>
#include <math.h>

#define DIM	500

#define IDC_MAIN_STATUS	1001

#define ID_FILE_RESET	5000
#define ID_FILE_EXIT	5001

#define ID_FUNCS_COSX	7001
#define ID_FUNCS_SINX	7002
#define ID_FUNCS_X2		7003
#define ID_FUNCS_X3		7004
#define ID_FUNCS_EX		7005
#define ID_FUNCS_LNX	7006

#define ID_HELP_ABOUT 9100

const char g_szClassName[] = "Functions Graph by koby";

int flag=0;

LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {

	PAINTSTRUCT ps;
	HDC hdc;
	double x, y;
	int p, q;
	double h=20.00;
	int t, res;
	char Pos[20], tmp[20];

	POINTS coord;

	coord = MAKEPOINTS(lParam);

	strcpy(Pos, "x=");

	itoa((int)(coord.x-DIM/2)/(DIM/20), tmp, 10);
	strcat(Pos, tmp);
	strcat(Pos, " y=");
	itoa((int)(DIM/2-coord.y)/(DIM/20), tmp, 10);

	strcat(Pos, tmp);

	SendDlgItemMessage(hwnd, IDC_MAIN_STATUS, SB_SETTEXT, 1, (LPARAM)Pos);

	switch(Message)	{
		case WM_CREATE:	{

			HMENU hMenu, hSubMenu;

			HWND hStatus;
			int statwidths[] = {100, -1};

			// Create Menu

			hMenu = CreateMenu();

			hSubMenu = CreatePopupMenu();
			AppendMenu(hSubMenu, MF_STRING, ID_FILE_RESET, "&Reset");
			AppendMenu(hSubMenu, MF_SEPARATOR, 0, NULL);
			AppendMenu(hSubMenu, MF_STRING, ID_FILE_EXIT, "&Exit");
			AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, "&File");

			hSubMenu = CreatePopupMenu();
			AppendMenu(hSubMenu, MF_STRING, ID_FUNCS_COSX, "&cos(x)");
			AppendMenu(hSubMenu, MF_STRING, ID_FUNCS_SINX, "&sin(x)");
			AppendMenu(hSubMenu, MF_SEPARATOR, 0, NULL);
			AppendMenu(hSubMenu, MF_STRING, ID_FUNCS_EX, "&exp(x)");
			AppendMenu(hSubMenu, MF_STRING, ID_FUNCS_LNX, "&ln(x)");
			AppendMenu(hSubMenu, MF_SEPARATOR, 0, NULL);
			AppendMenu(hSubMenu, MF_STRING, ID_FUNCS_X2, "&x^2");
			AppendMenu(hSubMenu, MF_STRING, ID_FUNCS_X3, "&x^3");
			AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, "&Functions");

			hSubMenu = CreatePopupMenu();
			AppendMenu(hSubMenu, MF_STRING, ID_HELP_ABOUT, "&About...");
			AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, "&Help");

			SetMenu(hwnd, hMenu);

			// Create Status bar

			hStatus = CreateWindowEx(0, STATUSCLASSNAME, NULL,
				WS_CHILD | WS_VISIBLE, 0, 0, 0, 0,
				hwnd, (HMENU)IDC_MAIN_STATUS, GetModuleHandle(NULL), NULL);

			SendMessage(hStatus, SB_SETPARTS, sizeof(statwidths)/sizeof(int), (LPARAM)statwidths);
			SendMessage(hStatus, SB_SETTEXT, 0, (LPARAM)"Sel a function");

		}
		break;
		case WM_PAINT: {
			SetCursor( LoadCursor(NULL, IDC_WAIT) );
			if (flag!=0 ) {
				RECT rect;

				hdc = BeginPaint(hwnd, &ps);

				SetRect(&rect, 0, 0, DIM+100, DIM+100);
				FillRect(hdc, &rect, (HBRUSH) (COLOR_WINDOW+1));

				for(x=0, y=DIM/2; x<=DIM; x++)
					SetPixel(hdc, x, y, RGB(255, 0, 0) );
				for(x=DIM/2, y=0; y<=DIM; y++)
					SetPixel(hdc, x, y, RGB(255, 0, 0) );
				for(x=-10.00; x<=10.00; x+=1) {
					SetPixel(hdc, (int)(DIM/2 + DIM/20*x), DIM/2+1, RGB(255, 0, 0) );
					SetPixel(hdc, (int)(DIM/2 + DIM/20*x), DIM/2-1, RGB(255, 0, 0) );
				}
				for(y=-10.00; y<=10.00; y+=1) {
					SetPixel(hdc, DIM/2+1, (int)(DIM/2 + DIM/20*y), RGB(255, 0, 0) );
					SetPixel(hdc, DIM/2-1, (int)(DIM/2 + DIM/20*y), RGB(255, 0, 0) );
				}

				for(x=-10.00; x<=10.00; x+=0.001) {
					switch(flag) {
							case 1: {
								y=cos(x);
								break;
							}
							case 2: {
								y=sin(x);
								break;
							}
							case 3: {
								y=x*x;
								break;
							}
							case 4: {
								y=x*x*x;
								break;
							}
							case 5: {
								y=exp(x);
								break;
							}
							case 6: {
								y=log(x);
								break;
							}
					}

					p=(int)(DIM/2 + DIM/20*x);
					q=(int)(DIM/2 - DIM/20*y);
					SetPixel(hdc, p, q, 0);
				}

				EndPaint(hwnd, &ps);
				SetCursor( LoadCursor(NULL, IDC_ARROW) );
				return 0L;
			}
			else if( !flag) {
				RECT rect;

				hdc = BeginPaint(hwnd, &ps);

				SetRect(&rect, 0, 0, DIM+100, DIM+100);
				FillRect(hdc, &rect, (HBRUSH) (COLOR_WINDOW+1));

				for(x=0, y=DIM/2; x<=DIM; x++)
					SetPixel(hdc, x, y, RGB(255, 0, 0) );
				for(x=DIM/2, y=0; y<=DIM; y++)
					SetPixel(hdc, x, y, RGB(255, 0, 0) );
				for(x=-10.00; x<=10.00; x+=1) {
					SetPixel(hdc, (int)(DIM/2 + DIM/20*x), DIM/2+1, RGB(255, 0, 0) );
					SetPixel(hdc, (int)(DIM/2 + DIM/20*x), DIM/2-1, RGB(255, 0, 0) );
				}
				for(y=-10.00; y<=10.00; y+=1) {
					SetPixel(hdc, DIM/2+1, (int)(DIM/2 + DIM/20*y), RGB(255, 0, 0) );
					SetPixel(hdc, DIM/2-1, (int)(DIM/2 + DIM/20*y), RGB(255, 0, 0) );
				}

				EndPaint(hwnd, &ps);
			}
		}
		break;
		case WM_COMMAND:
			switch(LOWORD(wParam)) {
				case ID_FILE_RESET:
					flag=0;
					RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE);
					SendDlgItemMessage(hwnd, IDC_MAIN_STATUS, SB_SETTEXT, 0, (LPARAM)"Sel a function");
				break;
				case ID_FILE_EXIT:
					PostMessage(hwnd, WM_CLOSE, 0, 0);
				break;
				case ID_FUNCS_COSX:
					flag=1;
					RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE);
					SendDlgItemMessage(hwnd, IDC_MAIN_STATUS, SB_SETTEXT, 0, (LPARAM)"f(x)=cos(x)");
				break;
				case ID_FUNCS_SINX:
					flag=2;
					RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE);
					SendDlgItemMessage(hwnd, IDC_MAIN_STATUS, SB_SETTEXT, 0, (LPARAM)"f(x)=sin(x)");
				break;
				case ID_FUNCS_X2:
					flag=3;
					RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE);
					SendDlgItemMessage(hwnd, IDC_MAIN_STATUS, SB_SETTEXT, 0, (LPARAM)"f(x)=x^2");
				break;
				case ID_FUNCS_X3:
					flag=4;
					RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE);
					SendDlgItemMessage(hwnd, IDC_MAIN_STATUS, SB_SETTEXT, 0, (LPARAM)"f(x)=x^3");
				break;
				case ID_FUNCS_EX:
					flag=5;
					RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE);
					SendDlgItemMessage(hwnd, IDC_MAIN_STATUS, SB_SETTEXT, 0, (LPARAM)"f(x)=exp(x)");
				break;
				case ID_FUNCS_LNX:
					flag=6;
					RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE);
					SendDlgItemMessage(hwnd, IDC_MAIN_STATUS, SB_SETTEXT, 0, (LPARAM)"f(x)=ln(x)");
				break;
				case ID_HELP_ABOUT:
					MessageBox(hwnd, "Functions Graph\nVersion 1.02\n\nDeveloped by koby\n"
								"Please send bug reports and suggestions... koby@in.gr\n\n"
								"Newest version and source code can be found at the site:\n"
								"\t  http://www.codecraft.tk\n\n"
								"Feel free to distribute...",
								"About Functions Graph", MB_OK | MB_ICONINFORMATION);
				break;
			}
		break;
		case WM_CLOSE:
			DestroyWindow(hwnd);
		break;
		case WM_DESTROY:
			PostQuitMessage(0);
		break;
		default:
			return DefWindowProc(hwnd, Message, wParam, lParam);
	}
	return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {

	InitCommonControls();

	WNDCLASSEX wc;
	HWND hwnd;
	MSG Msg;

	wc.cbSize	 = sizeof(WNDCLASSEX);
	wc.style	 = 0;
	wc.lpfnWndProc	 = WndProc;
	wc.cbClsExtra	 = 0;
	wc.cbWndExtra	 = 0;
	wc.hInstance	 = hInstance;
	wc.hIcon	 = NULL;
	wc.hCursor	 = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
	wc.lpszMenuName  = NULL;
	wc.lpszClassName = g_szClassName;
	wc.hIconSm	 = NULL;

	if(!RegisterClassEx(&wc)) {
		MessageBox(NULL, "Window Registration Failed!", "Error!",
			MB_ICONEXCLAMATION | MB_OK);
		return 0;
	}

	hwnd = CreateWindowEx(
		WS_EX_CLIENTEDGE | WS_EX_TOPMOST,
		g_szClassName,
		"Functions Graph by koby",
		WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU,
		CW_USEDEFAULT, CW_USEDEFAULT, DIM+11, DIM+77,
		NULL, NULL, hInstance, NULL);

	if(hwnd == NULL) {
		MessageBox(NULL, "Window Creation Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
		return 0;
	}

	ShowWindow(hwnd, nCmdShow);
	UpdateWindow(hwnd);

	while(GetMessage(&Msg, NULL, 0, 0) > 0) {
		TranslateMessage(&Msg);
		DispatchMessage(&Msg);
	}

	return Msg.wParam;
}
