#include "main.h"
#include "windows.h"
#include "Psapi.h"
#include "shlwapi.h"
#include "time.h"
#include <math.h>
#define MY_TIMER    122

//MSG Msg;//Структура Msg типа MSG для получения сообщений Windows
//-------------------------------------------------------------------------------------
/*Главная функция WinMaln*/
 HINSTANCE hInstance;
 
 const int iHeightEdit=20;

 HWND hWndMain;
 HWND hButExit,hButClear,hButRun;
 HWND hListBox;
 
 wchar_t buf[256];
 LONG maxPlaces = 3;
 const int maxTrains = 5;

 HANDLE hSemaphore;
 HANDLE trainHandles[maxTrains];
 int trainID[maxTrains];
 
int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrev,LPSTR lpCmd, int nShow)
{
//-------------------------------------------------------------------------------------
  hInstance=hInst;
  WNDCLASSEX  wc;//Структура we типа WNDCLASS для задания характеристик окна
  static LPCTSTR szClassName = TEXT("MainLab5Window");//Произвольное имя класса главного окна
  static LPCTSTR szTitle = TEXT("Железнодорожная станция");//заголовок окна
   /*Зарегистрируем класс главного окна*/
  ZeroMemory(&wc,sizeof(wc));//Обнуление всех членов структуры wс
  wc.cbSize = sizeof(wc); // Set structure size
  wc.style = CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc=WndProc; // Определяем оконную процедуру для главного окна
  wc.hInstance=hInst;//Дескриптор приложения
  wc.hIcon = LoadIcon(0, IDI_APPLICATION);//Стандартная пиктограмма
  wc.hCursor=LoadCursor(NULL,IDC_ARROW);//Стандартный курсор мыши
  char ID_MAINMENU[10] = "menu? o_0";
  wc.hbrBackground=CreateSolidBrush(GetSysColor(COLOR_BTNFACE));// системный цвет рабочий области окна
  wc.lpszMenuName=(LPCWSTR)ID_MAINMENU; 
  wc.lpszClassName=szClassName;//Имя класса окна

  RegisterClassEx(&wc);//Вызов функции Windows регистрации класса окна
  //Создадим главное окно по центру экрана и сделаем его видимым
  
  hWndMain=CreateWindow(szClassName, szTitle, WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX & ~WS_THICKFRAME,0,0,800,735,HWND_DESKTOP,NULL,hInst,NULL);//Родитель, меню, другие параметры
  RECT rc,rcMain;
  HWND hwndDesktop = GetDesktopWindow();  
  GetWindowRect(hwndDesktop, &rc); 
  GetWindowRect(hWndMain, &rcMain);   
  SetWindowPos(hWndMain, HWND_TOP, (rc.right-rc.left-rcMain.right)/2, (rc.bottom-rc.top-rcMain.bottom)/2, 0, 0, SWP_NOSIZE); 
  ShowWindow(hWndMain,SW_SHOWNORMAL);//Вызов функции Windows показа окна 
	
  /*Организуем цикл обнаружения сообщений*/
  while(GetMessage(&Msg,NULL,0,0)) {// Если есть сообщение, передать его нам
    TranslateMessage(&Msg);
	  DispatchMessage(&Msg);}//и вызвать оконную процедуру WndProc

  return 0;//После выхода из цикла вернуться в Windows
}//Конец функции WinMain

LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam){
  switch(msg){
	HANDLE_MSG (hwnd, WM_CREATE, OnCreate);
	HANDLE_MSG (hwnd, WM_COMMAND, OnCommand);
    //HANDLE_MSG (hwnd, WM_DESTROY, OnDestroy);
	//HANDLE_MSG (hwnd, WM_NOTIFY, OnNotify);
    default:  //B случае всех остальных сообщений Windows обработка
      return(DefWindowProc(hwnd,msg,wParam,lParam)) ; //их по умолчанию
  }//Конец оператора switch
}//Конец функции WndProc

bool OnCreate (HWND hwnd, LPCREATESTRUCT){
//-------------------------------------------------------------------------------------
  TCHAR ButExit[]=TEXT(" Exit ");
    
  RECT Rect;
  GetClientRect(hwnd,&Rect);
  

  hButExit=CreateWindow(TEXT("BUTTON"),NULL,WS_CHILD|WS_VISIBLE|SS_CENTER,Rect.right- Rect.left-105,Rect.top+655+iHeightEdit,(int)(1,5*iHeightEdit),iHeightEdit ,hwnd,NULL,hInstance,NULL);
  SendMessage(hButExit,WM_SETTEXT, 0, (LPARAM)(LPCSTR)ButExit);
  hButClear=CreateWindow(TEXT("BUTTON"),NULL,WS_CHILD|WS_VISIBLE|SS_CENTER,Rect.right- Rect.left-235,Rect.top+655+iHeightEdit,(int)(1,5*iHeightEdit),iHeightEdit ,hwnd,NULL,hInstance,NULL);
  SendMessage(hButClear,WM_SETTEXT, 0, (LPARAM)(LPCSTR)TEXT("Clear"));
  hButRun=CreateWindow(TEXT("BUTTON"),NULL,WS_CHILD|WS_VISIBLE|SS_CENTER,Rect.right- Rect.left-600,Rect.top+55+iHeightEdit,(int)(1,5*iHeightEdit),iHeightEdit ,hwnd,NULL,hInstance,NULL);
  SendMessage(hButRun,WM_SETTEXT, 0, (LPARAM)(LPCSTR)TEXT("Пааааехали!"));  
  hListBox= CreateWindow(
	TEXT("LISTBOX"), NULL, WS_CHILD | /*LBS_STANDARD |*/ WS_VSCROLL | LBS_DISABLENOSCROLL | WS_VISIBLE/* & (~LBS_SORT)*/,
	340,30, 455, 550, hwnd, NULL, hInstance, NULL);
  
  HWND hAuthor=CreateWindow(TEXT("STATIC"),NULL,WS_CHILD|WS_VISIBLE|SS_LEFT ,(int)(Rect.left+250),(int)(Rect.top+680),(int)(Rect.right- Rect.left-550),20,hwnd,NULL,hInstance,NULL);
  SendMessage(hAuthor,WM_SETTEXT, 0, (LPARAM)(LPCSTR)TEXT("(c) Косоногова М.А., гр. ИТ-31, 2008"));

  return TRUE;
}

void OnCommand (HWND hwnd, int id, HWND hw, UINT){
//-------------------------------------------------------------------------------------
		if (hw==hButExit) OnClickButExit();
		if (hw==hButClear) OnClickButClear(hWndMain);
		if (hw==hButRun) OnClickButRun(hWndMain);
}


void OnClickButExit()
{
	PostQuitMessage(0);		
}

void OnClickButClear(HWND hwnd)
{
	RECT Rect;
	GetClientRect(hwnd,&Rect);
}

int Puass(double Lamda)
{
	int k = 0;
	double p0 = exp(-Lamda);
	double P = p0;
	
	// Генерируем вещественное число в интервале 0 .. 1
	double ver = (double)rand() / RAND_MAX;
	do {
		ver -= P;
		if(ver >= 0) {
			P = P*Lamda / (k+1);
			k += 1;
		}
	} while(ver >= 0);
	return k;
}

DWORD TrainThread(int *p)
{
	__int64 gTime;
    QueryPerformanceCounter((LARGE_INTEGER *)&gTime);
    srand(gTime);

	wsprintf(buf,L"Train #%d...",*p);
	SendMessage(hListBox,LB_ADDSTRING, 0, (LPARAM)(LPCSTR)buf);

	int finished = 0;
	do {
		// Проверяем состояние семафора
		DWORD dwResult = WaitForSingleObject(hSemaphore, 1000); // !!! ждем 1 секунду
		DWORD time_stopping;
		switch(dwResult) {
	        case WAIT_OBJECT_0:
			// Место есть, остановка
			wsprintf(buf,L"Train #%d is stoping...",*p);
			SendMessage(hListBox,LB_ADDSTRING, 0, (LPARAM)(LPCSTR)buf);
			time_stopping = Puass(200) * 10 + 1000; // Время стоянки
			Sleep(time_stopping);
			ReleaseSemaphore(hSemaphore, 1, NULL); // Освободим семафор
			finished = 1;
			break;
            
		case WAIT_TIMEOUT:
			// Семафор занят, сообщаем об этом, и повторяем попытку ...
			wsprintf(buf, L"Train #%d: no empty places...waiting",*p);
			SendMessage(hListBox,LB_ADDSTRING, 0, (LPARAM)(LPCSTR)buf);            
			break;
		}
	} while(!finished);
	return 0;
}

void OnClickButRun(HWND hwnd)
{
    // генератор случ. чисел
    //srand(time(NULL));
	if(hSemaphore = CreateSemaphore(NULL, maxPlaces, maxPlaces, NULL)) {
		for(int i = 0; i < maxTrains; i++) {
			DWORD timeWait = Puass(200) * 10; // <--- Ну, коэффициенты сама подберешь

			wsprintf(buf, L"Ждем %ld ms перед генерацией следующего потока-поезда", timeWait);
			SendMessage(hListBox, LB_ADDSTRING, 0, (LPARAM)(LPCSTR)buf);

			// Ожидание, но все запущенные ранее потоки уже работают,
			// на них Sleep не распространяется
			Sleep(timeWait); 

			trainID[i] = i+1;
			trainHandles[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)TrainThread,
				&trainID[i], 0, NULL);
		}
    int b = 1;
		do {
			// DWORD r = ; // дождаться всех
			switch(WaitForMultipleObjects(maxTrains, trainHandles, TRUE, 100)) {
				case WAIT_TIMEOUT:
					// Здесь добавить аналог Application->ProcessMessages() чтоб обновить окно;
					MSG lpMsg;
					while (PeekMessage(&lpMsg, NULL, 0, 0, PM_REMOVE)) {
						TranslateMessage(&lpMsg);
						DispatchMessage(&lpMsg);
					}
					break;
				default:
					b = 0;
			}
		} while(b);

		CloseHandle(hSemaphore);

    }
    else SendMessage(hListBox,LB_ADDSTRING, 0, (LPARAM)(LPCSTR)TEXT("Error by creation semaphore"));
}