
#define _CRT_SECURE_NO_DEPRECATE

#include<windows.h>
#include<stdlib.h>
#include<time.h>


#include"NARReader.h"
#include"oui.h"
#include"PointerList.h"

#include<gdiplus.h>
#pragma comment(lib,"gdiplus.lib")

#define NEXT_SLIDE 9001
#define DONT_CHANGE_SLIDE 9002
#define ALWAYS_ONTOP 9003
#define DISABLE_DOCK 9004
#define DISABLE_DRAG 9005
#define ABOUT_XSLIDE 9006
#define EXIT_XSLIDE 9007

#define TIMER_ID 1001

#define MAX_IMAGE_SIZE 150
int windowWidth=MAX_IMAGE_SIZE;
int windowHeight=MAX_IMAGE_SIZE;

Gdiplus::Bitmap *image;
HMENU popupMenu;
ULONG_PTR m_gdiplusToken=0;

bool disableTimer,AlwaysOnTop,DisableDock,DisableDrag;
int currentImageNumber;
//PointerList* fileList;


HGLOBAL memImage;
NARReader* narReader;

void set_config_int(const char *name, int val) {
  char str[40];
  wsprintfA(str, "%d", val);
  WritePrivateProfileStringA("XSlide", name, str,"XSlideConfig.xnf");
  
}

int get_config_int(const char *name, int def=0) {
  char tmp[40], tmp2[40];
  wsprintfA(tmp, "%d", def);
  wsprintfA(tmp2, "%d", def);
  GetPrivateProfileStringA("XSlide", name, tmp2, tmp, sizeof tmp,"XSlideConfig.xnf");
  return atoi(tmp);
}

int GetRandomImageNumber()
{
	return rand()%narReader->GetFileCount();
	//return rand()%fileList->GetSize();
}

void OnPaint(HWND hwnd)
{
	HDC hdc,hMemDCForWindow;
	PAINTSTRUCT ps;
	hdc=BeginPaint(hwnd,&ps);

	HBRUSH  hFrameBrush=CreateSolidBrush(PALETTERGB(0,0,0)); // black
	hMemDCForWindow=CreateCompatibleDC(hdc);
	HBITMAP bmp = CreateCompatibleBitmap(hdc, windowWidth, windowHeight);// double buffering!
	HBITMAP oldbmp = (HBITMAP)SelectObject(hMemDCForWindow, bmp);

	//draw image here...
	Gdiplus::Graphics* g=Gdiplus::Graphics::FromHDC(hMemDCForWindow);
	g->DrawImage(image,0,0,windowWidth,windowHeight);
	delete g;

	RECT rect={0,0,windowWidth,windowHeight};
	FrameRect(hMemDCForWindow,&rect,hFrameBrush);

	BitBlt(hdc, 0, 0, windowWidth, windowHeight, hMemDCForWindow, 0, 0, SRCCOPY);

	EndPaint(hwnd,&ps);
	
	SelectObject(hMemDCForWindow, oldbmp);
	
	DeleteObject(bmp);
	DeleteObject(hFrameBrush);
	DeleteDC(hMemDCForWindow);

}

void OnNextSlide(HWND hwnd)
{
	delete image;

	int newImageNumber=GetRandomImageNumber();

	if(narReader->GetFileCount()>1)
	{
		while(currentImageNumber==newImageNumber)
		{
			newImageNumber=GetRandomImageNumber();
		}
	}

	currentImageNumber=newImageNumber;

	GlobalFree(memImage);
	memImage=GlobalAlloc(GMEM_FIXED,narReader->ReadFileSize(currentImageNumber));
	CopyMemory(memImage,narReader->ReadFile(currentImageNumber),narReader->ReadFileSize(currentImageNumber));

	IStream* stream = NULL;
	CreateStreamOnHGlobal(memImage, FALSE,&stream);
	image=Gdiplus::Bitmap::FromStream(stream);	

	//image=Gdiplus::Bitmap::FromFile((wchar_t*)fileList->GetPointer(currentImageNumber));

	if(image->GetWidth()>image->GetHeight()) // resize window size!
	{
		windowHeight=(int)(((float)MAX_IMAGE_SIZE/image->GetWidth())*image->GetHeight());
		windowWidth=MAX_IMAGE_SIZE;

	}else
	{
		windowWidth=(int)(((float)MAX_IMAGE_SIZE/image->GetHeight())*image->GetWidth());
		windowHeight=MAX_IMAGE_SIZE;
	}

	SetWindowPos(hwnd,0,0,0,windowWidth,windowHeight,SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);

	InvalidateRect(hwnd,0,FALSE); // repaint the window
}
/*
void SearchDirForImages(wchar_t* root_)
{
	wchar_t* buf=new wchar_t[MAX_PATH];
	wchar_t* root=new wchar_t[MAX_PATH];

	GetCurrentDirectoryW(MAX_PATH,buf);
	wcscpy(root,root_);

	if(SetCurrentDirectoryW(root)==0)
	{
		delete root;
		delete buf;
		return;
	}


	WIN32_FIND_DATAW current_file;
	HANDLE file_search=0;

	file_search = FindFirstFileW(L"*.jpg", &current_file);

	if (file_search == INVALID_HANDLE_VALUE)
	{
		delete root;
		delete buf;
		return;
	}

	do{
		if(current_file.dwFileAttributes==0xffffffff)
			continue;

		if( (!lstrcmp(current_file.cFileName,L".")) || (!lstrcmp(current_file.cFileName,L"..")))
		{
			continue;
		}

		if( (current_file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)!=0 )
		{

			wchar_t* root2=new wchar_t[MAX_PATH];

			root2[0]=0;
			wcscpy(root2,root);

			if(root2[lstrlen(root2)-1]!='\\')
			{
				wcscat(root2,L"\\");
			}

			wcscat(root2,current_file.cFileName);

			SearchDirForImages(root2);

		}
		else
		{
			// root is dir & current_file.cFileName is filename			

			wchar_t* filePath=(wchar_t*)malloc(MAX_PATH);

			wcscpy(filePath,root);

			if(filePath[lstrlen(filePath)-1]!='\\')
			{
				wcscat(filePath,L"\\");
			}

			wcscat(filePath,current_file.cFileName);

			fileList->AddPointer(filePath);

		}


	} while (FindNextFileW(file_search, &current_file));

	FindClose(file_search);

	SetCurrentDirectoryW(buf);
	delete buf;
	delete root;

}*/

bool PopulateImageList(HWND hwnd)
{
	/*fileList=new PointerList();


	static wchar_t slidePath[MAX_PATH];
	GetModuleFileNameW(GetModuleHandle(0),slidePath,MAX_PATH);

	wchar_t *p;
	for (p = slidePath; *p; p++) { }	// find end
	for (; p > slidePath && *p != '\\'; p--) { } // back up to last backslash
	*p = 0;	// kill it

	wcscat(slidePath,L"\\slide");

	SearchDirForImages(slidePath);*/

	if(narReader->GetFileCount())
	{
		currentImageNumber=GetRandomImageNumber();
		//image=Gdiplus::Bitmap::FromFile((wchar_t*)fileList->GetPointer(currentImageNumber));
		
		memImage=GlobalAlloc(GMEM_FIXED,narReader->ReadFileSize(currentImageNumber));
		CopyMemory(memImage,narReader->ReadFile(currentImageNumber),narReader->ReadFileSize(currentImageNumber));

		IStream* stream = NULL;
		CreateStreamOnHGlobal(memImage, FALSE,&stream);
		image=Gdiplus::Bitmap::FromStream(stream);			

		if(image->GetWidth()>image->GetHeight()) // resize window size!
		{
			windowHeight=(int)(((float)MAX_IMAGE_SIZE/image->GetWidth())*image->GetHeight());
			windowWidth=MAX_IMAGE_SIZE;
			
		}else
		{
			windowWidth=(int)(((float)MAX_IMAGE_SIZE/image->GetHeight())*image->GetWidth());
			windowHeight=MAX_IMAGE_SIZE;
		}

		SetWindowPos(hwnd,0,0,0,windowWidth,windowHeight,SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);

		return true;
	}else // no images!
	{
		return false;
	}

}

void OnCreate(HWND hwnd)
{
	if(!PopulateImageList(hwnd))
	{
		MessageBox(0,L"No images in slide folder!",L"Error",MB_ICONERROR);
		SendMessage(hwnd,WM_CLOSE,0,0);
		return;
	}

	popupMenu=CreatePopupMenu();

	if(get_config_int("disable_timer"))
		disableTimer=true;
	else
		disableTimer=false;

	if(get_config_int("always_ontop"))
		AlwaysOnTop=true;
	else
		AlwaysOnTop=false;

	if(get_config_int("disable_dock"))
		DisableDock=true;
	else
		DisableDock=false;

	if(get_config_int("disable_drag"))
		DisableDrag=true;
	else
		DisableDrag=false;

	InsertMenu(popupMenu,0xFFFFFFFF,MF_BYPOSITION|MF_STRING,NEXT_SLIDE,L"Next Slide");
	InsertMenu(popupMenu,0xFFFFFFFF,MF_BYPOSITION|MF_SEPARATOR,0,0);
	InsertMenu(popupMenu,0xFFFFFFFF,disableTimer?MF_CHECKED|MF_BYPOSITION|MF_STRING:MF_BYPOSITION|MF_STRING,DONT_CHANGE_SLIDE,L"Lock Current Slide");
	InsertMenu(popupMenu,0xFFFFFFFF,AlwaysOnTop?MF_CHECKED|MF_BYPOSITION|MF_STRING:MF_BYPOSITION|MF_STRING,ALWAYS_ONTOP,L"Always OnTop");
	InsertMenu(popupMenu,0xFFFFFFFF,DisableDock?MF_CHECKED|MF_BYPOSITION|MF_STRING:MF_BYPOSITION|MF_STRING,DISABLE_DOCK,L"Disable Docking");
	InsertMenu(popupMenu,0xFFFFFFFF,DisableDrag?MF_CHECKED|MF_BYPOSITION|MF_STRING:MF_BYPOSITION|MF_STRING,DISABLE_DRAG,L"Disable Dragging");
	InsertMenu(popupMenu,0xFFFFFFFF,MF_BYPOSITION|MF_SEPARATOR,0,0);
	InsertMenu(popupMenu,0xFFFFFFFF,MF_BYPOSITION|MF_STRING,ABOUT_XSLIDE,L"About XSlide");
	InsertMenu(popupMenu,0xFFFFFFFF,MF_BYPOSITION|MF_SEPARATOR,0,0);
	InsertMenu(popupMenu,0xFFFFFFFF,MF_BYPOSITION|MF_STRING,EXIT_XSLIDE,L"Exit");

	int x=get_config_int("x");
	int y=get_config_int("y");

	SetWindowPos(hwnd,AlwaysOnTop?HWND_TOPMOST:0,x,y,0,0,SWP_NOSIZE);

	SetTimer(hwnd,TIMER_ID,60000,0);
}

void saveSettings(HWND hwnd)
{
	RECT rect;
	GetWindowRect(hwnd,&rect);
	set_config_int("x",rect.left);
	set_config_int("y",rect.top);

	set_config_int("disable_timer",disableTimer);
	set_config_int("always_ontop",AlwaysOnTop);
	set_config_int("disable_dock",DisableDock);
	set_config_int("disable_drag",DisableDrag);
}

void OnDestroy(HWND hwnd)
{
	KillTimer(hwnd,TIMER_ID);

	saveSettings(hwnd);

	DestroyMenu(popupMenu);
	delete image;
	GlobalFree(memImage);

	/*for(int i=0;i<fileList->GetSize();i++)
		delete fileList->GetPointer(i);

	delete fileList;*/
}

void OnAbout(HWND hwnd)
{
	MessageBox(hwnd,L"XSlide v1.0\n\nCoded by Ruchira Hasaranga\nE-mail: ruchira66@gmail.com\nWeb: nucos.wordpress.com",L"About",MB_ICONINFORMATION);
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	if(!DisableDock)
		EnableDocking(hwnd,msg,wParam,lParam,10);

	if(!DisableDrag)
		EnableClientAreaDrag(hwnd,msg,wParam,lParam);

    switch(msg)
    {
		case WM_PAINT:
			OnPaint(hwnd);
		break;
		case WM_ERASEBKGND:
		return 1;
		case WM_TIMER:
			if(wParam==TIMER_ID)
			{
				if(!disableTimer)
					OnNextSlide(hwnd);
				return 0;
			}else
				return DefWindowProc(hwnd, msg, wParam, lParam);
		case WM_CONTEXTMENU:
			{
				POINT p;
				GetCursorPos(&p);
				TrackPopupMenu(popupMenu, TPM_LEFTBUTTON, p.x, p.y, 0, hwnd, NULL);
			}
			break;
		case WM_COMMAND:
			switch (LOWORD(wParam))
			{
				case NEXT_SLIDE:
					KillTimer(hwnd,TIMER_ID);
					OnNextSlide(hwnd);
					SetTimer(hwnd,TIMER_ID,60000,0);
				break;
				case DONT_CHANGE_SLIDE:
					disableTimer=!disableTimer;
					CheckMenuItem(popupMenu,DONT_CHANGE_SLIDE,disableTimer?MF_CHECKED:MF_UNCHECKED);
					break;
				case ALWAYS_ONTOP:
					AlwaysOnTop=!AlwaysOnTop;
					CheckMenuItem(popupMenu,ALWAYS_ONTOP,AlwaysOnTop?MF_CHECKED:MF_UNCHECKED);
					SetWindowPos (hwnd, AlwaysOnTop?HWND_TOPMOST:HWND_NOTOPMOST,0, 0, 0, 0,SWP_NOMOVE | SWP_NOSIZE );
					break;
				case DISABLE_DOCK:
					DisableDock=!DisableDock;
					CheckMenuItem(popupMenu,DISABLE_DOCK,DisableDock?MF_CHECKED:MF_UNCHECKED);
					break;
				case DISABLE_DRAG:
					DisableDrag=!DisableDrag;
					CheckMenuItem(popupMenu,DISABLE_DRAG,DisableDrag?MF_CHECKED:MF_UNCHECKED);
					break;
				case ABOUT_XSLIDE:
					OnAbout(hwnd);
					break;
				case EXIT_XSLIDE:
					SendMessage(hwnd,WM_CLOSE,0,0);
				break;
				default:
					return DefWindowProc(hwnd, msg, wParam, lParam);
			}
			return 0;
		case WM_CREATE:
			OnCreate(hwnd);
		break;
        case WM_CLOSE:
            DestroyWindow(hwnd);
        break;
        case WM_DESTROY:
			OnDestroy(hwnd);
            PostQuitMessage(0);
        break;
		case WM_ENDSESSION : // save settings on system shutdown!
			saveSettings(hwnd);
			break;
        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE,LPSTR,int nCmdShow)
{
	CoInitialize(NULL);

	srand( (unsigned)time( NULL ) );
	
	narReader=new NARReader("ImagePack.nar");

	if(!narReader->GetFileCount())
	{
        MessageBox(NULL, L"Image Pack Load Failed!", L"Error!",MB_ICONEXCLAMATION | MB_OK);
        return 0;
	}

	Gdiplus::GdiplusStartupInput gdiplusStartupInput;
	Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);

	WNDCLASSEX wc;
    HWND hwnd;
    MSG Msg;

    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style         = CS_HREDRAW|CS_VREDRAW;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = 0;
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = 0;
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = L"XSlide";
    wc.hIconSm       = 0;

    if(!RegisterClassEx(&wc))
    {
        MessageBox(NULL, L"Window Registration Failed!", L"Error!",MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    hwnd = CreateWindowEx(
        WS_EX_TOOLWINDOW,
        L"XSlide",
        L"XSlide",
        WS_POPUP,
        0,0, 
		windowWidth, windowHeight,
        NULL, NULL, hInstance, NULL);

    if(hwnd == NULL)
    {
        MessageBox(NULL, L"Window Creation Failed!", L"Error!",MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);


    while(GetMessage(&Msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }

	Gdiplus::GdiplusShutdown(m_gdiplusToken);

	delete narReader;
	CoUninitialize();
    return (int)Msg.wParam;
	
}

