-- LuaCalendar v3.0.1 by Smurfier (smurfier20@gmail.com)
-- This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 License.

PROPERTIES={
CurrentColor='255,255,255,255';
CurrentHighlight='';
DayLabels='S|M|T|W|T|F|S';
DayPrefix='';
DisableBuiltInEvents='0';
HideLastWeek=0;
HolidayColor='255,0,0,255';
HolidayFile='';
LabelText='';
LeadingZeroes='0';
MeterPrefix='Day';
MonthLabels='';
NextColor='0,0,0,0';
PreviousColor='0,0,0,0';
StartOnMonday=0;
UseLocalMonths='0';
WeekdayHighlight='';
WeekendColor='';
}

function Initialize()
	SMon,OldDay,OldMonth,OldYear,StartDay,cMonth=tonumber(PROPERTIES.StartOnMonday),0,0,0,0,{31;28;31;30;31;30;31;31;30;31;30;31;}
	Month,Year=tonumber(os.date('%m')),tonumber(os.date('%Y'))
	D,W={Sun=0,Mon=1,Tue=2,Wed=3,Thu=4,Fri=5,Sat=6},{First=0,Second=1,Third=2,Fourth=3,Last=4}
--	========== Weekday labels ==========
	Labels={}
	for a in string.gmatch(PROPERTIES.DayLabels,'[^%|]+') do table.insert(Labels,a) end
	for a=1,#Labels do SKIN:Bang('!SetOption "'..PROPERTIES.DayPrefix..a..'" Text "'..Labels[SMon==1 and a%#Labels+1 or a]..'"') end
--	========== Localization ==========
	MLabels={}
	if PROPERTIES.UseLocalMonths=='1' then
		os.setlocale('','time')
		for a=1,12 do table.insert(MLabels,os.date('%B',os.time({year=2000,month=a,day=1}))) end
	else
		for a in string.gmatch(PROPERTIES.MonthLabels,'[^%|]+') do table.insert(MLabels,a) end
	end
--	========== Holiday File ==========
	hFile={}
	for a=1,5 do hFile[a]={} end
	for file in string.gmatch(PROPERTIES.HolidayFile,'[^%|]+') do
		local In=io.input(file,'r')
		if In then
			local Title=''
			for line in io.lines() do
				if string.match(line,'<Title>.+</Title>') then
					Title=' -'..string.match(line,'<Title>(.+)</Title>')
				elseif string.match(line,'<Event.-Month=.+Day=.+>.+</') then
					table.insert(hFile[1],string.match(line,'Month=([%d*]+)'))
					table.insert(hFile[2],string.match(line,'Day=(%w+)'))
					table.insert(hFile[3],string.match(line,'Year=%d+') and string.match(line,'Year=(%d+)') or '')
					table.insert(hFile[4],string.match(line,'<Event.+>(.+)</'))
					table.insert(hFile[5],Title)
				end
			end
		else
			print('File Read Error:'..file)
		end
		io.close(In)
	end	
end -- function Initialize

function Update()
	Today,WeekDay,RealMonth,RealYear=tonumber(os.date('%d')),tonumber(os.date('%w')),tonumber(os.date('%m')),tonumber(os.date('%Y'))
	if SMon==1 then WeekDay=(WeekDay-1+7)%7 end
	if Month~=OldMonth or Year~=OldYear then
		StartDay,cMonth[2],OldMonth,OldYear=tonumber(os.date('%w',os.time({year=Year,month=Month,day=1}))),28+((((Year%4)==0 and (Year%100)~=0) or (Year%400)==0) and 1 or 0),Month,Year
		if  SMon==1 then StartDay=StartDay==0 and 6 or StartDay-1 end
		SKIN:Bang('!SetVariable LastWkHidden '..((math.ceil((StartDay+cMonth[Month])/7)<6 and PROPERTIES.HideLastWeek=='1') and 1 or 0))
		Retrieve()
	end	
	if Today~=OldDay then
		OldDay=Today
		SKIN:Bang('!Execute [!SetVariable ThisWeek '..math.ceil((Today+StartDay)/7)..'][!SetVariable Week '..WeekDay..'][!SetVariable Today '..(PROPERTIES.LeadingZeroes=='1' and string.format('%02d',Today) or Today)..']')
		for a=1,(PROPERTIES.WeekdayHighlight~='' and #Labels or 0) do SKIN:Bang('!SetOption "'..PROPERTIES.DayPrefix..a..'" FontColor "'..(WeekDay==(a-1) and PROPERTIES.WeekdayHighlight or '')..'"') end
		Draw()
	end
	return 'Success!'
end -- function Update

function Retrieve()
	Hol={}
	if PROPERTIES.DisableBuiltInEvents=='0' then
		Easter()
		if Month==11 and (Year%2)==0 then Hol[2-StartDay+(StartDay>1 and 7 or 0)+1]='Election Day' end
	end
	for i=1,#hFile[1] do
		local Dy=0
		if tonumber(hFile[1][i])==Month or hFile[1][i]=='*' then
			if not tonumber(hFile[2][i]) then
				local v1,v2=string.match(hFile[2][i],'(.*)(...)')
				local L=36+D[v2]-StartDay
				Dy=W[v1]<4 and D[v2]+1-StartDay+(StartDay>D[v2] and 7 or 0)+7*W[v1] or L-math.ceil((L-cMonth[Month])/7)*7
			else
				Dy=tonumber(hFile[2][i])
			end
			Hol[Dy]=(Hol[Dy] and Hol[Dy]..'\n' or '')..hFile[4][i]..(tonumber(hFile[3][i]) and ' ('..(Year-tonumber(hFile[3][i]))..')' or '')..hFile[5][i]
		end
	end
	Draw()
end -- function Retrieve

function Draw()
	for a=1,42 do
		local Set={a-StartDay,PROPERTIES.CurrentColor,''}
		if (Today+StartDay)==a and PROPERTIES.CurrentHighlight~='' then
			Set[2],Set[3]=PROPERTIES.CurrentHighlight,(Hol[Today] and Hol[Today] or '')
		elseif a>35 and math.ceil((StartDay+cMonth[Month])/7)<6 and PROPERTIES.HideLastWeek=='1' then
			Set[2]='0,0,0,0'
		elseif Set[1]<1 then
			Set[1],Set[2]=Set[1]+cMonth[(Month==1 and 12 or Month-1)],PROPERTIES.PreviousColor
		elseif Set[1]>cMonth[Month] then
			Set[1],Set[2]=Set[1]-cMonth[Month],PROPERTIES.NextColor
		elseif Hol[Set[1]] then
			Set[2],Set[3]=PROPERTIES.HolidayColor,Hol[Set[1]]
		elseif a%7==0 or SMon==0 and a%7==1 or SMon==1 and a%7==6 and PROPERTIES.WeekendColor then
			Set[2]=PROPERTIES.WeekendColor
		end
		SKIN:Bang('!Execute [!SetOption "'..PROPERTIES.MeterPrefix..a..'" Text "'..(PROPERTIES.LeadingZeroes=='1' and string.format("%02d",Set[1]) or Set[1])..'"][!SetOption "'..PROPERTIES.MeterPrefix..a..'" FontColor "'..Set[2]..'"][!SetOption "'..PROPERTIES.MeterPrefix..a..'" ToolTipText "'..Set[3]..'"]')
	end
	SKIN:Bang('!Execute [!SetVariable Month '..(MLabels[Month] and MLabels[Month] or Month)..'][!SetVariable Year '..Year..'][!SetOption MonthLabel Text "'..(PROPERTIES.LabelText~='' and Replace(PROPERTIES.LabelText) or ((MLabels[Month] and MLabels[Month] or Month)..', '..Year))..'"]')
end -- function Draw

function Easter()
	local a,b,c,g,h,L,m=Year%19,math.floor(Year/100),Year%100,0,0,0,0
	local d,e,f,i,k=math.floor(b/4),b%4,math.floor((b+8)/25),math.floor(c/4),c%4
	g=math.floor((b-f+1)/3)
	h=(19*a+b-d-g+15)%30
	L=(32+2*e+2*i-h-k)%7
	m=math.floor((a+11*h+22*L)/451)
	if Month==math.floor((h+L-7*m+114)/31) then Hol[(h+L-7*m+114)%31+1]='Easter' end
end -- function Easter

function Forward()
	Month,Year=Month%12+1,Month==12 and Year+1 or Year
	SKIN:Bang('!SetVariable NotCurrentMonth '..((Month==RealMonth and Year==RealYear) and 0 or 1))
end

function Back()
	Month,Year=Month==1 and 12 or Month-1,Month==1 and Year-1 or Year
	SKIN:Bang('!SetVariable NotCurrentMonth '..((Month==RealMonth and Year==RealYear) and 0 or 1))
end

function Home()
	Month,Year=RealMonth,RealYear
	SKIN:Bang('!SetVariable NotCurrentMonth 0')
end

function Replace(a)
	for i,v in pairs({(MLabels[Month] and MLabels[Month] or Month);Year;(PROPERTIES.LeadingZeroes=='1' and string.format('%02d',Today) or Today)}) do a=string.gsub(a,'%%'..i,v) end
	return a
end