/*
Copyright (C) 2004  Melissa K. Schrumpf

This software may be distributed freely, provided that it is
distributed in its entirety, without modifications, and with
the original copyright notice and license included.

You may distribute your own separate patches together with
this software package or a modified package if you always
include a pointer where to get the original unmodified package.
In this case you must inform the author about the modified package.

The software may not be sold for profit or as "hidden" part of 
another software, but it may be included with collections 
of other free software, such as CD-ROM images of FTP servers
and similar, provided that this software is not a significant part 
of that collection.  In this case you must inform the author of the
method of distribution.

Pre-compiled binaries of this software may be distributed in the
same way, provided that this copyright notice and license is
included without modification.

This software may be used freely, for personal and non-profit
use, provided that the original author is always credited.  If you
intend to use this software as a significant part of business
(for-profit) activities, the author's permission is required.  Also,
any usage that is not covered by this license requires the explicit
permission of the author.

This software is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
*/



// PropServ.cpp : Defines the entry point for the console application.
//

//#include "stdafx.h"
#include <windows.h>
#include <winuser.h>
#include <stdio.h>
#include <conio.h>
#include <process.h>


#define COORD (int)1
#define WIND (int)2
#define PID (int)3

RECT workarea;
//BOOL debug = FALSE;
//BOOL zebug = FALSE;
//FILE *zFile;
//int myPid;

DWORD exPID = NULL;
long exWIN = NULL;

BOOL CALLBACK test(HWND, LPARAM);
BOOL CALLBACK EnumWindowsProc(HWND, LPARAM);
//void dbWinSz(int, int, int, int);
//void dbWinMv(int, int, int, int);
//void dbWkAr(int, int, int, int);
//void dbWnH(int);
void showUsage(char *);

int main(int argc, char* argv[]) {
	// TODO pass exception window id ([wm frame .])
	int i = 0;
	int sw = 0;
	int sh = 0;
	int sd = 0;
	int swtyp = 0;
	int ncoord = 0;
	BOOL sleeploop = FALSE;
	BOOL setwkarea = FALSE;
	BOOL isswitch = TRUE;
	BOOL result = FALSE;
	HDC dc = GetDC(NULL);

	workarea.left = 0;
	workarea.right = 0;
	workarea.top = 0;
	workarea.bottom = 0;

	for (i=1;i<argc;i++) {
		if (isswitch) {
			if (strcmpi(argv[i],"-loop")==0) {
				sleeploop = TRUE;
			} else if (strcmpi(argv[i],"-swk")==0) {
				setwkarea = TRUE;
				swtyp = COORD;
				isswitch = FALSE;
			} else if (strcmpi(argv[i],"-wid")==0) {
				swtyp = WIND;
				isswitch = FALSE;
			} else if (strcmpi(argv[i],"-pid")==0) {
				swtyp = PID;
				isswitch = FALSE;
			} else if (strcmpi(argv[i],"-h")==0) {
				showUsage(argv[0]);
				return 0;
			} else if (strcmpi(argv[i],"--help")==0) {
				showUsage(argv[0]);
				return 0;
//			} else if (strcmpi(argv[i],"-debug")==0) {
//				debug = TRUE;
//			} else if (strcmpi(argv[i],"-zebug")==0) {
//				zebug = TRUE;
			} else {
				printf("Error, bad switch: %s\nUse %s --help for details.\n",argv[i],argv[0]);
				return 1;
			}
		} else {
			switch (swtyp) {
				case COORD: {
					switch (ncoord) {
						case 0: {
							workarea.left = atol(argv[i]);
							break;
						}
						case 1: {
							workarea.right = atol(argv[i]);
							break;
						}
						case 2: {
							workarea.top = atol(argv[i]);
							break;
						}
						case 3: {
							workarea.bottom = atol(argv[i]);
							isswitch = TRUE;
							break;
						}
						default: {break;}
						}
					ncoord++;
					break;
				}
				case WIND: {
					exWIN = atol(argv[i]);
					isswitch = TRUE;
					break;
				}
				case PID: {
					exPID = atol(argv[i]);
					isswitch = TRUE;
					break;
				}
				default: {break;}
			}
		}
	}

//if (zebug) {
//	myPid = _getpid();
//	zFile = fopen("zebug.txt", "a");
//	fprintf(zFile,"\nStart PID=%d\n",myPid);
//	fclose(zFile);
//}

	if (setwkarea) {
		if (ncoord!=4) {
				printf("Option -swk requires 4 coordinates.\n");
				return 1;
		} else {
			if (((workarea.right-workarea.left)<200)||((workarea.bottom-workarea.top)<200)) {
				printf("Safe Working Area restriction requires 200x200 minimum.\n");
				return 1;
			} else {
		
//if (zebug) {
//	zFile = fopen("zebug.txt", "a");
//	fprintf(zFile,"%d DoSetWorkArea\n",myPid);
//	fclose(zFile);
//}

				SystemParametersInfo(SPI_SETWORKAREA, (UINT)0, &workarea, SPIF_SENDCHANGE);		
//if (zebug) {
//	zFile = fopen("zebug.txt", "a");
//	fprintf(zFile,"%d WorkArea Set\n",myPid);
//	fclose(zFile);
//}
//				Sleep(1);
//if (zebug) {
//	zFile = fopen("zebug.txt", "a");
//	fprintf(zFile,"%d Slept\n",myPid);
//	fclose(zFile);
//}
				EnumWindows((WNDENUMPROC)EnumWindowsProc, exWIN);
		
//if (zebug) {
//if (1) {
//	FILE *zFile;
//	zFile = fopen("zebug.txt", "a");
//	fprintf(zFile,"Windows Handled\n");
//	fclose(zFile);
//}
//}
			}
		}
	}
	while(!kbhit()) {
		if (ferror(stdout) || ferror(stdin) ||
			feof(stdout) || feof(stdin)) {break;}
//if (zebug) {
//	zFile = fopen("zebug.txt", "a");
//	fprintf(zFile,"%d  Good I/O\n",myPid);
//	fclose(zFile);
//}
		sw = GetSystemMetrics(SM_CXSCREEN);
		sh = GetSystemMetrics(SM_CYSCREEN);
		sd = GetDeviceCaps(dc, BITSPIXEL);
		
//if (zebug) {
//	zFile = fopen("zebug.txt", "a");
//	fprintf(zFile,"%d  Got Metrics\n",myPid);
//	fclose(zFile);
//}
		printf("ScreenDim: %dx%dx%d\n", sw, sh, sd);
		result = SystemParametersInfo(SPI_GETWORKAREA, (UINT)0, &workarea, SPIF_SENDCHANGE);
		if (result) {
			printf("AvailableArea: [%d-%d]x[%d-%d]\n", workarea.left, workarea.right,
				workarea.top, workarea.bottom);
		}
		fflush(stdout);
		if (ferror(stdout) || ferror(stdin) ||
			feof(stdout) || feof(stdin)) {break;}
		
//if (zebug) {
//	zFile = fopen("zebug.txt", "a");
//	fprintf(zFile,"%d  StdOut Flushed\n",myPid);
//	fclose(zFile);
//}
		if (!sleeploop) {break;}
		Sleep(1000);
	}

//if (zebug) {
//	zFile = fopen("zebug.txt", "a");
//	fprintf(zFile,"%d Exiting\n",myPid);
//	fclose(zFile);
//}
	return 0;
}



BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) {
	long lStyle;
	HWND hTray = NULL;
	RECT wndarea;
	DWORD wthrPID;
	GetWindowThreadProcessId(hwnd, &wthrPID);

//BOOL zebug = TRUE;
//FILE *zFile;
//if (zebug) {zFile = fopen("zebug.txt", "a");fprintf(zFile,"WindowProcess Called for %d\n", (int)hwnd);fclose(zFile);}

	try {
		hTray = FindWindow("Shell_TrayWnd", "");
		lStyle = GetWindowLong(hwnd, GWL_STYLE);
		if((IsWindowVisible(hwnd)) && (!IsIconic(hwnd)) && (lStyle&WS_VISIBLE) && (hwnd != hTray) && (hwnd != (HWND)exWIN) && (wthrPID != exPID)) {
//if (zebug) {zFile = fopen("zebug.txt", "a");fprintf(zFile,"0x%x  Window criteria accepted for resize.\n", (int)hwnd);fclose(zFile);}
//dbWkAr(workarea.left, workarea.right, workarea.top, workarea.bottom);
//dbWnH((int)hwnd);
			if(lStyle&WS_MAXIMIZE) {
//if (zebug) {zFile = fopen("zebug.txt", "a");fprintf(zFile,"0x%x  Window is maximized.\n", (int)hwnd);fclose(zFile);}
//dbWinMv(workarea.left, workarea.right, workarea.top, workarea.bottom);
				MoveWindow(hwnd, workarea.left, workarea.top, workarea.right-workarea.left, workarea.bottom-workarea.top, TRUE);
				//MoveWindow(hwnd, workarea.left, workarea.top, workarea.right-workarea.left, workarea.bottom-workarea.top, FALSE);
//if (zebug) {zFile = fopen("zebug.txt", "a");fprintf(zFile,"0x%x  Maximized window resized.\n", (int)hwnd);fclose(zFile);}
			} else {	
//if (zebug) {zFile = fopen("zebug.txt", "a");fprintf(zFile,"0x%x  Window is not maximized.\n", (int)hwnd);fclose(zFile);}
				GetWindowRect(hwnd, &wndarea);
//if (zebug) {zFile = fopen("zebug.txt", "a");fprintf(zFile,"0x%x  Size grabbed.\n", (int)hwnd);fclose(zFile);}
//dbWinSz(wndarea.left, wndarea.right, wndarea.top, wndarea.bottom);
				if(wndarea.top < workarea.top) {
					// window top is above top of new work area
					// shift entire window down, shrinking if necessary
					wndarea.bottom = wndarea.bottom + workarea.top - wndarea.top;
					wndarea.top = workarea.top;
					if (wndarea.bottom>workarea.bottom) {wndarea.bottom = workarea.bottom;}
				}
//if (zebug) {zFile = fopen("zebug.txt", "a");fprintf(zFile,"0x%x  Top Check.\n", (int)hwnd);fclose(zFile);}
//dbWinSz(wndarea.left, wndarea.right, wndarea.top, wndarea.bottom);
				if(wndarea.left < workarea.left) {
					// window left is left of left of new work area
					// shift entire window right, shrinking if necessary
					wndarea.right = wndarea.right + workarea.left - wndarea.left;
					wndarea.left = workarea.left;
					if (wndarea.right>workarea.right) {wndarea.right = workarea.right;}
				}
//if (zebug) {zFile = fopen("zebug.txt", "a");fprintf(zFile,"0x%x  Left Check.\n", (int)hwnd);fclose(zFile);}
//dbWinSz(wndarea.left, wndarea.right, wndarea.top, wndarea.bottom);
				if(wndarea.bottom > workarea.bottom) {
					// window bottom is below bottom of new work area
					// shift entire window up, shrinking if necessary
					wndarea.top = wndarea.top + workarea.bottom - wndarea.bottom;
					wndarea.bottom = workarea.bottom;
					if (wndarea.top<workarea.top) {wndarea.top = workarea.top;}
				}
//if (zebug) {zFile = fopen("zebug.txt", "a");fprintf(zFile,"0x%x  Bottom Check.\n", (int)hwnd);fclose(zFile);}
//dbWinSz(wndarea.left, wndarea.right, wndarea.top, wndarea.bottom);
				if(wndarea.right > workarea.right) {
					// window right is right of right of new work area
					// shift entire window left, shrinking if necessary
					wndarea.left = wndarea.left + workarea.right - wndarea.right;
					wndarea.right = workarea.right;
					if (wndarea.left<workarea.left) {wndarea.left = workarea.left;}
				}
//if (zebug) {zFile = fopen("zebug.txt", "a");fprintf(zFile,"0x%x  Right Check.\n", (int)hwnd);fclose(zFile);}
//dbWinSz(wndarea.left, wndarea.right, wndarea.top, wndarea.bottom);
//dbWinMv(wndarea.left, wndarea.right, wndarea.top, wndarea.bottom);

//if (zebug) {zFile = fopen("zebug.txt", "a");fprintf(zFile,"0x%x  Pre-Move.\n", (int)hwnd);fclose(zFile);}
				MoveWindow(hwnd, wndarea.left, wndarea.top, wndarea.right-wndarea.left, wndarea.bottom-wndarea.top, TRUE);
				//MoveWindow(hwnd, wndarea.left, wndarea.top, wndarea.right-wndarea.left, wndarea.bottom-wndarea.top, FALSE);
//if (zebug) {zFile = fopen("zebug.txt", "a");fprintf(zFile,"0x%x  Moved.\n", (int)hwnd);fclose(zFile);}
			}
		}
//if (zebug) {zFile = fopen("zebug.txt", "a");fprintf(zFile,"WindowProcess Complete for %d\n", (int)hwnd);fclose(zFile);}
		return TRUE;
	}
	catch(...) {
//if (zebug) {zFile = fopen("zebug.txt", "a");fprintf(zFile,"WindowProcess Failed for %d\n", (int)hwnd);fclose(zFile);}
		return TRUE;
	}
}

//void dbWinSz(int l, int r, int t, int b) {
//	if (debug) {printf("Window Area L=%d R=%d T=%d B=%d\n", l, r, t, b);}
//}

//void dbWinMv(int l, int r, int t, int b) {
//	if (debug) {printf("Move Window to %d %d %d %d\n\n", l, t, r-l, b-t);}
//}

//void dbWkAr(int l, int r, int t, int b) {
//	if (debug) {printf("Work Area L=%d R=%d T=%d B=%d\n", l, r, t, b);}
//}

//void dbWnH(int h){
//	if (debug) {printf("0x%08x\n", h);}
//}

void showUsage(char * progn) {
	printf("Usage: %s [-loop] [-swk left right top bottom] [-wid n] [-pid n]\n",progn);
	printf("\t-loop\tShow Screen Size & Depth every 1 second\n");
	printf("\t-swk\tSet Working Area (200x200 minimum limit imposed)\n");
	printf("\t-wid\tWindow ID to ignore when setting working area (decimal)\n");
	printf("\t-pid\tProcess ID to ignore when setting working area (decimal)\n\n");
	fflush(stdout);
}







