#include "StdAfx.h"
#include "WindowFinder.h"

#include <algorithm>
#include <iostream>

BOOL CALLBACK EnumChildren(HWND hwnd, LPARAM lParam) {
	int resourceId = 0;
	int windowTextLen = 128;
	wchar_t * windowText = new wchar_t[128];
	int classNameLen = 128;
	wchar_t * className = new wchar_t[128];

	WindowFinder * finder = (WindowFinder*) lParam;

	resourceId = GetDlgCtrlID(hwnd);
	windowTextLen = GetWindowText(hwnd, windowText, windowTextLen);
	classNameLen = GetClassName(hwnd, className, classNameLen);

	finder->setEqualityScore(hwnd,resourceId, windowText, className);
	
	return TRUE;
}

WindowFinder::WindowFinder()
{
	evalPopup = false;
	parentHandles = NULL;
	success = true;
}

WindowFinder::~WindowFinder(void)
{
}

HWND WindowFinder::find(WindowData * winData) {
	currentWindow = winData;
	maxScore = 0;
	scores = new std::vector<std::pair<HWND, int>>();

	if( parentHandles==NULL ) {
		EnumWindows(EnumChildren, (LPARAM) this);
	} else {
		if( winData->isModal ) {
			evalPopup = true;
			EnumWindows(EnumChildren, (LPARAM) this);
			evalPopup = false;
		} else {
			for( size_t i=0 ; i<parentHandles->size() ; i++ ) {
				EnumChildWindows((*parentHandles)[i], EnumChildren, (LPARAM) this);
			}
		}
		delete parentHandles;
	}
	parentHandles = new std::vector<HWND>();
	for( size_t i=0 ; i<scores->size() ; i++ ) {
		if( (*scores)[i].second==maxScore ) {
			parentHandles->push_back((*scores)[i].first);
		}
	}
	delete scores;
	
	HWND result = NULL;

	if( winData->child!=NULL ) {
		if( maxScore==0 ) {
			std::wcerr << L"Warning: Score is zero." << std::endl;
			errorMessage = L"score zero";
			success = false;
		}
		result = find(winData->child);
	} else {
		if( parentHandles->size()==0 ) {
			std::wcerr << L"Error: handle not found." << std::endl;
			errorMessage = L"handle not found";
			result = NULL;
			success = false;
		}
		else {
			if( parentHandles->size()!=1 ) {
				std::wcerr << L"Warning: more than one fitting window found." << std::endl;
				errorMessage = L"multiple matches";
				success = false;
			}
			if( maxScore==0 ) {
				std::wcerr << L"Warning: Score is zero." << std::endl;
				errorMessage = L"score zero";
				success = false;
			}
			result = (*parentHandles)[0];
			delete parentHandles;
		}
	}
	return result;
}


void WindowFinder::setEqualityScore(HWND hwnd, int resourceId, wchar_t * windowName, wchar_t * className) {
	int score = 0;

	if( resourceId!=0 && currentWindow->resourceId==resourceId && currentWindow->name.compare(windowName)==0 && currentWindow->className.compare(className)==0 ) {
		score = 6;
	}
	else if( resourceId!=0 && currentWindow->resourceId==resourceId && currentWindow->name.compare(windowName)==0 ) {
		score = 5;
	}
	else if( resourceId!=0 && currentWindow->resourceId==resourceId ) {
		score = 4;
	}
	else if( currentWindow->name.compare(windowName)==0 && currentWindow->className.compare(className)==0 ) {
		score = 3;
	}
	else if( currentWindow->name.compare(windowName)==0 ) {
		score = 2;
	}
	else if( currentWindow->className.compare(className)==0 ) {
		score = 1;
	}
	if( evalPopup ) {
		HWND parent = GetParent(hwnd);
		if( std::find(parentHandles->begin(), parentHandles->end(), parent)==parentHandles->end() ) {
			score = 0;
		}
	}

	scores->push_back(std::make_pair(hwnd, score));

	if( score>maxScore ) {
		maxScore = score;
	}
}

bool WindowFinder::isCurrentPopup() {
	return evalPopup;
}

bool WindowFinder::successfull() {
	return success;
}

std::wstring WindowFinder::getErrorMessage() {
	return errorMessage;
}