// vizBDD.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include <commdlg.h>
#include "vizBDD.h"
#include <iostream>
#include "wingraph.h"
#include "Commctrl.h"
#include "cudd/include/cudd.h" 
#include "cudd/include/util.h" 

using namespace std;
#define MAX_LOADSTRING 100

#pragma warning(disable : 4996)

// Global Variables:
HINSTANCE hInst;								// current instance
TCHAR szTitle[MAX_LOADSTRING];					// The title bar text
TCHAR szWindowClass[MAX_LOADSTRING];			// the main window class name

// Forward declarations of functions included in this code module:
ATOM				MyRegisterClass(HINSTANCE hInstance);
BOOL				InitInstance(HINSTANCE, int);
LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK	About(HWND, UINT, WPARAM, LPARAM);

#define IDC_TOOLBAR 999
int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);

 	// TODO: Place code here.
	MSG msg;
	HACCEL hAccelTable;

	// Initialize global strings
	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
	LoadString(hInstance, IDC_VIZBDD, szWindowClass, MAX_LOADSTRING);
	MyRegisterClass(hInstance);

	// Perform application initialization:
	if (!InitInstance (hInstance, nCmdShow))
	{
		return FALSE;
	}

	hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_VIZBDD));

	// Main message loop:
	while (GetMessage(&msg, NULL, 0, 0))
	{
		if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}

	return (int) msg.wParam;
}



//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
//  COMMENTS:
//
//    This function and its usage are only necessary if you want this code
//    to be compatible with Win32 systems prior to the 'RegisterClassEx'
//    function that was added to Windows 95. It is important to call this function
//    so that the application will get 'well formed' small icons associated
//    with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX);

	wcex.style			= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
	wcex.lpfnWndProc	= WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_VIZBDD));
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(GetStockObject(WHITE_BRUSH));
	wcex.lpszMenuName	= MAKEINTRESOURCE(IDC_VIZBDD);
	wcex.lpszClassName	= szWindowClass;
	wcex.hIconSm		= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

	return RegisterClassEx(&wcex);
}

//
//   FUNCTION: InitInstance(HINSTANCE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//

// Toolbar buttons used to create the first 4 buttons.
TBBUTTON tbButtonsCreate [ ] = {
	{0, ID_FILE_OPEN, TBSTATE_ENABLED, BTNS_BUTTON, 0L, 0},
	{0, 0, TBSTATE_ENABLED, BTNS_SEP, 0L, 0},
	{1, ID_FILE_SAVE, TBSTATE_ENABLED, BTNS_BUTTON, 0L, 0},
	{0, 0, TBSTATE_ENABLED, BTNS_SEP, 0L, 0},
	{5, ID_CONTROL_MOVE, TBSTATE_ENABLED, BTNS_BUTTON, 0L, 0},
	{3, ID_CONTROL_ZOOM, TBSTATE_ENABLED, BTNS_BUTTON, 0L, 0}
};

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

   hInst = hInstance; // Store instance handle in our global variable

   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
   int err=GetLastError();
   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}


LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	
	static WinGraph winGraph(hWnd);
	
	static OPENFILENAME ofn, sfn;		// instance s vlastnostmi dialogu pro otevreni souboru
	static TCHAR szFileOpen[260], szFileSave[260];		// buffer pro nazev souboru
	static char szFileName[50];
	static TCHAR szTitleName[50];
	static HMENU hMenu;
	static bool moveMode=true, clicked=false;
	static POINT click;
	static HWND hWndToolbar;
	static HBRUSH btnBrush;
	static int loadMethod=2;
	static HCURSOR cur;
	static int iterChecked=ID_ITERATIONCOUNT_3;
	static int iterCount=3;
	int wmId, wmEvent;
	RECT rect;

	switch (message){
	case WM_CREATE:
		btnBrush= CreateSolidBrush(RGB(200,0,0));
		hWndToolbar = CreateToolbarEx (hWnd, WS_CHILD | WS_BORDER | WS_VISIBLE | TBSTYLE_TOOLTIPS, IDC_TOOLBAR, 2, 
		hInst, IDB_BITMAP3, tbButtonsCreate, sizeof(tbButtonsCreate) / sizeof(TBBUTTON), 0, 0, 0, 0, sizeof (TBBUTTON));
		SendMessage(hWndToolbar, TB_PRESSBUTTON, ID_CONTROL_MOVE,1);
		//inicializace promenych pro dialog otevreni souboru
		click.x=0;
		click.y=0;
		ZeroMemory(&ofn, sizeof(ofn));
		ofn.lStructSize = sizeof(ofn);
		ofn.hwndOwner = hWnd;
		ofn.lpstrFile = szFileOpen;
		ofn.lpstrFile[0] = '\0';
		ofn.nMaxFile = sizeof(szFileOpen);
		ofn.lpstrFilter = TEXT("Pla\0*.pla\0All\0*.*\0");
		ofn.nFilterIndex = 1;
		ofn.lpstrFileTitle = NULL;
		ofn.nMaxFileTitle = 0;
		ofn.lpstrInitialDir = NULL;
		ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
		//inicializace promenych pro dialog ulozeni souboru
		ZeroMemory(&sfn, sizeof(sfn));
		sfn.lStructSize = sizeof(sfn);
		sfn.hwndOwner = hWnd;
		sfn.lpstrFile = szFileSave;
		sfn.lpstrFile[0] = '\0';
		sfn.nMaxFile = sizeof(szFileSave);
		sfn.lpstrFilter = TEXT("PS\0*.ps\0All\0*.*\0");
		sfn.nFilterIndex = 1;
		sfn.lpstrFileTitle = NULL;
		sfn.nMaxFileTitle = 0;
		sfn.lpstrInitialDir = NULL;
		sfn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;				   
		break;
	case WM_COMMAND:
		wmId    = LOWORD(wParam);
		wmEvent = HIWORD(wParam);
		// Parse the menu selections:
		if(winGraph.IsWorking()) return 0;
		switch (wmId){
		//dialog otevreni souboru
		case ID_FILE_OPEN:
			if (GetOpenFileName(&ofn)){
				if(!winGraph.LoadPLA(szFileOpen, loadMethod, iterCount)){
					MessageBox(hWnd, TEXT("File couldn't be open"), NULL, MB_OK | MB_ICONERROR);
				}
				GetClientRect(hWnd, &rect);
				SendMessage(hWnd, WM_SIZE, SIZE_RESTORED, MAKELPARAM(rect.right, rect.bottom));
				InvalidateRect(hWnd, NULL, true);
			}
			break;
		case ID_FILE_SAVE:
			// export do formatu PS
			if(GetSaveFileName(&sfn)){
				winGraph.SavePs(szFileSave);
			}
			break;
		case ID_CONTROL_MOVE:
			hMenu=GetMenu(hWnd);
			CheckMenuItem(hMenu, ID_CONTROL_MOVE, MF_CHECKED);
			CheckMenuItem(hMenu, ID_CONTROL_ZOOM, MF_UNCHECKED);
			SendMessage(hWndToolbar, TB_PRESSBUTTON, ID_CONTROL_ZOOM,0);
			SendMessage(hWndToolbar, TB_PRESSBUTTON, ID_CONTROL_MOVE,1);
			moveMode=true;
			break;			 
		case ID_CONTROL_ZOOM:
			hMenu=GetMenu(hWnd);
			CheckMenuItem(hMenu, ID_CONTROL_MOVE, MF_UNCHECKED);
			CheckMenuItem(hMenu, ID_CONTROL_ZOOM, MF_CHECKED);	
			SendMessage(hWndToolbar, TB_PRESSBUTTON, ID_CONTROL_MOVE,0);
			SendMessage(hWndToolbar, TB_PRESSBUTTON, ID_CONTROL_ZOOM,1);
			
			moveMode=false;
			break;						 
		case ID_CONTROL_NONE:
			hMenu=GetMenu(hWnd);
			CheckMenuItem(hMenu, ID_CONTROL_GREED, MF_UNCHECKED);
			CheckMenuItem(hMenu, ID_CONTROL_BARYCENTERS, MF_UNCHECKED);
			CheckMenuItem(hMenu, ID_CONTROL_NONE, MF_CHECKED);
			loadMethod=0;
		break;
		case ID_CONTROL_GREED:
			hMenu=GetMenu(hWnd);
			CheckMenuItem(hMenu, ID_CONTROL_BARYCENTERS, MF_UNCHECKED);
			CheckMenuItem(hMenu, ID_CONTROL_NONE, MF_UNCHECKED);
			CheckMenuItem(hMenu, ID_CONTROL_GREED, MF_CHECKED);
			loadMethod=1;
		break;
		case ID_CONTROL_BARYCENTERS:
			hMenu=GetMenu(hWnd);
			CheckMenuItem(hMenu, ID_CONTROL_GREED, MF_UNCHECKED);
			CheckMenuItem(hMenu, ID_CONTROL_NONE, MF_UNCHECKED);
			CheckMenuItem(hMenu, ID_CONTROL_BARYCENTERS, MF_CHECKED);
			loadMethod=2;
		break;
		case ID_ITERATIONCOUNT_1:
		case ID_ITERATIONCOUNT_2:
		case ID_ITERATIONCOUNT_3:
		case ID_ITERATIONCOUNT_5:
		case ID_ITERATIONCOUNT_10:
		case ID_ITERATIONCOUNT_20:
			hMenu=GetMenu(hWnd);
			CheckMenuItem(hMenu, iterChecked, MF_UNCHECKED);
			iterChecked=wmId;
			iterCount=iterChecked-ID_ITERATIONCOUNT_1+1;
			CheckMenuItem(hMenu, iterChecked, MF_CHECKED);
		break;
		case IDM_ABOUT:
			DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
			break;
		case ID_HELP_SHOWLEGEND:
			CreateDialog(hInst, MAKEINTRESOURCE(IDD_LEGEND), hWnd, About);
			break;
		case IDM_EXIT:
			DestroyWindow(hWnd);
			break;		
		default: 
			return DefWindowProc(hWnd, message, wParam, lParam);
		}
		break;
	case WM_PAINT:
		winGraph.Draw();
		return DefWindowProc(hWnd, message, wParam, lParam);	
	case WM_SIZE:
		SendMessage(hWndToolbar, WM_SIZE, 29, LOWORD(lParam));
		winGraph.Resize((int)wParam);
		break;
	//ovladani horizontalniho posuvniku
	case WM_HSCROLL:
		winGraph.Scroll(SB_HORZ, LOWORD (wParam));
		break;
	//ovladani vertikanliho posuvniku
	case WM_VSCROLL:
		winGraph.Scroll(SB_VERT, LOWORD (wParam));
		break;	
	case WM_LBUTTONDOWN:
		clicked=true;
		click.x=LOWORD(lParam);
		click.y=HIWORD(lParam);
		break;
	case WM_LBUTTONUP:
		clicked=false;
		break;
	case WM_MOUSEMOVE:
		if(winGraph.IsWorking()) return 0;
		if(clicked && MK_LBUTTON == wParam && !moveMode){
			cur = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR2));
			SetCursor(cur);
			winGraph.Zoom((click.y-HIWORD(lParam)));
		}
		//posuv tazenim mysi
		if(clicked && MK_LBUTTON == wParam && moveMode){
			static int moveX=0, moveY=0;
			moveX+=LOWORD(lParam)-click.x;
			moveY+=HIWORD(lParam)-click.y;
			cur = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR1));
			SetCursor(cur);
			if(moveX>10 || moveX<-10){
				winGraph.Scroll(SB_HORZ, (LOWORD(lParam)-click.x>0)?SB_LINELEFT:SB_LINERIGHT);
				moveX=moveX%5;
			}
			if(moveY>10 || moveY<-10){
				winGraph.Scroll(SB_VERT, (HIWORD(lParam)-click.y>0)?SB_LINEUP:SB_LINEDOWN);
				moveY=moveY%5;
			}
		}
		click.x=LOWORD(lParam);
		click.y=HIWORD(lParam);	
		break;						
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	UNREFERENCED_PARAMETER(lParam);
	switch (message)
	{
	case WM_INITDIALOG:
		return (INT_PTR)TRUE;

	case WM_COMMAND:
		if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
		{
			EndDialog(hDlg, LOWORD(wParam));
			return (INT_PTR)TRUE;
		}
		break;
	}
	return (INT_PTR)FALSE;
}


