local getArgs = require('Module:Arguments').getArgs
local builder = mw.html.create

local function defaultInvokeFunc(funcName)
	return function (frame)
		args = getArgs(frame, {
 trim = true,
 removeBlanks = true,
 parentFirst = true

 local from = getNotNilValue(tonumber(args['from']))
 local to = getNotNilValue(tonumber(args['to']))

 if not from or not to or from == to then
 return ("")
 else
 	return horizontal_timeline[funcName](args)
 end
	end
end

horizontal_timeline.showTimeLine = defaultInvokeFunc('_showTimeLine')
function horizontal_timeline._showTimeLine(args)
 local wdth = getNotNilValue
 local bordr = getNotNilValue(args['border'], '1px solid rgb' )
 local bgCol = getNotNilValue
 local mrgn = getNotNilValue

 local div_root = builder

 local cntnt = div_root
 
 local rowNums = affixNums -- Gets numbers for row1, row2, etc. with nil arguments removed.
 for _, num in ipairs(rowNums) do
 local rowType = args['row' .. num] -- Gets args.rowtype1, args.rowtype2, etc. with nil arguments removed.
 if rowType == 'scale' then
 cntnt:wikitext(horizontal_timeline.scaleRow(args))
 elseif rowType == 'note' then
 cntnt:wikitext(horizontal_timeline.noteRow)
 elseif rowType == 'timeline' then
 cntnt:wikitext(horizontal_timeline.timelineRow)
 else
 cntnt:wikitext(rowType)
 end
 end
 if args.caption then
 cntnt:tag('p')
 end
 return tostring(div_root) .. ""
end

horizontal_timeline.showOneRow = defaultInvokeFunc('_showOneRow')
function horizontal_timeline._showOneRow(args)
 local rowNums = affixNums -- Gets numbers for row1, row2, etc. with nil arguments removed.
 for _, num in ipairs(rowNums) do
 local rowType = args['row' .. num] -- Gets args.rowtype1, args.rowtype2, etc. with nil arguments removed.
 if rowType == 'scale' then
 return horizontal_timeline.scaleRow(args)
 elseif rowType == 'note' then
 return horizontal_timeline.noteRow
 elseif rowType == 'timeline' then
 return horizontal_timeline.timelineRow
 else
 return wikitext(rowType)
 end
 end
 return "?"
end

function horizontal_timeline.timelineRow
 local root = mw.html.create
 
 local from = getNotNilValue(tonumber(args['from']))
 local to = getNotNilValue(tonumber(args['to']))
 
 local style = getNotNilValue
 local hght = getNotNilValue 
 local bordrTop = getNotNilValue 
 local bordrBtm = getNotNilValue 
 local txtTop = getNotNilValue 
 local colr = getNotNilValue 
	local barborder = getNotNilValue 
	 
 if bordrTop ~= 'none' then
 	bordrTop = 'border-top:' .. bordrTop .. ';'
 else
 	bordrTop = ''
	end
	
	if bordrBtm ~= 'none' then
 	bordrBtm = 'border-bottom:' .. bordrBtm .. ';'
 else
 	bordrBtm = ''
	end

 local p = root

 local rowDat = affixNums
 local lastTo = from
 local firstNode = true
 for _, vals in ipairs(rowDat) do

 	local styleL = getNotNilValue

 --These vars should be initialized every iteration. Do not move outside of loop
 local bar_to = tonumber(getNotNilValue )
 local bar_fontsize =getNotNilValue
 local bar_bordr= getNotNilValue
 local bar_txtTop= getNotNilValue
 local bar_text = getNotNilValue
 local bar_colour = getNotNilValue
 
 if from < to then
 if bar_to > to then bar_to = to end
 if lastTo < from then lastTo = from end
 else
 if bar_to < to then bar_to = to end
 if lastTo > from then lastTo = from end
 	end

 local width =( (bar_to-lastTo)*100 / (to-from) ) --math.abs

 if width > 0 and width <= 100 then
 if bar_bordr == 'none' then
 if firstNode then -- for first box both left and right border needed
 bar_bordr = barborder .. "; border-left:" .. barborder
 firstNode = false
 else
 bar_bordr = barborder
 	 end
		 end
 p:tag('div')
 end

 lastTo = bar_to
 end
 return tostring(root)
end

function horizontal_timeline.noteRow
 local root = mw.html.create
 
 local from = getNotNilValue(tonumber(args['from']))
 local to = getNotNilValue(tonumber(args['to']))
 
 local hght = getNotNilValue

 local p = root

 local rowDat = affixNums
 if not rowDat then
 return ("")
 end
 for _, vals in ipairs(rowDat) do
 local note_at =args['row' .. num .. '-'.. vals .. '-at'] --will never be nil as it is what is sued to recieve rowDat
 local note_text =getNotNilValue
 local note_shift=getNotNilValue
 local note_lift =getNotNilValue
 local note_arrow=getNotNilValue

		local note_sft = 100*(note_at - from) / (to-from)
 
 p:tag('div')
 end
 return tostring(root)
end

function horizontal_timeline.scaleRow(args)
	local from = getNotNilValue(tonumber(args['from']))
 local to = getNotNilValue(tonumber(args['to']))
 local inc = getNotNilValue( tonumber(args['inc']), (math.floor( (from - to) / 5 ) * -1) )
 local negativeFmt = getNotNilValue
 local positiveFmt = getNotNilValue
 local zeroFmt = getNotNilValue
 local nudge = getNotNilValue

 local wdth = math.abs ( (100 * inc) / (from - to) )
 local root = mw.html.create

 local p = root
 
 for var=from, to, inc do
 if from < to then
 if var+inc > to then wdth = 0 end
 else
 if var+inc < to then wdth = 0 end
 end
 
 local lbl
 if var < 0 then
 lbl = string.format( negativeFmt, math.abs(var) )
 elseif var > 0 then
 lbl = string.format( positiveFmt, math.abs(var) )
 else
 lbl = string.format( zeroFmt, math.abs(var) )
 end

 local markr = getNotNilValue 
		lbl = getNotNilValue
		
 p:tag('div')
 end
 p:done
 return tostring(root)
end

--Returns the first non nil value from the list of parameters.
function getNotNilValue(...)
 for _,v in pairs(arg) do --Do not use ipairs. Will stop at first nil
 if v then return v end
 end
 return nil
end

function affixNums
 prefix = prefix or ''
 suffix = suffix or ''
 
 local pattern = '^' .. prefix .. '([1-9]%d*)' .. suffix .. '$'
 local nums = {}
 for k, v in pairs(t) do
 if type(k) == 'string' then 
 local num = mw.ustring.match
 if num then
 nums[#nums + 1] = tonumber(num)
 end
 end
 end
 table.sort(nums)
 return nums
end