/////////////////////////////////////////////////
//
//  filename: MainWindow.cpp
//  author:Chafumi Touji
//  date: 2018/04/03 ver1.00
//		  2020/02/06 ver1.01
//
/////////////////////////////////////////////////

#include "StdAfx.h"
#include "Config.h"
#include "MainWindow.h"
#include "DispWindow.h"
#include "CustomButton.h"

CMainWindow::CMainWindow(){

	wmemset(InitDirectory, 0, SIZE_CHAR_MAX);
	::GetCurrentDirectoryW(SIZE_CHAR_MAX, InitDirectory);

	HDC screen = GetDC(0);
	dpiX = (float)GetDeviceCaps(screen, LOGPIXELSX);
	dpiY = (float)GetDeviceCaps(screen, LOGPIXELSY);
	ReleaseDC(0, screen);

	ScaleX = (dpiX / 96.0f);
	ScaleY = (dpiY / 96.0f);

	DisplayWidth = ::GetSystemMetrics(SM_CXSCREEN);
	DisplayHeight = ::GetSystemMetrics(SM_CYSCREEN);
	FrameEdgeX = 8;
	FrameEdgeY = 8;

	TransparentR = COLOR_TRANSPARENT_R;
	TransparentG = COLOR_TRANSPARENT_G;
	TransparentB = COLOR_TRANSPARENT_B;

	CRect	rectDesktop;
	::SystemParametersInfo(SPI_GETWORKAREA, 0, &rectDesktop, 0);

	Width = (int)((double)DisplayWidth / 1.5);
	Height = (int)((double)DisplayHeight / 1.5);
	TitleBarHeight = (int)((double)DisplayHeight / 30.0);
	TaskBarHeight = DisplayHeight - rectDesktop.bottom;

	BKColorA = 255;
	BKColorR = 180;
	BKColorG = 150;
	BKColorB = 150;
	BarColorA = 255;
	BarColorR = 100;
	BarColorG = 70;
	BarColorB = 70;

	PosX = (DisplayWidth - Width) / 2;
	PosY = (DisplayHeight - Height) / 2;

	LButtonDown = false;
	GetCaption = false;
	IsMaximized = false;
	DownPoint = CPoint(0, 0);

	Config = new CConfig();
	Config->LoadConfigFile(L"config.ini");
	SetParam(Config);

	DispWindow = NULL;

	::CoInitialize(NULL);
}

CMainWindow::~CMainWindow(){

	delete Config;
	delete DispWindow;

	::CoUninitialize();
}

/////////////////////////////////////////////////////////////////////////////

bool CMainWindow::SetParam(CConfig *config){

	BKColorA = config->BKColorA;
	BKColorR = config->BKColorR;
	BKColorG = config->BKColorG;
	BKColorB = config->BKColorB;
	BarColorA = config->BarColorA;
	BarColorR = config->BarColorR;
	BarColorG = config->BarColorG;
	BarColorB = config->BarColorB;

	return true;
}

bool CMainWindow::CreateWnd(){


	WNDCLASSEX wcx;
	memset(&wcx, 0, sizeof(WNDCLASSEX));
	wcx.style = CS_HREDRAW | CS_VREDRAW;
	wcx.cbSize = sizeof(WNDCLASSEX);
	wcx.hInstance = NULL;
	wcx.hIcon = NULL;
	wcx.lpszMenuName = NULL;
	wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
	wcx.lpfnWndProc = &CMainWindow::WindowProc;
	wcx.lpszClassName = L"CLASS_MAINWINDOW";
	RegisterClassEx(&wcx);

	m_hWnd = CreateWindowEx(WS_EX_LEFT, L"CLASS_MAINWINDOW", _T("ModelViewer"), WS_POPUP | WS_CLIPCHILDREN, PosX, PosY, Width, Height, GetDesktopWindow(), NULL, NULL, NULL);
	::SetWindowLongPtr(m_hWnd, GWLP_USERDATA, (UINT_PTR) this);
	::SetWindowLong(m_hWnd, GWL_EXSTYLE, WS_EX_LAYERED);
	;; SetLayeredWindowAttributes(m_hWnd, RGB(TransparentR, TransparentG, TransparentB), 0, LWA_COLORKEY);

	BitmapWidth = DisplayWidth;
	BitmapHeight = DisplayHeight;

	BITMAPINFO  bmi = { 0 };
	bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	bmi.bmiHeader.biWidth = BitmapWidth;
	bmi.bmiHeader.biHeight = BitmapHeight;
	bmi.bmiHeader.biPlanes = 1;
	bmi.bmiHeader.biBitCount = 32;

	MemBMP = CreateDIBSection(0, &bmi, DIB_RGB_COLORS, (void **)&AlphaBMP, 0, 0);
	::DeleteDC(MemDC);

	HDC hdc = ::GetDC(m_hWnd);
	MemDC = CreateCompatibleDC(hdc);
	::SelectObject(MemDC, MemBMP);
	DeleteDC(hdc);

	int button_size = (int)((double)TitleBarHeight * 0.8f);
	int x = Width - button_size - (int)((double)TitleBarHeight * 0.5f);
	int y = (int)((double)TitleBarHeight * 0.1f);
	ButtonClose = new CButtonClose();
	ButtonClose->CreateWnd(x, y, button_size, button_size, m_hWnd);
	ButtonClose->SetImage(L"./pict/ButtonClose.png", L"./pict/ButtonCloseDown.png");

	x -= button_size + (int)((double)TitleBarHeight * 0.3f);
	ButtonMaximize = new CButtonMaximize();
	ButtonMaximize->CreateWnd(x, y, button_size, button_size, m_hWnd);
	ButtonMaximize->SetImage(L"./pict/ButtonSize.png", L"./pict/ButtonSizeDown.png");

	x -= button_size + (int)((double)TitleBarHeight * 0.3f);
	ButtonMinimize = new CButtonMinimize();
	ButtonMinimize->CreateWnd(x, y, button_size, button_size, m_hWnd);
	ButtonMinimize->SetImage(L"./pict/ButtonMin.png", L"./pict/ButtonMinDown.png");

	::ShowWindow(ButtonClose->m_hWnd, SW_SHOW);
	::ShowWindow(ButtonMinimize->m_hWnd, SW_SHOW);
	::ShowWindow(ButtonMaximize->m_hWnd, SW_SHOW);

	::ShowWindow(m_hWnd, SW_SHOW);

	::InvalidateRect(m_hWnd, NULL, false);
	::UpdateWindow(m_hWnd);

	DispWindow = new CDispWindow();
	DispWindow->CreateWnd(m_hWnd, FrameEdgeX / 2, TitleBarHeight, Width - FrameEdgeX, Height - TitleBarHeight - FrameEdgeY / 2);

	return true;
}

void CALLBACK  CMainWindow::TimeUpdateCallback(UINT timer_id, UINT msg, LPTIMECALLBACK user, DWORD_PTR data1, DWORD_PTR data2){

	CMainWindow *main_wnd = (CMainWindow *)user;

	::InvalidateRect(main_wnd->m_hWnd, NULL, false);
	::UpdateWindow(main_wnd->m_hWnd);
}

LRESULT CMainWindow::WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){

	CMainWindow *main_wnd = (CMainWindow *) ::GetWindowLongPtr(hwnd, GWLP_USERDATA);
	if (main_wnd != NULL)
		main_wnd->MainWindowProc(hwnd, message, wParam, lParam);

	return DefWindowProc(hwnd, message, wParam, lParam);
}

LRESULT CMainWindow::MainWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){

	int width = 0;
	int height = 0;
	int x = 0;
	int y = 0;
	MOUSEHOOKSTRUCT *ms = NULL;

	switch (message){
	case WM_PAINT:
		OnPaint();
		break;
	case WM_SIZE:
		width = GET_X_LPARAM(lParam);
		height = GET_Y_LPARAM(lParam);
		OnSize((UINT)wParam, width, height);
		break;
	case WM_LBUTTONDOWN:
		x = GET_X_LPARAM(lParam);
		y = GET_Y_LPARAM(lParam);
		OnLButtonDown((UINT)wParam, CPoint(x, y));
		break;
	case WM_LBUTTONUP:
		x = GET_X_LPARAM(lParam);
		y = GET_Y_LPARAM(lParam);
		OnLButtonUp((UINT)wParam, CPoint(x, y));
		break;
	case WM_MOUSEMOVE:
		x = GET_X_LPARAM(lParam);
		y = GET_Y_LPARAM(lParam);
		OnMouseMove((UINT)wParam, CPoint(x, y));
		break;
	default:
		break;
	}

	return 0;
}

void CMainWindow::OnSize(UINT nType, int cx, int cy){

	if (nType == SIZE_MAXIMIZED){

		IsMaximized = true;
		if (DispWindow->IsTransparent == true){
			::SetWindowPos(DispWindow->m_hWnd, NULL, 0, 0, DisplayWidth, DisplayHeight, SWP_NOZORDER);
			::SetWindowPos(ButtonClose->m_hWnd, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_HIDEWINDOW);
			::SetWindowPos(ButtonMaximize->m_hWnd, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_HIDEWINDOW);
			::SetWindowPos(ButtonMinimize->m_hWnd, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_HIDEWINDOW);
			::SetWindowPos(m_hWnd, HWND_TOPMOST, 0, 0, DisplayWidth, DisplayHeight, SWP_SHOWWINDOW);
		}
		else{
			DispWindow->Width = DisplayWidth;
			::SetWindowPos(DispWindow->m_hWnd, NULL, FrameEdgeX / 2, TitleBarHeight, DisplayWidth - FrameEdgeX, DisplayHeight - TitleBarHeight - FrameEdgeY / 2, SWP_NOZORDER);

			int button_size = (int)((double)TitleBarHeight * 0.8f);
			int x = DisplayWidth - button_size - (int)((double)TitleBarHeight * 0.5f);
			int y = (int)((double)TitleBarHeight * 0.1f);
			::SetWindowPos(ButtonClose->m_hWnd, NULL, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW);
			x -= button_size + (int)((double)TitleBarHeight * 0.3f);
			::SetWindowPos(ButtonMaximize->m_hWnd, NULL, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW);
			x -= button_size + (int)((double)TitleBarHeight * 0.3f);
			::SetWindowPos(ButtonMinimize->m_hWnd, NULL, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW);
			::SetWindowPos(m_hWnd, HWND_NOTOPMOST, 0, 0, DisplayWidth, DisplayHeight, SWP_SHOWWINDOW);
		}
	}
	else if (nType == SIZE_RESTORED){

		IsMaximized = false;
		::SetWindowPos(m_hWnd, HWND_NOTOPMOST, PosX, PosY, Width, Height, SWP_SHOWWINDOW);
		DispWindow->Width = Width - FrameEdgeX;
		::SetWindowPos(DispWindow->m_hWnd, NULL, FrameEdgeX / 2, TitleBarHeight, Width - FrameEdgeX, Height - TitleBarHeight - FrameEdgeY / 2, SWP_NOZORDER);

		int button_size = (int)((double)TitleBarHeight * 0.8f);
		int x = Width - button_size - (int)((double)TitleBarHeight * 0.5f);
		int y = (int)((double)TitleBarHeight * 0.1f);
		::SetWindowPos(ButtonClose->m_hWnd, NULL, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW);
		x -= button_size + (int)((double)TitleBarHeight * 0.3f);
		::SetWindowPos(ButtonMaximize->m_hWnd, NULL, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW);
		x -= button_size + (int)((double)TitleBarHeight * 0.3f);
		::SetWindowPos(ButtonMinimize->m_hWnd, NULL, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW);
	}

	::InvalidateRect(m_hWnd, NULL, false);
	::UpdateWindow(m_hWnd);
}

void CMainWindow::OnPaint(){

	static bool Rock = false;

	PAINTSTRUCT ps;
	HDC hdc = ::BeginPaint(m_hWnd, &ps);
	OnDraw(hdc);
	::EndPaint(m_hWnd, &ps);
}

bool CMainWindow::OnDraw(HDC hdc){

	HBITMAP OldBmp = (HBITMAP)::SelectObject(MemDC, MemBMP);

	int width = Width;
	int height = Height;
	if (IsMaximized == true){
		width = DisplayWidth;
		height = DisplayHeight;
	}

	Gdiplus::Graphics *gfc = new Gdiplus::Graphics(MemDC);
	gfc->Clear(Gdiplus::Color(255, BKColorR, BKColorG, BKColorB));

	Gdiplus::SolidBrush *brush1 = new Gdiplus::SolidBrush(Gdiplus::Color(255, BarColorR, BarColorG, BarColorB));
	gfc->FillRectangle(brush1, 0, 0, width, TitleBarHeight);
	delete brush1;

	Gdiplus::Pen *pen1 = new Gdiplus::Pen(Gdiplus::Color(255, BarColorR, BarColorG, BarColorB), 8);
	gfc->DrawLine(pen1, 0, 0, Width, 0);
	gfc->DrawLine(pen1, width, 0, width, height);
	gfc->DrawLine(pen1, width, height, 0, height);
	gfc->DrawLine(pen1, 0, height, 0, 0);
	delete pen1;

	gfc->SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAlias);
	Gdiplus::Font *font = new Gdiplus::Font(L"メイリオ", (REAL)((double)TitleBarHeight * 0.5f / ScaleX));

	size_t size;
	wchar_t wstr[60];
	Gdiplus::SolidBrush *brush3 = new Gdiplus::SolidBrush(Gdiplus::Color(BKColorA, BKColorR + 50, BKColorG + 50, BKColorB + 50));
	char str[SIZE_CHAR_MAX];
	memset(str, 0, SIZE_CHAR_MAX);

	//タイトル文字列設定

	strcpy_s(str, SIZE_CHAR_MAX, APP_NAME);
	if (DispWindow != NULL){
		if (DispWindow->Status == STATUS_LOADING)
			strcat_s(str, SIZE_CHAR_MAX, " [LOADING...]");
		else if (DispWindow->Status == STATUS_RUN){
			char data[SIZE_CHAR_MAX];
			memset(data, 0, SIZE_CHAR_MAX);
			sprintf_s(data, " [FPS: %.2f f/s]", DispWindow->FramePerSec);
			strcat_s(str, SIZE_CHAR_MAX, data);
		}
	}


	Gdiplus::StringFormat *format = new Gdiplus::StringFormat(StringFormatFlagsNoWrap);
	wmemset(wstr, 0, 60);
	mbstowcs_s(&size, wstr, str, strlen(str));
	gfc->DrawString(wstr, -1, font, RectF((double)width / 50.0, (double)TitleBarHeight * 0.1f, (REAL)width, (REAL)TitleBarHeight), format, brush3);

	::BitBlt(hdc, 0, 0, width, height, MemDC, 0, 0, SRCCOPY);

	delete brush3;
	delete font;
	delete format;
	delete gfc;

	return true;
}

bool CMainWindow::DrawRoundRect(Gdiplus::Graphics *gfc, Gdiplus::Pen *pen, int x, int y, int w, int h, int r){

	if (r % 2 != 0)
		r++;

	gfc->DrawArc(pen, x, y, r, r, 180, 90);
	gfc->DrawArc(pen, x + w - r, y, r, r, 270, 90);
	gfc->DrawArc(pen, x, y + h - r, r, r, 90, 90);
	gfc->DrawArc(pen, x + w - r, y + h - r, r, r, 0, 90);
	gfc->DrawLine(pen, x + r / 2, y, x + w + 1 - r / 2, y);
	gfc->DrawLine(pen, x, y + r / 2, x, y + h + 1 - r / 2);
	gfc->DrawLine(pen, x + w, y + r / 2, x + w + 1, y + h + 1 - r / 2);
	gfc->DrawLine(pen, x + r / 2, y + h, x + w + 1 - r / 2, y + h + 1);

	return true;
}

bool CMainWindow::FillRoundRect(Gdiplus::Graphics *gfc, Gdiplus::Brush *brush, int x, int y, int w, int h, int r){

	if (r % 2 != 0)
		r++;

	gfc->FillPie(brush, x, y, r, r, 180, 90);
	gfc->FillPie(brush, x + w - r, y, r, r, 270, 90);
	gfc->FillPie(brush, x, y + h - r, r, r, 90, 90);
	gfc->FillPie(brush, x + w - r, y + h - r, r, r, 0, 90);
	gfc->FillRectangle(brush, x + r / 2, y, w - r, r / 2);
	gfc->FillRectangle(brush, x, y + r / 2, r / 2, h - r);
	gfc->FillRectangle(brush, x + r / 2, y + h - r / 2, w - r, r / 2);
	gfc->FillRectangle(brush, x + w - r / 2, y + r / 2, r / 2, h - r);
	gfc->FillRectangle(brush, x + r / 2, y + r / 2, w - r, h - r);

	return true;
}

void CMainWindow::OnLButtonDown(UINT nFlag, CPoint point){

	LButtonDown = true;

	if (point.y < TitleBarHeight)
		GetCaption = true;
	else
		GetCaption = false;

	int pos_x = point.x;
	int pos_y = point.y + FrameEdgeY * 2 + ::GetSystemMetrics(SM_CYCAPTION);

	/////////////////////////////////////////////////////////

	::ClientToScreen(m_hWnd, &point);
	DownPoint = point;
	LButtonDown = true;
	::SetCapture(m_hWnd);
	::InvalidateRect(m_hWnd, NULL, false);
	::UpdateWindow(m_hWnd);
}

void CMainWindow::OnLButtonUp(UINT nFlag, CPoint point){

	::ReleaseCapture();
	LButtonDown = false;
	GetCaption = false;

	::InvalidateRect(m_hWnd, NULL, false);
	::UpdateWindow(m_hWnd);
}

void CMainWindow::OnMouseMove(UINT nFlag, CPoint point){

	if (LButtonDown == true && GetCaption == true && IsMaximized == false){
		::ClientToScreen(m_hWnd, &point);
		PosX += point.x - DownPoint.x;
		PosY += point.y - DownPoint.y;
		DownPoint = point;
		::SetWindowPos(m_hWnd, HWND_TOP, PosX, PosY, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
		::InvalidateRect(m_hWnd, NULL, false);
		::UpdateWindow(m_hWnd);
	}
}
