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

#include "stdafx.h"
#include <time.h>
#include <stdio.h>
#include "resource.h"
#include "nopepad.h"


// Global Variables:
HINSTANCE hInst;								// current instance
TCHAR szTitle[MAX_LOADSTRING];								// The title bar text
TCHAR szWindowClass[MAX_LOADSTRING];								// The title bar text

char CurFile[MAX_PATH];
BOOL Modified=FALSE;

HFONT CurFont;
PAGESETUPDLG PageSetup;

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

void HandleEdit( int Notification );
void DoOpenFile( HWND hWnd );
void DoNewFile( HWND hWnd );
BOOL DoSaveFile( HWND hWnd );
BOOL DoSaveAsFile( HWND hWnd );
void DoClipboard( HWND hWnd, UINT ID );
void SetTitle( HWND hWnd );
void PrepareEditMenu( HWND hWnd );
void InsertTimeDate( HWND hWnd );
HFONT PNCreateFont( int Height, BOOL Bold, BOOL Italic, BOOL Underline, BOOL StrikeOut, DWORD Family, char* FaceName );
void SetFont( HWND hWnd );
void DoPrint( HWND hWnd );

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
	MSG msg;
	HACCEL hAccelTable;

	// Initialize the Margin settings for the page setup
	PNPageSetupInit( &PageSetup );
	strcpy( CurFile, "Untitled" );

	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
	LoadString(hInstance, IDC_NOPEPAD, szWindowClass, MAX_LOADSTRING);
	PNRegisterClass(hInstance);

	CurFont = PNCreateFont( 12, FALSE, FALSE, FALSE, FALSE, 0, "FixedSys" );
	
	if (!InitInstance (hInstance, nCmdShow)) 
		return FALSE;

	hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_NOPEPAD);

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

	return msg.wParam;
}


ATOM PNRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX); 

	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= (WNDPROC)WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= LoadIcon(hInstance, (LPCTSTR)IDI_NOPEPAD);
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= GetSysColorBrush(COLOR_3DFACE);
	wcex.lpszMenuName	= (LPCSTR)IDC_NOPEPAD;
	wcex.lpszClassName	= szWindowClass;
	wcex.hIconSm		= LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);

	return RegisterClassEx(&wcex);
}

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

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

   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

   if (!hWnd)
      return FALSE;

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

   return TRUE;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;
	TCHAR szHello[MAX_LOADSTRING];
	LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);

	switch (message) 
	{
		case WM_CREATE:
			{
				HWND E = CreateWindowEx( WS_EX_CLIENTEDGE, "EDIT", "", 
					WS_MAXIMIZE|WS_VISIBLE|WS_CHILD|WS_HSCROLL|WS_VSCROLL|ES_NOHIDESEL|ES_MULTILINE, 0, 0,
					0, 0, hWnd, (HMENU)IDC_EDIT,
					0, 0 );
				SendMessage( E, WM_SETFONT, (WPARAM)CurFont, 0 );
				SetFocus( E );
				SetTitle( hWnd );
				return(0);
			}
		case WM_SIZE:
			SetWindowPos( GetDlgItem( hWnd, 1000 ), 0, 0, 0, LOWORD(lParam), HIWORD(lParam), SWP_NOMOVE|SWP_NOZORDER );
			return(0);
		case WM_INITMENUPOPUP:
			if( LOWORD(lParam) == 1 ) // Edit menu
				PrepareEditMenu( hWnd );
			break;
		case WM_COMMAND:
			wmId    = LOWORD(wParam); 
			wmEvent = HIWORD(wParam); 
			switch (wmId)
			{
				case IDM_UNDO:
				case IDM_CUT:
				case IDM_COPY:
				case IDM_PASTE:
				case IDM_DELETE:
				case IDM_SELECTALL:
					DoClipboard( hWnd, wmId );
					break;
				case IDC_EDIT:
					HandleEdit( wmEvent );
					break;
				case IDM_TIMEDATE:
					InsertTimeDate( hWnd );
					break;
				case IDM_SETFONT:
					SetFont( hWnd );
					break;
				case IDM_NEW:
					DoNewFile( hWnd );
					break;
				case IDM_OPEN:
					DoOpenFile( hWnd );
					break;
				case IDM_SAVE:
					DoSaveFile( hWnd );
					break;
				case IDM_SAVEAS:
					DoSaveAsFile( hWnd );
					break;
				case IDM_ABOUT:
				   DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
				   break;
				case IDM_PAGESETUP:
					PNPageSetup( hWnd, &PageSetup );
					break;
				case IDM_PRINT:
					DoPrint( hWnd );
					break;
				case IDM_EXIT:
				   DestroyWindow(hWnd);
				   break;
				default:
				   return DefWindowProc(hWnd, message, wParam, lParam);
			}
			break;
		case WM_DESTROY:
			PostQuitMessage(0);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
   }
   return 0;
}

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

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

void SetTitle( HWND hWnd )
{
	char Title[MAX_PATH+32];
	wsprintf( Title, "%s - NopePad", CurFile );
	SetWindowText( hWnd, Title );
}

void DoNewFile( HWND hWnd )
{
	if( Modified )
	{
		char Msg[MAX_PATH*2];
		int i;
		wsprintf( Msg, "The text in the file %s has changed\n\nDo you want to save it?", CurFile );
		i = MessageBox( hWnd, Msg, "NopePad", MB_ICONEXCLAMATION|MB_YESNOCANCEL );
		if( i == IDYES )
			if( !DoSaveAsFile( hWnd ) )
				return;
		if( i == IDCANCEL )
			return;
	}
	SetDlgItemText( hWnd, IDC_EDIT, "" );
	Modified = FALSE;
	strcpy( CurFile, "Untitled" );
	Modified = FALSE;
	SetTitle( hWnd );
}


void DoOpenFile( HWND hWnd )
{

	if( PNGetOpenFileName( hWnd, CurFile, sizeof(CurFile) ) )
	{
		ReadText( hWnd, IDC_EDIT );
		SetTitle( hWnd );
	}
}

BOOL DoSaveFile( HWND hWnd )
{
	char TmpName[MAX_PATH]="";
	
	if( !CurFile[0] )
	{
		if( !PNGetSaveFileName( hWnd, TmpName, sizeof(TmpName) ) )
			return( FALSE );
		if( !OkToReplace( hWnd, TmpName ) )
			return( FALSE );
		strcpy( CurFile, TmpName );
	}
	WriteText( hWnd, IDC_EDIT );
	SetTitle( hWnd );
	return( TRUE );
}

BOOL DoSaveAsFile( HWND hWnd )
{
	char TmpName[MAX_PATH]="";

	if( !PNGetSaveFileName( hWnd, TmpName, sizeof(TmpName) ) )
		return( FALSE );
	if( !OkToReplace( hWnd, TmpName ) )
		return( FALSE );
	strcpy( CurFile, TmpName );
	DoSaveFile( hWnd );
	return( TRUE );
}

void HandleEdit( int Notification )
{
	switch( Notification )
	{
		case EN_CHANGE:
			Modified = TRUE;
	}
}

void DoClipboard( HWND hWnd, UINT ID )
{
	int SelStart, SelEnd, ClipLength;

	ClipLength = GetClipTextLength( hWnd );
	SendDlgItemMessage( hWnd, IDC_EDIT, EM_GETSEL, (WPARAM)&SelStart, (LPARAM) &SelEnd );
	switch( ID )
	{
		case IDM_UNDO:
			SendDlgItemMessage( hWnd, IDC_EDIT, WM_UNDO, 0, 0 );
			break;
		case IDM_CUT:
			SendDlgItemMessage( hWnd, IDC_EDIT, WM_CUT, 0, 0 );
			SelEnd=SelStart;
			break;
		case IDM_COPY:
			SendDlgItemMessage( hWnd, IDC_EDIT, WM_COPY, 0, 0 );
			break;
		case IDM_PASTE:
			SendDlgItemMessage( hWnd, IDC_EDIT, WM_PASTE, 0, 0 );
			SelStart=SelEnd = (SelEnd+ClipLength);
			break;
		case IDM_DELETE:
			SendDlgItemMessage( hWnd, IDC_EDIT, EM_REPLACESEL, TRUE, (LPARAM)"" );
			break;
		case IDM_SELECTALL:
			SendDlgItemMessage( hWnd, IDC_EDIT, EM_SETSEL, 0, -1 );
	}
}

void PrepareEditMenu( HWND hWnd )
{
	int SelStart, SelEnd, ClipLength;

	ClipLength = GetClipTextLength( hWnd );
	SendDlgItemMessage( hWnd, IDC_EDIT, EM_GETSEL, (WPARAM)&SelStart, (LPARAM) &SelEnd );
	int CanUndo = SendDlgItemMessage( hWnd, IDC_EDIT, EM_CANUNDO, 0, 0 );
	
	HMENU hMenu = GetMenu( hWnd );

	EnableMenuItem( hMenu, IDM_COPY, SelStart!=SelEnd?MF_ENABLED:MF_GRAYED );
	EnableMenuItem( hMenu, IDM_CUT, SelStart!=SelEnd?MF_ENABLED:MF_GRAYED );
	EnableMenuItem( hMenu, IDM_DELETE, SelStart!=SelEnd?MF_ENABLED:MF_GRAYED );
	EnableMenuItem( hMenu, IDM_PASTE, ClipLength>0?MF_ENABLED:MF_GRAYED );
	EnableMenuItem( hMenu, IDM_UNDO, CanUndo?MF_ENABLED:MF_GRAYED );
	
}

void InsertTimeDate( HWND hWnd )
{
	char Text[128];
	
	time_t Now;
	struct tm* ptm;

	time( &Now );
	ptm = localtime( &Now );
	sprintf( Text, "%d:%d %cM %d/%d/%d", ptm->tm_hour%12?ptm->tm_hour%12:12, 
		ptm->tm_min, ptm->tm_hour>11?'P':'A', ptm->tm_mon+1, ptm->tm_mday, ptm->tm_year );
	SendMessage( GetDlgItem(hWnd, IDC_EDIT ), EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)Text );;
}

HFONT PNCreateFont( int Height, BOOL Bold, BOOL Italic, BOOL Underline, BOOL StrikeOut, DWORD Family, char* FaceName )
{
	if( Family==0 )
		Family = FF_DONTCARE;
	return( CreateFont( Height, 0, 0, 0, Bold ? FW_BOLD : FW_NORMAL,
		Italic, Underline, StrikeOut, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
		CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | Family, FaceName ) );
}

void SetFont( HWND hWnd )
{
	if( PNChooseFont( hWnd, &CurFont ) )
	{
		SendMessage( GetDlgItem( hWnd, IDC_EDIT ), WM_SETFONT, (WPARAM)CurFont, MAKELPARAM(TRUE,0) );
		SetFocus( GetDlgItem( hWnd, IDC_EDIT ) );
	}
}



void DoPrint( HWND hWnd )
{
	HDC PrintDC;
	static char OneLine[1024]; // We will print 1 line at a time
	HFONT ReportFont;
	SIZE TextSize;
	int End;
	bool PageStart=true;
	int Top, Left, Bottom, Right, BodyWidth, CurY;
	int LineHeight, PrintLen;

	PrintDC = PNGetPrinterDC();
	
	if( !PrintDC )
		MessageBox( hWnd, "Unable to locate printer", NULL, MB_ICONEXCLAMATION|MB_OK );
	else
	{
		HWND hEdit = GetDlgItem(hWnd, IDC_EDIT );
		int LineCount = SendMessage( hEdit, EM_GETLINECOUNT, 0, 0 );
		
		// CurFonts Height is based on screen DC.  Make one for the printer DC
		ReportFont = PNCreatePrinterFont( hWnd, CurFont );
		SelectObject( PrintDC, ReportFont );
		SetMapMode( PrintDC, MM_HIENGLISH );

		// Determine our true printable margins
		PNEzMargins( &PageSetup, &Left, &Top, &Right, &Bottom );
		BodyWidth = Right - Left;

		if( LineCount )
		{
			// Determine Text height for the current font 
			GetTextExtentPoint32( PrintDC, "Hy", 2, &TextSize );
			LineHeight = TextSize.cy;
			
			// Setup the DOCINFO structure, for Print Manager
			DOCINFO DocInfo;
			memset( &DocInfo, 0, sizeof(DocInfo) );
			DocInfo.lpszDocName = CurFile;

			// Start the Document
			StartDoc( PrintDC, &DocInfo );

			StartPage( PrintDC );
			EndPage( PrintDC );

			// Print each line from the multi-line edit (the report)
			for( int i = 0; i < LineCount; i++ ) 
			{
				// Prints header for report
				if( PageStart )
				{
					if( i > 0 ) // Is this the start of a second or greater page?
						EndPage( PrintDC );
					
					// Start a new page
					StartPage( PrintDC );
					
					// Printer header
					TextOut( PrintDC, Left, Top + TextSize.cy+100, CurFile, strlen(CurFile) );
					MoveToEx( PrintDC, Left, Top + 100, NULL ); // Remember: +100 means 'up the page'
					LineTo( PrintDC, Right, Top + 100 );
					
					// Set StartPage flag to false until needed again, and set CurY back to top
					PageStart = false;
					CurY = Top; 
				}

				// Get line from edit control
				*(int*)OneLine = sizeof( OneLine );
				End = SendMessage( hEdit, EM_GETLINE, (WPARAM)i, (LPARAM)OneLine );
				OneLine[End]='\0';

				// Determine how much of line will fit within our margins
				PrintLen = strlen( OneLine );
				do {
					GetTextExtentPoint32( PrintDC, OneLine, PrintLen, &TextSize );
					if( TextSize.cx > BodyWidth )
						PrintLen--;
				} while( TextSize.cx > BodyWidth );

				// Print that 1 line
				TextOut( PrintDC, Left, CurY, OneLine, PrintLen );
				CurY -= TextSize.cy; // Move CurY down the page

				// If we have atleast 1 more line, and it would be below bottom margin,
				// then we indicate a new page start is needed
				if( i+1 < LineCount && (CurY-TextSize.cy) <= Bottom )
					PageStart = true;
			}
			
			// End the current page, and the report.
			EndPage( PrintDC );
			EndDoc( PrintDC );
		}
		// Release the Printer DC when done printing
		DeleteDC( PrintDC );
	}
}
