Documentation for this module may be created at ಮೋಡ್ಯೂಲ್:Infobox settlement/doc

--
-- This template will implement {{Infobox settlement}}
--
local p = {}
local math_module = require( "Module:Wp/bgn/Math" )
local precision = math_module._precision

local function isnotempty(s)
	return s and s:match( '^%s*(.-)%s*$' ) ~= ''
end

local function rnd(num, digits)
	-- This function implements {{rnd}}
	return math_module._precision_format(tostring(num), tostring(digits))
end

local function order_of_magnitude(num)
	-- This function partially implements {{Order of magnitude}}
    if( num ) then
		num = math.abs(num)
		if( num == 0 ) then
			return 0
		else
			return math.floor( math.log10(num) )
		end
	else
		return 0
	end
end

local function page_exists( title )
    -- This function implements #ifexist
    local noError, titleObject = pcall(mw.title.new, title)
    if not noError then
        return false
    else
        if titleObject then
            return titleObject.exists
        else
            return false
        end
    end
end

local function link(pagelink, linktext, name)
    -- This function implements {{Infobox settlement/link}}
    pagelink = pagelink or ''
    linktext = linktext or ''
    name     = name or ''
    
    if( pagelink ~= '' ) then
        -- use "[[pagelink|linktext]]"
        return string.format('[[%s|%s]]', pagelink, linktext)
    else
        -- try "[[linktext of PAGENAME|linktext]]"
        pagelink = string.format('%s of %s',linktext, mw.title.getCurrentTitle().text)
        if( page_exists( pagelink ) ) then
            return string.format('[[%s|%s]]', pagelink, linktext)
        elseif( name ~= '' ) then
            -- try "[[linktext of name|linktext]]"
            pagelink = string.format('%s of %s', linktext, name)
            if( page_exists(pagelink) ) then
               return string.format('[[%s|%s]]', pagelink, linktext)
            end
        end
    end

    return linktext
end

local function columns(cell1, cell2, cell3, cell4)
    --- This function implements {{Infobox settlement/columns}} with no cell0
    local function makecell( c1 )
        if isnotempty(c1) then
			local root = mw.html.create('td')
			root:attr('align', 'center')
				:css('vertical-align', 'middle')
				:wikitext(c1)
            return tostring(root)
        end
        return ''
    end
    
    local function makerow( c1, c2 )
        local root = mw.html.create('')
        if isnotempty(c1) then
            if isnotempty(c2) then
            	root:tag('td')
					:attr('align', 'center')
					:css('vertical-align', 'middle')
					:wikitext(c1)
				root:tag('td')
					:attr('align', 'center')
					:css('vertical-align', 'middle')
					:wikitext(c2)
            else
            	root:tag('td')
					:attr('colspan', '2')
					:attr('align', 'center')
					:css('vertical-align', 'middle')
					:wikitext(c1)
            end
        elseif isnotempty(c2) then
			root:tag('td')
				:attr('colspan', '2')
				:attr('align', 'center')
				:css('vertical-align', 'middle')
				:wikitext(c2)
        end
        return tostring(root)
    end
    
    local count = 0
    count = count + (isnotempty(cell1) and 1 or 0)
    count = count + (isnotempty(cell2) and 1 or 0)
    count = count + (isnotempty(cell3) and 1 or 0)
    count = count + (isnotempty(cell4) and 1 or 0)

    if(count > 0) then
		local root = mw.html.create('table')
		root:css('width', '100%')
			:css('background', 'transparent')
		if(count > 2) then
			root:tag('tr')
					:wikitext(makerow(cell1, cell2))
			root:tag('tr')
					:wikitext(makerow(cell3, cell4))
		else
			root:tag('tr')
				:wikitext(makecell(cell1))
				:wikitext(makecell(cell2))
				:wikitext(makecell(cell3))
				:wikitext(makecell(cell4))
		end
		return tostring(root)
	else
		return ''
	end
end

local function columns2(cell0, cell1, cell2, cell3, cell4, cell5)
    -- This function implements {{Infobox settlement/columns}} with cell0
    local function makerow( c1 )
		if isnotempty(c1) then
			local root = mw.html.create('tr')
			root:tag('td')
				:attr('align', 'center')
				:css('style', 'vertical-align:middle')
				:wikitext(c1)
			return tostring(root)
		else
			return ''
		end
	end
    
	local count = 0
	count = count + (isnotempty(cell1) and 1 or 0)
	count = count + (isnotempty(cell2) and 1 or 0)
	count = count + (isnotempty(cell3) and 1 or 0)
	count = count + (isnotempty(cell4) and 1 or 0)
	count = count + (isnotempty(cell5) and 1 or 0)

	if(count > 0) then
		local root = mw.html.create('table')
		root:css('width', '100%')
			:css('background', 'transparent')
		local row = root:tag('tr')
		row
			:tag('td')
				:tag('table')
					:css('width', '100%')
					:css('background', 'transparent')
					:wikitext(makerow(cell1))
					:wikitext(makerow(cell2))
					:wikitext(makerow(cell3))
					:wikitext(makerow(cell4))
					:wikitext(makerow(cell5))
        if isnotempty(cell0) then
			row
				:tag('td')
					:attr('align', 'center')
					:css('vertical-align', 'top')
					:wikitext(cell0)
		end
		return tostring(root)
	else
		return cell0
	end
end

local function unitpref(pref, region, unit_type)
    -- This function implements {{Infobox settlement/pref}}
    local pref_impus = { ['imperial'] = 1, ['english'] = 1, ['uk'] = 1, ['us'] = 1, 
        ['u.s.'] = 1, ['standard'] = 1, ['us customary'] = 1, ['u.s. customary'] = 1}
    local pr = (pref and pref:lower()) or ''
    local r = region or ''
    local u = unit_type or ''

    pr = mw.ustring.gsub(pr, '^%s*([a-z].*[a-z\.])%s*$','%1')

    if( pref_impus[pr] ) then
        return 'impus'
    end
    if( mw.ustring.match( r, 'United States' ) ) then
        return 'impus'
    end
    if( mw.ustring.match( r, 'United Kingdom' ) ) then
        return 'impus'
    end
    if( (u .. '_' .. pr ) == 'area_dunam' ) then
        return 'dunam'
    end
    
    return 'metric'
end

local function areadisp(frame, pref, name, mag, ha, km2, sqmi, acre, dunam, percent, link)
    -- This function implements {{Infobox settlement/areadisp}}
    local function formatnum(num)
        return frame:callParserFunction{ name = 'formatnum', args = num }
    end
    
    local metv, metu = '', ''
    local impv, impu = '', ''
    local dunv, dunu = '', ''
    local lstr1, lstr2 = '', ''
    local rndv = 0
    
    pref = pref or ''
    name = name or ''
    mag = mag or ''
    ha = ha or ''
    km2 = km2 or ''
    sqmi = sqmi or ''
    acre = acre or ''
    dunam = dunam or ''
    percent = percent or ''
    link = link or ''
    
    if ( ha ~= '' ) then
        metv = formatnum( ha )
        metu = 'ha'
    elseif ( km2 ~= '' ) then
        metv = formatnum( km2 )
        metu = 'km<sup>2</sup>'
    elseif ( dunam ~= '' ) then
        if (tonumber(dunam) < 1E3) then
            -- convert dunams to hectares
            metv = dunam/10
            metu = 'ha'
            rndv = precision(dunam)+1
            metv = rnd(metv,rndv)
        else
            -- convert dunams to square kilometers
            metv = dunam/1000
            metu = 'km<sup>2</sup>'
            rndv = precision(dunam)+3
            metv = rnd(metv,rndv)
        end
    elseif( acre ~= '' ) then 
        -- convert acres to hectares
        metv = acre*0.4046856422
        metu = 'ha'
        rndv = math.max(precision(acre),-1*order_of_magnitude(metv))
        metv = rnd(metv,rndv)
    elseif( sqmi ~= '' ) then
        -- convert sqmi to km2
        metv = sqmi*2.589988110336
        metu = 'km<sup>2</sup>'
        rndv = math.max(precision(sqmi)-1,-1*order_of_magnitude(metv))
        metv = rnd(metv,rndv)
    end

    if ( acre ~= '' ) then
        impv = formatnum( acre )
        impu = 'acre'
    elseif ( sqmi ~= '' ) then
        impv = formatnum( sqmi )
        impu = 'sq&nbsp;mi'
    elseif (ha ~= '' ) then
        -- convert hectares to acres
        impv = ha/0.4046856422
        impu = 'acre'
        rndv = precision(ha)
        impv = rnd(impv,rndv)
    elseif (km2 ~= '' ) then
        -- convert square kilometres to square miles
        impv = km2/2.589988110336
        impu = 'sq&nbsp;mi'
        rndv = math.max(precision(km2),-1*order_of_magnitude(impv))
        impv = rnd(impv,rndv)
    elseif (dunam ~= '' ) then
        if (tonumber(dunam) < 2589) then
            -- convert dunams to acres
            impv = dunam/4.046856422
            impu = 'acre'
            rndv = math.max(precision(dunam),-1*order_of_magnitude(impv))
            impv = rnd(impv,rndv)
        else
            -- convert dunams to square miles
            impv = dunam/2589.988110336
            impu = 'sq&nbsp;mi'
            rndv = math.max(precision(dunam)+3,-1*order_of_magnitude(impv))
            impv = rnd(impv,rndv)
        end
    end

    if( mw.ustring.match(pref:lower(), '^%s*dunam%s*$') and (dunam == '') ) then
        if( km2 ~= '' ) then
            -- convert square kilometres to dunams
            dunv = km2*1000
            rndv = precision(km2)-3
            dunv = rnd(dunv,rndv)
        elseif( ha ~= '' ) then
            -- convert hectares to dunams
            dunv = ha*10
            rndv = precision(ha)-1
            dunv = rnd(dunv,rndv)
        elseif( sqmi ~= '' ) then
            -- convert square miles to dunams
            dunv = sqmi*2589.988110336
            rndv = math.max(precision(sqmi)-4,-1*order_of_magnitude(dunv))
            dunv = rnd(dunv,rndv)
        elseif( acre ~= '' ) then
            -- convert acres to dunams
            dunv = acre*4.046856422
            rndv = math.max(precision(acre)-1,-1*order_of_magnitude(dunv))
            dunv = rnd(dunv,rndv)
        end
    else
        dunv = formatnum( dunam )
    end
    if( link ~= '' ) then
        dunu = '[[dunum]]'
    else
        dunu = 'dunam'
    end
    
    if( (impu == 'acre') and (tonumber(impv) ~= 1) ) then
        impu = impu .. 's'
    end    
    if( tonumber(dunv) ~= 1 ) then
        dunu = dunu .. 's'
    end
    
    if( metv ~= '' and impv ~= '' ) then
        pref = unitpref(pref, name, 'area')
        if( percent ~= '' ) then
            percent = ' &nbsp;' .. percent .. '%'
        end
        
        if( mag ~= '' ) then
            if( metu == 'ha' ) then
                lstr1 = tostring( order_of_magnitude( metv * 1E4 ) ) 
            else
                lstr1 = tostring( order_of_magnitude( metv * 1E6 ) )
            end
            lstr1 = '[[1_E+' .. lstr1 .. '_m²|'
            lstr2 = ']]'
         end
   
         if( pref == 'impus' ) then
             return string.format('%s&nbsp;%s (%s%s&nbsp;%s%s)%s', 
                 impv, impu, lstr1, metv, metu, lstr2, percent)
         elseif ( pref == 'dunam' ) then
             return string.format('%s&nbsp;%s (%s%s&nbsp;%s%s&nbsp;or&nbsp;%s&nbsp;%s)%s', 
                 dunv, dunu, lstr1, metv, metu, lstr2, impv, impu, percent)
         else
             return string.format('%s%s&nbsp;%s%s (%s&nbsp;%s)%s', 
                 lstr1, metv, metu, lstr2, impv, impu, percent)
         end
     end
end

local function densdisp(frame, pref, name, perkm2, persqmi, pop, ha, km2, sqmi, acre, dunam)
    -- This function implements {{Infobox settlement/densdisp}}
    local function numorzero( num )
        num = num or ''
        num = tonumber(frame:callParserFunction{ name = 'formatnum', args = {num, 'R'}})
        if( num == nil ) then
            return 0
        else
            return num
        end
    end

    local function formatnum(num)
        return frame:callParserFunction{ name = 'formatnum', args = num }
    end
    
    local function formatnumR(num)
        return frame:callParserFunction{ name = 'formatnum', args = {num, 'R'} }
    end

    local metv, metu = '', 'km<sup>2</sup>'
    local impv, impu = '', 'sq&nbsp;mi'
    local rndv = 0
    local perkm2num = tonumber(formatnumR(perkm2 or ''))
    local persqminum = tonumber(formatnumR(persqmi or ''))
    local popnum = tonumber(formatnumR(pop or ''))

    pref = pref or ''
    name = name or ''
    perkm2 = perkm2 or ''
    persqmi = persqmi or ''
    pop = pop or ''
    ha = numorzero(ha)
    km2 = numorzero(km2)
    acre = numorzero(acre)
    sqmi = numorzero(sqmi)
    dunam = numorzero(dunam)
    
    if( (perkm2num == nil) and (persqminum == nil) ) then
       if( mw.ustring.match(perkm2:lower(), '^%s*auto%s*$') or mw.ustring.match(persqmi:lower(), '^%s*auto%s*$') ) then
           if( popnum ~= nil ) then
               if( km2 > 0 ) then
                   metv = popnum/km2
                   rndv = 1 - order_of_magnitude(metv)
                   metv = rnd(metv,rndv)
               elseif( ha > 0 ) then
                   metv = 100*popnum/ha
                   rndv = 1 - order_of_magnitude(metv)
                   metv = rnd(metv,rndv)
               elseif( dunam > 0 ) then
                   metv = 1000*popnum/dunam
                   rndv = 1 - order_of_magnitude(metv)
                   metv = rnd(metv,rndv)
               elseif( acre > 0 ) then
                   metv = (popnum/acre)/0.004046856422
                   rndv = 1 - order_of_magnitude(metv)
                   metv = rnd(metv,rndv)
               elseif( sqmi > 0 ) then
                   metv = (popnum/sqmi)/2.589988110336
                   rndv = 1 - order_of_magnitude(metv)
                   metv = rnd(metv,rndv)
               end
               if( sqmi > 0 ) then
                   impv = popnum/sqmi
                   rndv = 1 - order_of_magnitude(impv)
                   impv = rnd(impv,rndv)
               elseif( acre > 0 ) then
                   impv = 640*popnum/acre
                     rndv = 1 - order_of_magnitude(impv)
                   impv = rnd(impv,rndv)
               elseif( km2 > 0 ) then
                   impv = 2.589988110336*popnum/km2
                   rndv = 1 - order_of_magnitude(impv)
                   impv = rnd(impv,rndv)
               elseif( ha > 0 ) then
                   impv = 258.9988110336*popnum/ha
                   rndv = 1 - order_of_magnitude(impv)
                   impv = rnd(impv,rndv)
               elseif( dunam > 0 ) then
                   impv = 2589.988110336*popnum/dunam
                   rndv = 1 - order_of_magnitude(impv)
                   impv = rnd(impv,rndv)
               end
           end
       end
   elseif( perkm2num ~= nil ) then
       if( persqminum ~= nil ) then
           metv = formatnum( perkm2 )
           impv = formatnum( persqmi )
       else
           metv = formatnum( perkm2 )
           impv = perkm2num*2.589988110336
           rndv = math.max(precision(perkm2num)-1,-1*order_of_magnitude(impv)) 
           impv = rnd(impv,rndv)
       end
    elseif( persqminum ~= nil ) then
        metv = persqminum/2.589988110336
        rndv = math.max(precision(persqminum),-1*order_of_magnitude(metv))
        metv = rnd(metv,rndv)
        impv = formatnum( persqmi )
    end

    if( metv ~= '' and impv ~= '') then
      pref = unitpref(pref, name, 'area')
      if( pref == 'impus' ) then
         return string.format('%s/%s (%s/%s)', impv, impu, metv, metu)
      else
         return string.format('%s/%s (%s/%s)', metv, metu, impv, impu)
      end
    else
      return ''
    end  
end

local function lengthdisp(frame, pref, name, km, m, mi, ft)
    -- This function implements {{Infobox settlement/lengthdisp}}
    local function formatnum(num)
        return frame:callParserFunction{ name = 'formatnum', args = num }
    end
    
    local metv, metu = '', ''
    local impv, impu = '', ''
    pref = pref or ''
    name = name or ''
    m = m or ''
    km = km or ''
    ft = ft or ''
    mi = mi or ''
    
    if ( km ~= '' ) then
        metv = formatnum( km )
        metu = 'km'
    elseif ( m ~= '' ) then
        metv = formatnum( m )
        metu = 'm'
    elseif ( mi ~= '' ) then
        metv = mi*1.609344
        metu = 'km'
        rndv = precision(mi)
        metv = rnd(metv,rndv)
    elseif ( ft ~= '' ) then
        metv = ft*0.3048
        metu = 'm'
        rndv = math.max(precision(ft),-1*order_of_magnitude(metv))
        metv = rnd(metv,rndv)
    end
    
    if ( mi ~= '' ) then
        impv = formatnum( mi )
        impu = 'mi'
    elseif ( ft ~= '' ) then
        impv = formatnum( ft )
        impu = 'ft'
    elseif ( km ~= '' ) then
        impv = km/1.609344
        impu = 'mi'
        rndv = math.max(precision(km),-1*order_of_magnitude(impv))
        impv = rnd(impv,rndv)
    elseif ( m ~= '' ) then
        impv = m/0.3048
        impu = 'ft'
        rndv = precision(m)
        impv = rnd(impv,rndv)
    end
    
    if( impv ~= '' and metv ~= '' ) then
        pref = unitpref(pref, name, 'length')
        if( pref == 'impus' ) then
           return string.format('%s&nbsp;%s (%s&nbsp;%s)', impv, impu, metv, metu)
        else
           return string.format('%s&nbsp;%s (%s&nbsp;%s)', metv, metu, impv, impu)
        end
    else
        return ''
    end    
end

function p.areadisp(frame)
    local args = frame.args
    return areadisp(frame, args['pref'], args['name'], args['mag'], 
        args['ha'], args['km2'], args['sqmi'], args['acre'], args['dunam'], args['percent'], args['link'])
end

function p.densdisp(frame)
    local args = frame.args
    return densdisp(frame, args['pref'], args['name'], 
        args['/km2'], args['/sqmi'], args['pop'], args['ha'], args['km2'], args['sqmi'], args['acre'], args['dunam'])
end

function p.lengthdisp(frame)
    local args = frame.args
    return lengthdisp(frame, args['pref'], args['name'], args['km'], args['m'], args['mi'], args['ft'])
end

function p.link(frame)
    local args = frame.args
    return link(args['link'], args['type'], args['name'])
end

function p.columns(frame)
    local args = frame.args
    if( args[0] and args[0] ~= '' ) then
      return columns2(args[0], args[1], args[2], args[3], args[4], args[5])
    else
      return columns(args[1], args[2], args[3], args[4])
    end
end

return p