#include "windows.h"		    /* required for all Windows applications */
#include "kiviat.h"		   /* specific to this program		    */
#include <math.h>
#include <dos.h>


#define PI 3.14159265359
#define FIX_WERTE 5

static int howoften= 1000,
	   werte_anzahl = 5,
	   max_tasks = 100;
static long max_mem, largest_block;

HANDLE hInst;			    /* current instance			     */
int MyTimer;
static long LastCall;
static HBRUSH hRed, hGreen, hYellow;

int PASCAL WinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow)
HANDLE hInstance;			     /* current instance	     */
HANDLE hPrevInstance;			     /* previous instance	     */
LPSTR lpCmdLine;			     /* command line		     */
int nCmdShow;				     /* show-window type (open/icon) */
{
    MSG msg;				     /* message			     */

    if (!hPrevInstance)			 /* Other instances of app running? */
	if (!InitApplication(hInstance)) /* Initialize shared things */
	    return (FALSE);		 /* Exits if unable to initialize     */

    /* Perform initializations that apply to a specific instance */

    if (!InitInstance(hInstance, nCmdShow))
        return (FALSE);

    /* Acquire and dispatch messages until a WM_QUIT message is received. */

    while (GetMessage(&msg,	   /* message structure			     */
	    NULL,		   /* handle of window receiving the message */
	    NULL,		   /* lowest message to examine		     */
	    NULL))		   /* highest message to examine	     */
	{
	TranslateMessage(&msg);	   /* Translates virtual key codes	     */
	DispatchMessage(&msg);	   /* Dispatches message to window	     */
    }
    return (msg.wParam);	   /* Returns the value from PostQuitMessage */
}


BOOL InitApplication(hInstance)
HANDLE hInstance;			       /* current instance	     */
{
    WNDCLASS  wc;

    /* Fill in window class structure with parameters that describe the       */
    /* main window.                                                           */

    wc.style = NULL;                    /* Class style(s).                    */
    wc.lpfnWndProc = MainWndProc;       /* Function to retrieve messages for  */
                                        /* windows of this class.             */
    wc.cbClsExtra = 0;                  /* No per-class extra data.           */
    wc.cbWndExtra = 0;                  /* No per-window extra data.          */
    wc.hInstance = hInstance;           /* Application that owns the class.   */
    wc.hIcon = NULL;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = GetStockObject(WHITE_BRUSH); 
    wc.lpszMenuName =  NULL;   /* Name of menu resource in .RC file. */
    wc.lpszClassName = "kiviatWClass"; /* Name used in call to CreateWindow. */

    /* Register the window class and return success/failure code. */

    return (RegisterClass(&wc));

}


BOOL InitInstance(hInstance, nCmdShow)
    HANDLE          hInstance;          /* Current instance identifier.       */
    int             nCmdShow;           /* Param for first ShowWindow() call. */
{
    HWND	    hWnd;		/* Main window handle.		      */
    HMENU	    hSysMenu;

    /* Save the instance handle in static variable, which will be used in  */
    /* many subsequence calls from this application to Windows.            */

    hInst = hInstance;

    /* Create a main window for this application instance.  */

    hWnd = CreateWindow(
	"kiviatWClass", 	       /* See RegisterClass() call.	     */
	"Kiviat Graph",   /* Text for window title bar. 	*/
	WS_OVERLAPPEDWINDOW | WS_ICONIC |
	WS_SYSMENU | WS_MINIMIZE,
        CW_USEDEFAULT,                  /* Default horizontal position.       */
        CW_USEDEFAULT,                  /* Default vertical position.         */
        CW_USEDEFAULT,                  /* Default width.                     */
        CW_USEDEFAULT,                  /* Default height.                    */
        NULL,                           /* Overlapped windows have no parent. */
        NULL,                           /* Use the window class menu.         */
        hInstance,                      /* This instance owns this window.    */
        NULL                            /* Pointer not needed.                */
    );

    /* If window could not be created, return "failure" */

    if (!hWnd)
        return (FALSE);

    /* Make the window visible; update its client area; and return "success" */

    hRed    = CreateSolidBrush(RGB(255,0,0));
    hGreen  = CreateSolidBrush(RGB(0,255,0));
    hYellow = CreateSolidBrush(RGB(255,255,0));

    hSysMenu = GetSystemMenu(hWnd, FALSE);
    AppendMenu(hSysMenu, MF_SEPARATOR, 0, NULL);
    AppendMenu(hSysMenu, MF_STRING, IDM_ABOUT, "About Kiviat");
    AppendMenu(hSysMenu, MF_STRING, IDM_SETUP, "Setup...");

    /* Initialize Variables */
    max_mem	 = 1024l * (long)GetProfileInt(APPNAME, "MaxMem", 1024);
    howoften	 = GetProfileInt(APPNAME, "SampleRate", 1000);
    werte_anzahl = FIX_WERTE + GetProfileInt(APPNAME, "HardDrives", 1);
    max_tasks	 = GetProfileInt(APPNAME, "MaxTasks", 50);
    largest_block= 1024l * (long)GetProfileInt(APPNAME, "LargestBlock", 1024);

    LastCall = GetTickCount();
    MyTimer = SetTimer(hWnd, 1, howoften, NULL);

    ShowWindow(hWnd, SW_MINIMIZE);  /* Show the window			      */
    UpdateWindow(hWnd);          /* Sends WM_PAINT message                 */
    return (TRUE);               /* Returns the value from PostQuitMessage */

}

static double GetSysInfo(int which) {
    static long all;
    switch (which) {
	case 0: /* Get Free Memory */ {
	    long above, below;
	    above = GetFreeSpace(GMEM_NOT_BANKED);
	    below = GetFreeSpace(0);
	    all = (above != below) ? above + below : below;
	    return((double)all / (double)max_mem);
	}
	case 1: /* Largest Free Block */ {
	    long n;
	    n = GlobalCompact(0l);
	    if (n > largest_block)
		return(1.0);
	    else
		return((double)n / (double)largest_block);
	}
	case 2: /* Ticks */ {
	    long NowCall, CallDiff;
	    NowCall = GetTickCount();
	    CallDiff = NowCall - LastCall;
	    return((double) howoften / (double)CallDiff);
	}
	case 3: /* Disk I/O Time */ {
	    long start;
	    int f;
	    start = -GetTickCount();
	    f = _lcreat("kiviat.tmp", OF_WRITE | OF_SHARE_DENY_NONE);
	    _lwrite(f, (LPSTR)"Kiviat - Graph, by Wolfgang Tremmel", 34);
	    _lclose(f);
	    unlink("kiviat.tmp");
	    start += GetTickCount();
	    start /= 300;
	    return(1.0 / (double)(1+start));
	}
	case 4: /* Tasks */
	    return((max_tasks - GetNumTasks()) / 100.0);
	default:
	     /* Filespace on x */ {
		struct diskfree_t df;
		_dos_getdiskfree(which-2,  &df);
		return((double)df.avail_clusters / (double)df.total_clusters);
	}

    }
}

static KiviatGraph(HWND hWnd) {
    HDC hDC, hDCw;
    PAINTSTRUCT paint;
    RECT winrect;
    int i;
    HRGN hRgn;
    HBITMAP hBitmap, hOldBitmap;
    double a= 0.0, b = 1.0;
    double *ww;

    ww = (double *) malloc(sizeof(double) * werte_anzahl);
    for (i = 0; i < werte_anzahl; i++)
	*(ww+i) = GetSysInfo(i);

    GetClientRect(hWnd, (LPRECT)&winrect);
    /* InvalidateRect(hWnd,(LPRECT)&winrect, TRUE); */

    hDCw = GetDC(hWnd);

    hDC = CreateCompatibleDC(hDCw);
    hBitmap = CreateCompatibleBitmap(hDCw, winrect.right, winrect.bottom);
    hOldBitmap = SelectObject(hDC, hBitmap);
    PatBlt(hDC, 0, 0, winrect.right, winrect.bottom, WHITENESS);


    /* hDC = BeginPaint(hWnd, (LPPAINTSTRUCT)&paint); */

    Ellipse(hDC, winrect.left,
		 winrect.top,
		 winrect.right,
		 winrect.bottom);

    for (i = 0; i < werte_anzahl; i++) {
	int x1,y1, x2, y2, x3, y3, x4, y4;
	double w;

	/* MoveTo(hDC, (winrect.right-winrect.left)/2, (winrect.bottom-winrect.top)/2); */

	/* w = GetSysInfo(i); */
	w = *(ww + i);

	if (w > 0.75)
	    SelectObject(hDC, hGreen);
	else if (w > 0.4)
	    SelectObject(hDC, hYellow);
	else
	    SelectObject(hDC, hRed);

	x1 = (winrect.right - (int)(winrect.right * w)) / 2;
	y1  = (winrect.bottom- (int)(winrect.bottom* w)) / 2;

	x2 = winrect.right - x1;
	y2 = winrect.bottom - y1;

	x3 = (int)((winrect.right*2) * a);
		  /* (sin((2*PI/werte_anzahl)*i))); */
	y3 = (int)((winrect.bottom*2) * b);
		  /* (cos((2*PI/werte_anzahl)*i))); */
	x4 = (int)((winrect.right*2) *
		  (a = sin((2*PI/werte_anzahl)*(i+1))));
	y4 = (int)((winrect.bottom*2) *
		  (b = cos((2*PI/werte_anzahl)*(i+1))));


	Pie(hDC, x1, y1, x2, y2,
		 x3, y3, x4, y4);

    }


    BitBlt(hDCw, 0, 0, winrect.right, winrect.bottom, hDC, 0, 0, SRCCOPY);
    SelectObject(hDC, hOldBitmap);
    DeleteDC(hDC);
    ReleaseDC(hWnd, hDCw);
    DeleteObject(hBitmap);

    free(ww);

    /* EndPaint(hWnd, (LPPAINTSTRUCT)&paint); */
}


long FAR PASCAL MainWndProc(hWnd, message, wParam, lParam)
HWND hWnd;				  /* window handle		     */
unsigned message;			  /* type of message		     */
WORD wParam;				  /* additional information	     */
LONG lParam;				  /* additional information	     */
{
    FARPROC lpProc;		     /* pointer to the "About" function */

    switch (message) {
	case WM_SYSCOMMAND:	      /* message: command from application menu */
	    switch(wParam) {
		case IDM_ABOUT:
		    lpProc = MakeProcInstance(About, hInst);
		    DialogBox(hInst, "AboutBox", hWnd, lpProc);
		    FreeProcInstance(lpProc);
		    break;
		case IDM_SETUP:
		    lpProc = MakeProcInstance(Setup, hInst);
		    DialogBox(hInst, "Setup", hWnd, lpProc);
		    FreeProcInstance(lpProc);
		    break;
		default:
		    return (DefWindowProc(hWnd, message, wParam, lParam));
	    }
	    break;
	/* case WM_PAINT:
	    LastCall = GetTickCount();
	*/
	case WM_TIMER:
	    KillTimer(hWnd, 1);
	    KiviatGraph(hWnd);
	    MyTimer = SetTimer(hWnd, 1, howoften, NULL);
	    LastCall = GetTickCount();
	    PostMessage(hWnd, WM_COMMAND, 9999, LastCall);
	    break;
	case WM_DESTROY:		  /* message: window being destroyed */
	    PostQuitMessage(0);
	    break;

	default:			  /* Passes it on if unproccessed    */
	    return (DefWindowProc(hWnd, message, wParam, lParam));
    }
    return (NULL);
}


BOOL FAR PASCAL About(hDlg, message, wParam, lParam)
HWND hDlg;                                /* window handle of the dialog box */
unsigned message;                         /* type of message                 */
WORD wParam;                              /* message-specific information    */
LONG lParam;
{
    switch (message) {
	case WM_INITDIALOG:		   /* message: initialize dialog box */
	    return (TRUE);

	case WM_COMMAND:		      /* message: received a command */
	    if (wParam == IDOK                /* "OK" box selected?	     */
                || wParam == IDCANCEL) {      /* System menu close command? */
		EndDialog(hDlg, TRUE);	      /* Exits the dialog box	     */
		return (TRUE);
	    }
	    break;
    }
    return (FALSE);			      /* Didn't process a message    */
}

BOOL FAR PASCAL Setup(hDlg, message, wParam, lParam)
HWND hDlg;                                /* window handle of the dialog box */
unsigned message;                         /* type of message                 */
WORD wParam;                              /* message-specific information    */
LONG lParam;
{
    switch (message) {
	case WM_INITDIALOG:		   /* message: initialize dialog box */
	    SetDlgItemInt(hDlg, IDC_MEMORY, (int)(max_mem / 1024l), FALSE);
	    SetDlgItemInt(hDlg, IDC_TIME,   howoften, FALSE);
	    SetDlgItemInt(hDlg, IDC_DRIVES, werte_anzahl - FIX_WERTE, FALSE);
	    SetDlgItemInt(hDlg, IDC_TASKS, max_tasks, FALSE);
	    SetDlgItemInt(hDlg, IDC_BLOCK, (int)(largest_block / 1024l), FALSE);
	    return (TRUE);

	case WM_COMMAND:		      /* message: received a command */
	    if (wParam == IDOK) {
		BOOL ok;
		int t;
		char s[10];

		t = GetDlgItemInt(hDlg, IDC_MEMORY, (BOOL FAR *)&ok, FALSE);
		if (ok) {
		    sprintf(s,"%d",t);
		    WriteProfileString(APPNAME,"MaxMem",(LPSTR)s);
		    max_mem = 1024l * (long)t;
		}

		t = GetDlgItemInt(hDlg, IDC_BLOCK, (BOOL FAR *)&ok, FALSE);
		if (ok) {
		    sprintf(s,"%d",t);
		    WriteProfileString(APPNAME,"LargestBlock",(LPSTR)s);
		    largest_block = 1024l * (long)t;
		}

		t = GetDlgItemInt(hDlg, IDC_TIME, (BOOL FAR *)&ok, FALSE);
		if (ok) {
		    sprintf(s,"%d",t);
		    WriteProfileString(APPNAME,"SampleRate",(LPSTR)s);
		    howoften = t;
		}

		t = GetDlgItemInt(hDlg, IDC_DRIVES, (BOOL FAR *)&ok, FALSE);
		if (ok) {
		    sprintf(s,"%d",t);
		    WriteProfileString(APPNAME,"HardDrives",(LPSTR)s);
		    werte_anzahl = t + FIX_WERTE;
		}

		t = GetDlgItemInt(hDlg, IDC_TASKS, (BOOL FAR *)&ok, FALSE);
		if (ok) {
		    sprintf(s,"%d",t);
		    WriteProfileString(APPNAME,"MaxTasks",(LPSTR)s);
		    max_tasks = t;
		}

		EndDialog(hDlg, TRUE);
		return(TRUE);
	    }
	    else if (wParam == IDCANCEL) {
		EndDialog(hDlg, FALSE);
		return(TRUE);
	    }
	    break;
    }
    return (FALSE);			      /* Didn't process a message    */
}
