#include "stdafx.h"
#include <process.h>
#include <wchar.h>//by Kobarin
#include "PowerControlWindow.h"

using namespace std;
#ifdef _DEBUG
//by Kobarin
//隠しウィンドウを表示、クリックしたらスリープモードに入るときのメッセージをポスト
//スリープモードに入る時と似た状況をエミュレートしてテストする用
#define SUSPEND_TEST
#endif

namespace GuruGuruSmf { namespace Core {
	
    unsigned int WINAPI thread_entry(void* p_userdata)
    {
        PowerControlWindow* p_win = (PowerControlWindow*)p_userdata;
        p_win->Create();
        p_win->MessageLoop();
		return 0;
    }
	LRESULT WINAPI WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

	// コンストラクタ
	PowerControlWindow::PowerControlWindow(ICallBackPowerControlWindow* obj)
	{
        _class_name[0] = 0;//by Kobarin
        _callBackObject = obj;
        _closing = false;
        

        _hWnd = NULL;
        _hCreated = CreateEvent(NULL, FALSE, FALSE, NULL);
        _hThread = (HANDLE)_beginthreadex(NULL, 0, thread_entry, this, 0, NULL);
	}
	
	// デストラクタ
	PowerControlWindow::~PowerControlWindow()
	{
        Close();	// あらかじめ呼ばれますが念のため

        // スレッドが終わるまで待つ
        WaitForSingleObject(_hThread, INFINITE);
        CloseHandle(_hCreated);
        CloseHandle(_hThread);
	}

    // Closeメッセージを送る
    void PowerControlWindow::Close()
    {
        if (_closing) return;
        _closing = true;	// メッセージを送るのは一度だけ

        // 作成中の可能性があるので待つ
        WaitForCreated();
        SendMessage(_hWnd, WM_CLOSE, NULL, NULL);

    }


    // 作成完了を待つ
    void PowerControlWindow::WaitForCreated()
    {
        WaitForSingleObject(_hCreated, INFINITE);
    }

	const wchar_t *g_AppName  = L"GuruGuruSMFHidden";
    void PowerControlWindow::Create()
    {
        //by Kobarin
        //複数インスタンス対応の為、クラス名をインスタンスごとに異なるものにする
        _snwprintf_s(_class_name, _TRUNCATE, L"%s-%08x-%08x", g_AppName, GetCurrentThreadId(), GetTickCount());
        //
        WNDCLASSEX wcex;
        wcex.cbSize         = sizeof(WNDCLASSEX);
        wcex.style          = CS_HREDRAW | CS_VREDRAW;
        wcex.lpfnWndProc    = &WindowProc;
        wcex.cbClsExtra     = 0;
        wcex.cbWndExtra     = 0;
        wcex.hInstance      = GetModuleHandle(NULL);
        wcex.hIcon          = LoadIcon(NULL, IDI_APPLICATION);
        wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
        wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
        wcex.lpszMenuName   = NULL;
        //wcex.lpszClassName  = g_AppName;
        wcex.lpszClassName  = _class_name;//by Kobarin

        wcex.hIconSm        = LoadIcon(NULL, IDI_APPLICATION);

        RegisterClassEx(&wcex);

        _hWnd = CreateWindow(
			//g_AppName, g_AppName, WS_OVERLAPPEDWINDOW,
            _class_name, _class_name, WS_OVERLAPPEDWINDOW,
            //CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
            0, 0, 300, 300,
            NULL, NULL, GetModuleHandle(NULL), NULL
		);
        //
        SetWindowLongPtr(_hWnd, GWLP_USERDATA, (LONG_PTR)_callBackObject);
        #ifdef SUSPEND_TEST
        ShowWindow(_hWnd, SW_SHOWDEFAULT);
        #endif
        UpdateWindow(_hWnd);
    }

    void PowerControlWindow::MessageLoop()
    {
        MSG msg = {0};

        SetEvent(_hCreated);	// 作成完了を通知
        while (GetMessage(&msg, NULL, 0, 0))
        {
            if(msg.message == WM_QUIT)
            {
                break;
            }
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        //UnregisterClass(g_AppName, GetModuleHandle(NULL));
        UnregisterClass(_class_name, GetModuleHandle(NULL));//by Kobarin
    }
	
    LRESULT WINAPI WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        ICallBackPowerControlWindow* obj;
        switch(uMsg)
        {
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
#ifdef SUSPEND_TEST
        case WM_LBUTTONDOWN:{
            PostMessage(hWnd, WM_POWERBROADCAST, PBT_APMSUSPEND, 0);
            break;
        }
#endif
        case WM_POWERBROADCAST:
			switch(wParam)
			{
			case PBT_APMSUSPEND:{
                obj = (ICallBackPowerControlWindow*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
                if (obj) obj->CallBackSuspend();
                break;
            }
			case PBT_APMRESUMESUSPEND:
				break;
			}
#ifdef SUSPEND_TEST
            return TRUE;//クリック時にポストされたものだと wParam と lParam が意味をなさないので念の為 DefWindowProc が呼ばれないようにする
#endif
            break;
        
        }
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
}}
