--------------------------------------------------------------------------------
-- Title: WikiDateNavigation.lua
-- Description: Like a square peg in a round hole
-- Author: Raphaël Szwarc http://alt.textdrive.com/lua/
-- Creation Date: January 30, 2007
-- Legal: Copyright (C) 2007 Raphaël Szwarc
-- Under the terms of the MIT License
-- http://www.opensource.org/licenses/mit-license.html
--------------------------------------------------------------------------------
-- import dependencies
local HTTPService = require( 'HTTPService' )
local Template = require( 'Template' )
local WikiDate = require( 'WikiDate' )
local WikiDateService = require( 'WikiDateService' )
local WikiService = require( 'WikiService' )
local FormatDate = WikiService.FormatDate
local os = require( 'os' )
local getmetatable = getmetatable
local ipairs = ipairs
local mod = math.mod
local setmetatable = setmetatable
local tostring = tostring
--------------------------------------------------------------------------------
-- WikiDateNavigation
--------------------------------------------------------------------------------
module( 'WikiDateNavigation' )
_VERSION = '1.0'
local self = setmetatable( _M, {} )
local meta = getmetatable( self )
--------------------------------------------------------------------------------
-- Utilities
--------------------------------------------------------------------------------
local lengths = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
local function IsLeap( aYear )
return ( ( mod( aYear, 4 ) == 0 ) and ( mod( aYear, 100 ) ~= 0 ) ) or ( mod( aYear, 400 ) == 0 )
end
local function MonthLength( aDate )
local aLength = lengths[ aDate.month ]
if aDate.month == 2 and IsLeap( aDate.year ) then
aLength = aLength + 1
end
return aLength
end
local function Years()
local thisYear = os.date( '!*t' ).year
local aList = {}
for aYear = thisYear - 11, thisYear do
aList[ #aList + 1 ] = aYear
end
return aList
end
local function Values()
return
{
Years(),
{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 },
{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 },
{ 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 },
{ 25, 26, 27, 28, 29, 30, 31, 0, 0, 0, 0, 0 }
}
end
local function HasValue( anIterator, aValue )
for aLocalValue in anIterator do
if aLocalValue == aValue then
return true
end
end
return false
end
local function FormatYear( aDate, aValue )
local aLocalDate = { year = aValue, month = 1, day = 1 }
local aFormat = os.date( '!\'%y', os.time( aLocalDate ) )
local isCurrent = aDate.year == aValue
local firstYear = WikiDate()() or 0
if HasValue( WikiDate(), aValue ) then
aLocalDate.month = nil
aLocalDate.day = nil
else
aLocalDate = nil
end
if aValue < firstYear then
aFormat = nil
end
return aFormat, aLocalDate, isCurrent
end
local function FormatMonth( aDate, aValue )
local aLocalDate = { year = aDate.year, month = aValue, day = 1 }
local aFormat = os.date( '!%b', os.time( aLocalDate ) )
local isCurrent = aDate.month == aValue
if HasValue( WikiDate( { year = aDate.year } ), aValue ) then
aLocalDate.day = nil
else
aLocalDate = nil
end
return aFormat, aLocalDate, isCurrent
end
local function FormatDay( aDate, aValue )
local aLocalDate = { year = aDate.year, month = aDate.month or 1, day = aValue }
local aLength = MonthLength( aLocalDate )
local isCurrent = aDate.day == aValue
if aValue < 1 or aValue > aLength then
aValue = nil
aLocalDate = nil
isCurrent = false
end
if not HasValue( WikiDate( { year = aDate.year, month = aDate.month or 1 } ), aValue ) then
aLocalDate = nil
end
return aValue, aLocalDate, isCurrent
end
local types = { 'year', 'month', 'day', 'day', 'day' }
local formats = { year = FormatYear, month = FormatMonth, day = FormatDay }
local function Title( aYear, aMonth, aDay )
local aTime = os.time( { year = aYear or 1, month = aMonth or 1, day = aDay or 1 } )
local aFormat = nil
if aDay then
return FormatDate( aTime )
elseif aMonth then
aFormat = '!%B %Y'
else
aFormat = '!%Y'
end
return os.date( aFormat, aTime )
end
local function FormatValue( aType, aDate, aValue )
local aValue, aDate, isCurrent = formats[ aType ]( aDate, aValue )
if aValue and isCurrent then
aValue = ( '%s' ):format( aValue )
end
if aValue and aDate then
local aService = WikiDateService( aDate.year, aDate.month, aDate.day )
local anURL = HTTPService[ aService ]
local aPath = tostring( anURL.path )
local aTitle = Title( aDate.year, aDate.month, aDate.day )
aValue = ( '%s' ):format( aPath, aTitle, aValue )
end
return aValue or ' '
end
--------------------------------------------------------------------------------
-- Metamethods
--------------------------------------------------------------------------------
function meta:__call( aDate )
local aNavigation = { date = aDate }
setmetatable( aNavigation, self )
return aNavigation
end
function meta:__concat( aValue )
return tostring( self ) .. tostring( aValue )
end
function meta:__tostring()
return ( '%s/%s' ):format( self._NAME, self._VERSION )
end
function self:__concat( aValue )
return tostring( self ) .. tostring( aValue )
end
function self:__tostring()
local aTemplate = Template[ 'WikiNavigation.txt' ]
local someValues = Values()
local aDate = self.date
for aRowIndex, aRowValue in ipairs( someValues ) do
local aRowTemplate = aTemplate[ 'rows' ]
local aRowType = types[ aRowIndex ]
for aColumnIndex, aColumnValue in ipairs( aRowValue ) do
local aColumnTemplate = aRowTemplate[ 'columns' ]
aColumnTemplate[ 'value' ] = FormatValue( aRowType, aDate, aColumnValue )
aRowTemplate[ 'columns' ] = aColumnTemplate
end
aTemplate[ 'rows' ] = aRowTemplate
end
return tostring( aTemplate )
end