.386
.model flat, stdcall
option casemap :none

include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\gdi32.inc

includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\gdi32.lib

WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
MonthCalc proto
AfterPaint proto :DWORD

.const
	Seven equ 7
.data
	szClassName db "dzpWC",0
	szAppName db "dzp - calendar",0
	szMo db "ПН"
	szTu db "ВТ"
	szWe db "СР"
	szTh db "ЧТ"
	szFr db "ПТ"
	szSa db "СБ"
	szSu db "ВС"
	szDigits db " 1 2 3 4 5 6 7 8 910111213141516171819202122232425262728293031"
	wMonth db 31,28,31,30,31,30,31,31,30,31,30,31
	szMonthFormat db "MMMM yyyy",0
	szFontName db "Arial Black",0
.data?
	hInstance dd ?
	CommandLine dd ?
	stm SYSTEMTIME <?>
	dFirstDayOfWeek dd ? ;номер дня недели для первого числа месяца
	dDaysCount dd ? ;число дней в месяце
	dWeekDay dd ?
	dWeek dd ?
	dPosX dd ?
	dPosY dd ?
	szMonthString db 14 dup(?)
	dMonthLen dd ?
	NowRect RECT <?>
.code
start:
	invoke GetModuleHandle,NULL
	mov hInstance,eax
	invoke GetCommandLine
	mov CommandLine,eax
	invoke WinMain,hInstance,NULL,CommandLine,SW_SHOWDEFAULT
	invoke ExitProcess,NULL
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
	LOCAL wc:WNDCLASSEX
	LOCAL msg:MSG
	LOCAL hwnd:HWND
	mov wc.cbSize,sizeof WNDCLASSEX
	mov wc.style,CS_HREDRAW or CS_VREDRAW
	mov wc.lpfnWndProc,offset WndProc
	mov wc.cbClsExtra,NULL
	mov wc.cbWndExtra,NULL
	push hInst
	pop wc.hInstance
	mov wc.hbrBackground,COLOR_WINDOW+1
	mov wc.lpszMenuName,NULL
	mov wc.lpszClassName,offset szClassName
	invoke LoadIcon,hInst,IDI_APPLICATION
	mov wc.hIcon,eax
	mov wc.hIconSm,eax
	invoke LoadCursor,NULL,IDC_ARROW
	mov wc.hCursor,eax
	invoke RegisterClassEx,addr wc
	invoke GetSystemMetrics,SM_CXSCREEN
	sub eax,480
	invoke CreateWindowEx,NULL,addr szClassName,addr szAppName,\
		WS_POPUP,eax,0,480,328,NULL,NULL,hInst,NULL
	mov hwnd,eax
	invoke ShowWindow,hwnd,SW_SHOWNORMAL
	invoke UpdateWindow,hwnd
	.while TRUE
		invoke GetMessage,addr msg,0,0,0
		.break .if (!eax)
		invoke TranslateMessage,addr msg
		invoke DispatchMessage,addr msg
	.endw
	mov eax,msg.wParam
	ret
WinMain endp
WndProc proc hWnd:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
	LOCAL hdc:HDC
	LOCAL ps:PAINTSTRUCT
	LOCAL hfont:HFONT
	.if uMsg==WM_CREATE
		invoke GetWindowLong,hWnd,GWL_EXSTYLE
		or eax,WS_EX_LAYERED or WS_EX_NOACTIVATE
		invoke SetWindowLong,hWnd,GWL_EXSTYLE,eax
		invoke SetLayeredWindowAttributes,hWnd,00FFFFFFh,65,LMA_ALPHA or LMA_COLORKEY
		invoke GetSystemTime,addr stm
		invoke MonthCalc
	.elseif uMsg==WM_PAINT
		invoke BeginPaint,hWnd, ADDR ps
		mov hdc,eax
		invoke CreateFont,50,16,0,0,400,TRUE,0,0,DEFAULT_CHARSET,\
				OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,\
				DEFAULT_QUALITY,DEFAULT_PITCH or FF_SCRIPT,ADDR szFontName
		invoke SelectObject, hdc, eax
		mov hfont,eax
		;вывести месяц и год
		invoke RtlZeroMemory,addr szMonthString,14
		invoke GetDateFormat,LOCALE_USER_DEFAULT,NULL,addr stm,addr szMonthFormat,addr szMonthString,50
		dec eax
		mov dMonthLen,eax
		invoke SetTextColor,hdc,0000FF00h
		invoke TextOut,hdc,0,0,addr szMonthString,dMonthLen
		;вывести дни недели (будние и выходные разным цветом)
		invoke SetTextColor,hdc,00FF0000h
		mov ecx,0
		@@:
		mov eax,ecx
		inc eax
		xor edx,edx
		mov ebx,60
		mul ebx
		mov edx,ecx
		shl edx,1
		add edx,offset szMo
		push ecx
		invoke TextOut,hdc,eax,40,edx,2
		pop ecx
		inc ecx
		cmp ecx,5
		jne @b
		push ecx
		invoke SetTextColor,hdc,000000FFh
		pop ecx
		@@:
		mov eax,ecx
		inc eax
		xor edx,edx
		mov ebx,60
		mul ebx
		mov edx,ecx
		shl edx,1
		add edx,offset szMo
		push ecx
		invoke TextOut,hdc,eax,40,edx,2
		pop ecx
		inc ecx
		cmp ecx,7
		jne @b
		
		;вывести числа месяца
		
		;цикл по дням недели
		xor ecx,ecx
		@std:
		inc ecx
		mov eax,ecx
		add eax,dFirstDayOfWeek
		dec eax
		xor edx,edx
		mov ebx,Seven
		div ebx
		inc edx
		mov dWeekDay,edx
		add eax,2
		mov dWeek,eax
		xor edx,edx
		mov ebx,40
		mul ebx
		mov dPosY,eax
		xor edx,edx
		mov eax,dWeekDay
		mov ebx,60
		mul ebx
		mov dPosX,eax
		push ecx
		
		mov eax,dWeekDay
		cmp eax,6
		je @f
		mov eax,dWeekDay
		cmp eax,Seven
		je @f
		invoke SetTextColor,hdc,00FF0000h
		jmp @vyh
		@@:
		invoke SetTextColor,hdc,000000FFh
		@vyh:
		mov eax,offset szDigits
		pop ecx
		push ecx
		dec ecx
		shl ecx,1
		add eax,ecx
		invoke TextOut,hdc,dPosX,dPosY,eax,2
		
		pop ecx
		cmp ecx,dDaysCount
		jb @std
		invoke SelectObject,hdc,hfont
		
		invoke CreatePen,PS_SOLID,5,000000FFh
		invoke SelectObject,hdc,eax
		;invoke GetSysColor,COLOR_BTNFACE
		invoke MoveToEx,hdc,NowRect.left,NowRect.top,0
		invoke LineTo,hdc,NowRect.right,NowRect.top
		invoke LineTo,hdc,NowRect.right,NowRect.bottom
		invoke LineTo,hdc,NowRect.left,NowRect.bottom
		invoke LineTo,hdc,NowRect.left,NowRect.top
		
		invoke AfterPaint,hWnd
		invoke EndPaint,hWnd, ADDR ps
	.elseif uMsg==WM_NCHITTEST
		invoke DefWindowProc,hWnd,uMsg,wParam,lParam
		.if eax==HTCLIENT
			mov eax,HTCAPTION
		.endif
		ret
	.elseif uMsg==WM_CLOSE
		invoke DestroyWindow,hWnd
	.elseif uMsg==WM_DESTROY
		invoke PostQuitMessage,NULL
	.else
		invoke DefWindowProc,hWnd,uMsg,wParam,lParam
		ret
	.endif
	xor eax,eax
	ret
WndProc endp
MonthCalc proc
	;вычислить номер первого дня недели
	mov ax,stm.wDayOfWeek
	cmp ax,0
	jne @f
	mov ax,Seven
	@@:
	dec ax
	mov cx,stm.wDay
	dec cx
	sub ax,cx
	add ax,35
	xor edx,edx
	mov bx,Seven
	div bx
	mov dFirstDayOfWeek,edx
	;определим високосный ли год?
	xor dx,dx
	mov ax,stm.wYear
	mov bx,4
	div bx
	cmp dx,0
	jne @nvis
	xor dx,dx
	mov ax,stm.wYear
	mov bx,100
	div bx
	cmp dx,0
	jne @ivis
	xor dx,dx
	mov ax,stm.wYear
	mov bx,400
	div bx
	cmp dx,0
	je @ivis
	@nvis:
	mov eax,offset wMonth 
	mov byte ptr [eax+1],28
	jmp @fvis
	@ivis:
	mov eax,offset wMonth 
	mov byte ptr [eax+1],29
	@fvis:
	mov edx,offset wMonth
	xor ecx,ecx
	mov cx,stm.wMonth
	dec cx
	xor eax,eax
	mov al,byte ptr [edx+ecx]
	mov dDaysCount,eax
	;координаты выделения текущей даты
	xor edx,edx
	mov eax,dFirstDayOfWeek
	add ax,stm.wDay
	dec eax
	mov ebx,7
	div ebx
	mov NowRect.left,edx
	xor edx,edx
	add eax,2
	mov ebx,40
	mul ebx
	add eax,6
	mov NowRect.top,eax
	add eax,40
	mov NowRect.bottom,eax
	xor edx,edx
	mov eax,NowRect.left
	inc eax
	mov ebx,60
	mul ebx
	sub eax,5
	mov NowRect.left,eax
	add eax,53
	mov NowRect.right,eax
	ret
MonthCalc endp
AfterPaint proc hWnd:DWORD
	LOCAL WinRect:RECT
	;переместить окно на задний план
	invoke GetWindowRect,hWnd,addr WinRect
	mov eax,WinRect.right
	sub eax,WinRect.left
	mov ebx,WinRect.bottom
	sub ebx,WinRect.top
	invoke SetWindowPos,hWnd,HWND_BOTTOM,WinRect.left,WinRect.top,eax,ebx,SWP_SHOWWINDOW
	ret
AfterPaint endp
end start