Moduuli:Naapuriasemia WD

Wikipediasta
Siirry navigaatioon Siirry hakuun

Tämän moduulin ohjeistuksen voi tehdä sivulle Moduuli:Naapuriasemia WD/ohje

local p = {}
--Lua code made by Eru aimed at presenting preceding and following subway stations, sorted by geographical order and by service/line number/name. 
--For time being, still in bêta. Original code at https://commons.wikimedia.org/wiki/Module:Adjacent_stations
--If any requests or comments, please add them to (where?)
--Do not copy for time being

-- default params

local defaultLang = mw.language.getContentLanguage().code
local defaultLink = 'fiwiki' -- modify to your local wiki, like frwiki
local size_logo = 12
local showdebug = false
local ignoreCoordinate = false
local linkback
local showsource = false--parameter to help present sources, if they are present in Wikidata
local with_bearing=true--parameter to help decide to calculate with bearing or with classic line direction method (false)

-- module loading

local function loadModule(name, name2)
	local exist, res = pcall(require, name)
	if not exist then
		exist, res = pcall(require, name2)
	end
	return exist and res
end
local wikidata
if defaultLink == 'eowiki' or defaultLink == 'wikidata' or defaultLink == 'ptwiki'  or defaultLink == 'fiwiki' then -- too much incompatibilities in [[Module:Wikidata]]
	wikidata = loadModule( 'Moduuli:Fr:Wikidata' ) -- original code at https://fr.wikipedia.org/wiki/Module:Wikidata
	wikidata.getReferences = nil
	wikidata.sourceStr = nil
else
	wikidata = loadModule( 'Module:Wikidata' ) -- original code at https://fr.wikipedia.org/wiki/Module:Wikidata or https://commons.wikimedia.org/wiki/Module:Wikidata
end

local tools = loadModule( 'Moduuli:Fr:Wikidata/Outils' ) -- original code at https://commons.wikimedia.org/wiki/Module:Wikidata/Tools
local TNT = require 'Moduuli:TNT' -- https://www.mediawiki.org/wiki/Module:TNT

-- compatiblity of [[Module:Wikidata]] on various wiki

wikidata.formatEntity = wikidata.formatEntity -- frwiki
	or wikidata._getLabel -- commons
wikidata.getId = wikidata.getId -- frwiki
	or ( tools and tools.getId ) -- commons
wikidata.getFormattedQualifiers = wikidata.getFormattedQualifiers -- frwiki
	or wikidata.formatStatementQualifiers -- commons
wikidata.sourceStr = wikidata.sourceStr -- frwiki
	or function( sources, hashes ) -- commons
	return sources
end
wikidata.stringTable = wikidata.stringTable -- commons
	or wikidatafr.stringTable -- eowiki
wikidata.getClaims = wikidata.getClaims -- commons
	or wikidatafr.getClaims -- eowiki

-- private functions

local function getMessage(key, ...)
	return TNT.formatInLanguage(defaultLang, 'I18n/Template:Stations-voisines.tab', key, {...}) -- loading of https://commons.wikimedia.org/wiki/Data:I18n/Template:Stations-voisines.tab
end
--from https://commons.wikimedia.org/wiki/Module:Bearing

local function bearing (from_lat, from_long, to_lat, to_long)
	if not (to_lat and to_long) then
		return nil
	end
	local from_lat_rad = math.rad (from_lat);									-- convert degree inputs to radians
	local from_long_rad = math.rad (from_long);
	local to_lat_rad = math.rad (to_lat);
	local to_long_rad = math.rad (to_long);
	
	local delta_long_rad = to_long_rad - from_long_rad;
	local x = math.cos (to_lat_rad) * math.sin (delta_long_rad);
	local y = (math.cos (from_lat_rad) * math.sin (to_lat_rad)) - (math.sin (from_lat_rad) * math.cos (to_lat_rad) * math.cos (delta_long_rad));
	local beta = math.atan2 (x, y);												-- result in radians
	beta = math.deg (beta);														-- convert to degrees
	return (0.0 > beta) and (beta + 360.0) or beta;								-- when beta is negative, add 360 degrees to make a positive bearing
end

--[[--------------------------< E X P O R T S >----------------------------------------------------------------
]]


-- from [[fr:Module:Outils]]

local function trim( texte )
	if type( texte ) == 'string' and texte ~= '' then
		texte = texte:gsub( '^%s*(%S?.-)%s*$', '%1' )
		if texte ~= '' then
			return texte
		end
	end
	return nil
end

local function validTextArg( args, name, ... )
	local texte = trim( args[name] )
	if texte then
		return texte
	end
	if select( '#', ... ) > 0 then
		return validTextArg( args, ... )
	end
	return nil
end

local function extractArgs ( frame )
	if type( frame.getParent ) == 'function' then
		local args = frame:getParent().args
		for k,v in pairs( frame.args ) do
			args[k] = v;
		end
		return args
	else
		return frame
	end
end

-- from [[fr:Module:Wikidata]]

local function getMainId(claim)
	return wikidata.getId(claim.mainsnak)
end

local function entityId(entity)
	if type(entity) == 'string' then
		return entity
	elseif type(entity) == 'table' then
		return entity.id
	end
end

local function addLinkBack(str, id, property)
	if not id or id == '' then
		id = wikidata.getEntityIdForCurrentPage()
	end
	if not id then
		return str
	end
	if type(property) == 'table' then
		property = property[1]
	end
	
	id = entityId(id)

	local class = ''
	if property then
		class = 'wd_' .. string.lower(property)
	end
	local icon = '[[File:Blue pencil.svg|%s|10px|baseline|class=noviewer|link=%s]]'--pencil icon to help modify Wikidata
	local title = getMessage('see-wikidata-value')
	local url = mw.uri.fullUrl('d:' .. id, 'uselang=fr')
	url.fragment = property -- ajoute une #ancre si paramètre "property" défini
	url = tostring(url)
	local v = mw.html.create('span')
		:addClass(class)
		:wikitext(str)
		:tag('span')
			:addClass('noprint wikidata-linkback')
			:wikitext(icon:format(title, url))
		:allDone()
	return tostring(v)
end

-- from [[commons:Module:Wikidata]]

local function getQualifiers(statement, qualifs, params)
	if not statement.qualifiers then
		return nil
	end
	local vals = {}
	for i, j in pairs(qualifs) do
		j = string.upper(j)
		if statement.qualifiers[j] then
			local inserted = false
			if statement.qualifiers[j][1].datatype == 'monolingualtext' then
				local in_preferred_lang
				for _, language in ipairs(fb.fblist(params.lang or defaultlang, true)) do
					for _, snak in ipairs(statement.qualifiers[j]) do
						if isInLanguage(snak, language) then
							in_preferred_lang = snak
							break
						end
					end
					if in_preferred_lang then
						break
					end
				end
				if in_preferred_lang then
					table.insert(vals, in_preferred_lang)
					inserted = true
				end
			end
			if not inserted then
				for _, snak in pairs(statement.qualifiers[j]) do
					table.insert(vals, snak)
				end
			end
		end
	end
	if #vals == 0 then
		return nil
	end
	return vals
end

wikidata.getReferences = wikidata.getReferences or function(statement)
	local cite = loadModule( 'Module:Cite' )
	local isSpecial = wikidata.isSpecial or ( tools and tools.isSpecial )
	if not isSpecial or not cite or not statement.references then
		return ''	
	end
	local frame = mw.getCurrentFrame()
	local sourcestring = ''
	for i, ref in pairs(statement.references) do
		local s
		if ref.snaks.P248 then
			for j, source in pairs(ref.snaks.P248) do
				if not isSpecial(source) then
					local page
					if ref.snaks.P304 and not isSpecial(ref.snaks.P304[1]) then
						page = ref.snaks.P304[1].datavalue.value
					end
					s = cite.citeitem('Q' .. source.datavalue.value['numeric-id'], lang, page)
					s = frame:extensionTag('ref', s)
					sourcestring = sourcestring .. s
				end
			end
		elseif ref.snaks.P854 and not isSpecial(ref.snaks.P854[1]) then
			s = frame:extensionTag('ref', wikidata.formatSnak(ref.snaks.P854[1], {}))
			sourcestring = sourcestring .. s
		end
	end
	return sourcestring
end

-- public functions

function p.Adjacent_stations( id, onlyLineService, rows )
	if not id then
		id = mw.wikibase.getEntityIdForCurrentPage()
	end
	local argsData = { entity = id, property = 'P197' }
	if onlyLineService then
		argsData.qualifier = { 'P1192', 'P81' } -- ligne or service
		argsData.qualifiervalue = onlyLineService
	end
	--localisation principale
	local mainCoordinate = ( not ignoreCoordinate ) and wikidata.stringTable( { entity = id, property = 'P625', numval = 1 } )
	if mainCoordinate and #mainCoordinate > 0 then -- si des coordonnées pour la présente station sont présentes / if coordinates are present for the current subway
		mainCoordinate = mainCoordinate[ 1 ]
	end

	-- ajout d'une ligne dans le tableau / add a line in the table
	local function addLineDetail( lineDetail )
		if lineDetail.color then
			lineDetail.color = 'style="background:#' .. lineDetail.color .. ';" width="1*" |'
		else
			lineDetail.color = ''
		end
		local textBefore = { '| ' }
		local textAfter = { '| ' }
		local textLine = { '| ' }
		if lineDetail.logo then
			for _, logo in ipairs( lineDetail.logo ) do
				textLine[ #textLine + 1 ] = '[[Image:' .. logo .. '|' .. size_logo .. ' px]] '
			end
		end
		textLine[ #textLine + 1 ] = lineDetail.name
		if lineDetail.source then
			textLine[ #textLine + 1 ] = lineDetail.source
		end

		local isTerminus = false
		if lineDetail.after and lineDetail.after ~= '-' then -- no value
			textAfter[ #textAfter + 1 ] = lineDetail.after
			if lineDetail.afterDestination and lineDetail.afterDestination ~= '-' then
				textAfter[ #textAfter + 1 ] = "<br /><small>"
				if lineDetail.after == lineDetail.afterDestination then
					textAfter[ #textAfter + 1 ] = getMessage( 'if_terminus' )
				else
					textAfter[ #textAfter + 1 ] = getMessage( 'towards' )
					textAfter[ #textAfter + 1 ] = " ''"
					textAfter[ #textAfter + 1 ] = lineDetail.afterDestination
					textAfter[ #textAfter + 1 ] = "''"
				end
				textAfter[ #textAfter + 1 ] = "</small>"
			end
			if lineDetail.afterVia and lineDetail.afterVia ~= '-' then
				textAfter[ #textAfter + 1 ] = "<br /><small>"
				textAfter[ #textAfter + 1 ] = getMessage( 'via' )
				textAfter[ #textAfter + 1 ] = " ''"
				textAfter[ #textAfter + 1 ] = lineDetail.afterVia
				textAfter[ #textAfter + 1 ] = "''</small>"
			end
			lineDetail.colorAfter = lineDetail.color
		elseif lineDetail.Y then
			lineDetail.colorAfter = ''
		else
			isTerminus = true
			textLine[ #textLine + 1 ] = "<br /><small>"
			textLine[ #textLine + 1 ] = getMessage( 'terminus' )
			textLine[ #textLine + 1 ] = "</small>"
			lineDetail.colorAfter = ''
		end
		if lineDetail.before and lineDetail.before ~= '-' then -- no value
			textBefore[ #textBefore + 1 ] = lineDetail.before
			if lineDetail.beforeDestination and lineDetail.beforeDestination ~= '-' then
				textBefore[ #textBefore + 1 ] = "<br /><small>"
				if lineDetail.before == lineDetail.beforeDestination then
					textBefore[ #textBefore + 1 ] = getMessage( 'if_terminus' )
				else
					textBefore[ #textBefore + 1 ] = getMessage( 'towards' )
					textBefore[ #textBefore + 1 ] = " ''"
					textBefore[ #textBefore + 1 ] = lineDetail.beforeDestination
					textBefore[ #textBefore + 1 ] = "''"
				end
				textBefore[ #textBefore + 1 ] = "</small>"
			end
			if lineDetail.beforeVia and lineDetail.beforeVia ~= '-' then
				textBefore[ #textBefore + 1 ] = "<br /><small>"
				textBefore[ #textBefore + 1 ] = getMessage( 'via' )
				textBefore[ #textBefore + 1 ] = " ''"
				textBefore[ #textBefore + 1 ] = lineDetail.beforeVia
				textBefore[ #textBefore + 1 ] = "''</small>"
			end
			lineDetail.colorBefore  = lineDetail.color
		else
			isTerminus = true
			textLine[ #textLine + 1 ] = "<br /><small>"
			textLine[ #textLine + 1 ] = getMessage( 'terminus' )
			textLine[ #textLine + 1 ] = "</small>"
			lineDetail.colorBefore  = ''
		end
		local inverted
		--new decision tree with bearings to help decide  how to build the table, provided both neighbours have coordinates, disable it with 'with_bearing'
		if with_bearing and (lineDetail.beforeCoordinate or lineDetail.afterCoordinate) then
			local bearingbefore
			local bearingafter
			local angle
			if lineDetail.beforeCoordinate then
				bearingbefore=bearing ( mainCoordinate.latitude,  mainCoordinate.longitude, lineDetail.beforeCoordinate.latitude, lineDetail.beforeCoordinate.longitude)
			end
			if lineDetail.afterCoordinate then
				bearingafter=bearing ( mainCoordinate.latitude,  mainCoordinate.longitude, lineDetail.afterCoordinate.latitude, lineDetail.afterCoordinate.longitude)
				if bearingbefore and bearingafter then
					angle = 180 - math.abs(math.abs(bearingbefore - bearingafter) - 180)
				end
			end
			if bearingafter==nil and bearingbefore==nil then
				-- bug
			elseif bearingafter==nil then--termini case, only with bearingbefore
				--if bearingbefore<=205 --not too close to 180°if (bearingafter<=45.0 or bearingafter>=225.0)	--lazily heading North
				if(bearingbefore>45.0 and bearingbefore<225.0)	--lazily heading South/East for "before", modified
				then inverted=true
				else inverted=false end
			elseif bearingbefore==nil then
				-- bug
			elseif (bearingbefore<45.0 or bearingbefore>315.0)  	--truely heading North for "before" for 90°
				then
					if (bearingafter>=45.0 and bearingafter<=225.0)	--lazily heading South or East for "after" for 180°
						then if angle>45.0 then inverted=false		--their angle should be more than 45° so it is more of simple direction
						else inverted=true	end							--then ↕
					elseif (bearingbefore<45.0 and bearingafter>225.0)	--before in North and after in East/South
						then if angle>45.0 then inverted=true		--their angle should be more than 45° so it is more of simple direction
						else inverted=false	end
					elseif ( bearingbefore>315.0 and bearingafter<45.0) --before in North and after in North too? bizarre
						then inverted=true
					else inverted=false								--
					end
			elseif (bearingbefore>135.0 and bearingbefore<225.0)	--truely heading South for "before" for 90°
				then
					if (bearingafter<=45.0 or bearingafter>=225.0)	--lazily heading North or East for "after" for 180°
						then if angle>45.0 then inverted=true							--then ↕
							else inverted=false end
					elseif (bearingbefore>=180.0 and bearingafter<135.0)	--probably ┌
						then inverted=false
					elseif ( bearingbefore<=180.0 and bearingafter<225.0) --probably ┐ , hard to tell
						then inverted=false
					else inverted=true
					end

			elseif (bearingbefore>45.0 and bearingbefore<135.0) 	--truely heading West for "before" for 90°
				then
					if (bearingafter>=225.0 or bearingafter<=45.0)--lazily heading East or North for "after" for 180°
						then if angle>45.0 then inverted=true							--then ↕
							else inverted=false end						--then ↔
						else inverted=true							--probably ┌ or ┐
					end
			elseif (bearingbefore>225.0 and bearingbefore<315.0)	--truely heading East for "before" for 90°
				then  if (bearingafter>=45.0 and bearingafter<=225.0)	--lazily heading West or North for "after" for 180°
						then if angle>45.0 then inverted=false							--then ↕
							else inverted=true end						--then ↔
						else inverted=false							--probably ┌ or ┐
					end
			elseif (bearingbefore<135.0)							--lazily heading NorthWest for "before"
				or (bearingafter>135.0)								--lazily heading SouthEast for "after"
				then  inverted=false
			elseif (bearingbefore>=135.0)							--lazily heading SouthEast for "before"
				or (bearingafter<=135.0)							--lazily heading NorthWest for "after"
				then  inverted=true
			elseif bearingbefore>bearingafter
				then inverted=true --cas des bearings presques identiques
			--else inverted=true  --what about those having almost same bearing?
			end
--decision tree without bearing consideration
		elseif lineDetail.beforeCoordinate and lineDetail.afterCoordinate then
			local direction = lineDetail.beforeDirection or lineDetail.afterDirection
			if direction == 'Q679' -- west
				or direction == 'Q684' then -- est
				if lineDetail.beforeCoordinate.longitude and lineDetail.afterCoordinate.longitude
						and lineDetail.beforeCoordinate.longitude > lineDetail.afterCoordinate.longitude then
					inverted = true
				end
			else -- north or south
				if lineDetail.beforeCoordinate.latitude and lineDetail.afterCoordinate.latitude
						and lineDetail.beforeCoordinate.latitude < lineDetail.afterCoordinate.latitude then
					inverted = true
				end
			end
		elseif isTerminus and lineDetail.beforeCoordinate and not lineDetail.after and mainCoordinate then
			local direction = lineDetail.beforeDirection
			if direction == 'Q679' -- west
				or direction == 'Q684' then -- est
				if lineDetail.beforeCoordinate.longitude and mainCoordinate.longitude
						and lineDetail.beforeCoordinate.longitude > mainCoordinate.longitude then
					inverted = true
				end
			else -- north or south
				if lineDetail.beforeCoordinate.latitude and mainCoordinate.latitude
						and lineDetail.beforeCoordinate.latitude < mainCoordinate.latitude then
					inverted = true
				end
			end
		end

		rows[ #rows + 1 ] = '|-'
		if inverted then
			if showdebug then
				textLine[ #textLine + 1 ] = '<br>'
				if lineDetail.afterDirection then
					textLine[ #textLine + 1 ] = lineDetail.afterDirection end
					textLine[ #textLine + 1 ] =	'ß of after'
			--	if bearingafter then	textLine[ #textLine + 1 ] = bearingafter end
				textLine[ #textLine + 1 ] = ' <=> '
				if lineDetail.beforeDirection then
					textLine[ #textLine + 1 ] = lineDetail.beforeDirection end
					textLine[ #textLine + 1 ] =	'ß of before'
			--	if bearingbefore then	textLine[ #textLine + 1 ] =	bearingbefore end
			end
			rows[ #rows + 1 ] = table.concat( textAfter )
			rows[ #rows + 1 ] = '| ' .. lineDetail.colorAfter
			rows[ #rows + 1 ] = table.concat( textLine )
			rows[ #rows + 1 ] = '| ' .. lineDetail.colorBefore
			rows[ #rows + 1 ] = table.concat( textBefore )
		else
			if showdebug then
				textLine[ #textLine + 1 ] = '<br>'
				if lineDetail.beforeDirection then
					textLine[ #textLine + 1 ] = lineDetail.beforeDirection	end
					textLine[ #textLine + 1 ] =	'ß before'
			--	if bearingbefore and bearingafter  then	textLine[ #textLine + 1 ] =	bearingbefore end

				textLine[ #textLine + 1 ] = ' ― '
				if lineDetail.afterDirection then
					textLine[ #textLine + 1 ] = lineDetail.afterDirection end
				textLine[ #textLine + 1 ] =	'ß after'
			--	if bearingbefore and bearingafter  then	textLine[ #textLine + 1 ] =	bearingafter end
			end
			rows[ #rows + 1 ] = table.concat( textBefore )
			rows[ #rows + 1 ] = '| ' .. lineDetail.colorBefore
			rows[ #rows + 1 ] = table.concat( textLine )
			rows[ #rows + 1 ] = '| ' .. lineDetail.colorAfter
			rows[ #rows + 1 ] = table.concat( textAfter )
		end
	end

	local claims = wikidata.getClaims( argsData )
	local function getClaimDetail( claim )
		claim.lineid = wikidata.getId( claim.currentline )
		claim.lineName = wikidata.formatSnak( claim.currentline, { link = defaultLink } )
		if not claim.lineName or claim.lineName == '-' then -- no value
			claim.lineName = ''
		end
		local routenumber = wikidata.formatStatements( { entity = claim.lineid, property = 'P1671', numval = 1 } )
		if routenumber then
			claim.sortKey = tonumber( routenumber ) -- 570000
				or tonumber( tostring( routenumber:gsub( ' ', '' ) ) ) -- 655 000
				or routenumber:upper() -- KBS 566
		else
			claim.sortKey = claim.lineName:upper()
		end
	end

	if claims and #claims > 0 then
		-- récupération des données de bases et de tri des lignes / recovery of basic data and line sorting
		local newClaims = { }
		local defaultSortKey = 1
		for _, claim in ipairs( claims ) do
			claim.defaultSortKey = defaultSortKey
			defaultSortKey = defaultSortKey + 1
			local currentlines = getQualifiers( claim, { 'P1192', 'P81' }, { } ) -- ligne or service
			if currentlines and #currentlines > 0 then
				for _,currentline in ipairs( currentlines ) do
					local newClaim = mw.clone( claim )
					newClaim.currentline = currentline
					getClaimDetail( newClaim )
					if not onlyLineService or onlyLineService == newClaim.lineid then
						newClaims[ #newClaims + 1 ] = newClaim
					end
				end
			else
				claim.lineName = ''
				claim.sortKey = claim.lineName:upper()
				newClaims[ #newClaims + 1 ] = claim
			end
		end
		table.sort( newClaims,
			function( c1, c2 )
				if c1.sortKey == c2.sortKey then
					return c1.defaultSortKey < c2.defaultSortKey
				elseif type( c1.sortKey ) == 'number' and type( c2.sortKey ) == 'number' then
					return c1.sortKey < c2.sortKey
				else
					return tostring( c1.sortKey ) < tostring( c2.sortKey )
				end
			end
		)

		-- parcours de toutes les gares et stations / loop of all stations
		local lineDetail = { }
		for _, claim in ipairs( newClaims ) do
			-- nouvelle ligne
			if claim.lineName ~= lineDetail.name then
				if lineDetail.name ~= nil then
					addLineDetail( lineDetail )
				end
				lineDetail = { }
				lineDetail.name = claim.lineName
				if claim.currentline then
					lineDetail.color = wikidata.formatStatements( { entity = claim.lineid, property = 'P465', numval = 1} )
					lineDetail.logo = wikidata.stringTable( { entity = claim.lineid, property = 'P154' } )
				end
				if showsource then
					lineDetail.source = wikidata.sourceStr( wikidata.getReferences(claim) )
				end
			end

			local station = wikidata.formatStatement( claim, { link = defaultLink }  )
			local destination = wikidata.getFormattedQualifiers( claim, { 'P5051' }, { conjtype = getMessage( 'or', ' ' ), link = defaultLink } )
			local via = wikidata.getFormattedQualifiers( claim, { 'P2825' }, { conjtype = getMessage( 'and' ), link = defaultLink } )
			local coordinate = ( not ignoreCoordinate ) and wikidata.stringTable( { entity = getMainId( claim ), property = 'P625', numval = 1 } )
			local terminusDirection
			if claim.lineid and coordinate and #coordinate > 0 then -- si des coordonnées sont présentes / if coordinates are present
				coordinate = coordinate[ 1 ]
				local terminusDirections = wikidata.getClaims( { entity = claim.lineid, property = 'P559', showqualifier = 'P560' } ) -- récupérer la liste des terminus et des directions de la ligne
				if terminusDirections and #terminusDirections > 0 then
					local terminus = getQualifiers( claim, { 'P5051' } ) -- récupérer les terminus de la connexion en cours / retrieve the terminus of the current connection
					local terminusQid = { }
					if terminus then
						for i, t in ipairs( terminus ) do
							local tid = wikidata.getId( t )
							if tid then
								terminusQid[ tid ] = true
							end
						end
					end
					for _, td in ipairs( terminusDirections ) do
						local d = wikidata.getFormattedQualifiers( td, { 'P560' }, { displayformat = 'raw' } )
						local t = getMainId( td )
						if not terminusDirection and d and terminusQid[ t ] then -- si ce terminus de la ligne fait partie des terminus de ma connexion, prendre cette direction
							terminusDirection = d -- plusieurs résultats possibles, prendre le premier / several possible result, take the first
						end
					end
				end
			end

			if not lineDetail.before then -- station 1
				lineDetail.before = station
				lineDetail.beforeDestination = destination
				lineDetail.beforeVia = via
				lineDetail.beforeCoordinate = coordinate
			--	lineDetail.beforeBearing=bearingbefore does not work, why?
				lineDetail.beforeDirection = terminusDirection
			elseif not lineDetail.after then -- station 2
				lineDetail.after = station
				lineDetail.afterDestination = destination
				lineDetail.afterVia = via
				lineDetail.afterCoordinate = coordinate
			--	lineDetail.afterBearing=bearingafter does not work, why?
				lineDetail.afterDirection = terminusDirection
			else -- station 3 > nouvelle ligne dans le tableau
				local newLineDetail = { }
				newLineDetail.name = lineDetail.name
				newLineDetail.color = lineDetail.color
				newLineDetail.logo = lineDetail.logo
				newLineDetail.before = station
				newLineDetail.beforeDestination = destination
				newLineDetail.beforeVia = via
				newLineDetail.beforeCoordinate = coordinate
				newLineDetail.beforeDirection = terminusDirection
				newLineDetail.Y = true
				addLineDetail( lineDetail )
				lineDetail = newLineDetail
			end
		end
		addLineDetail( lineDetail ) -- ajout de la dernière ligne construite / addition of the last line constructed

		local lb = ''
		if linkback ~= '-' then
			lb = '[[d:' .. id  .. '#P197|' .. getMessage( 'edit_wikidata' ) .. ']]'
			rows[ #rows + 1 ] = '|-'
			rows[ #rows + 1 ] = '| class="noprint navigation-not-searchable tfoot" colspan="5" | ' .. lb
		end
		return true
	else
		return false
	end
end

function p.main( frame )
	local rows = {}
	local args = extractArgs( frame )
	local id = validTextArg( args, 1, 'id', 'wikidata', 'entity' )
	local onlyLineService = validTextArg( args, 2, 'ligne', 'line', 'service' )
	linkback = validTextArg( args, 'linkback' )
	local ssource = validTextArg( args, 'showsource' )
	if ssource and ( ssource == '-' or ssource == 'non' or ssource == 'no' or ssource == 'false' ) then
		showsource = false
	end
	local title = validTextArg( args, 'titre', 'title', 3 ) or ''
	if id and title == '' then
		title = wikidata.formatEntity( id , { link = defaultLink } )
		if linkback ~= '-' and defaultLink ~= 'wikidata' then
			title = addLinkBack( title, id, 'P197' )
			linkback = '-'
		end
	elseif title == '-' then
		title = ''
	end
	ignoreCoordinate = validTextArg( args, 'ignore coordinate', 'ignore coordonnées' )
	showdebug = validTextArg( args, 'debug' ) -- pour les tests uniquement / for testing only

	rows[ #rows + 1 ] = '{| class="wikitable adjacent-stations"'
	rows[ #rows + 1 ] = '! scope=col | ' .. getMessage( 'station_before', '<abbr title="', '">', '</abbr> <abbr title="', '">', '</abbr> ', ' <abbr title="', '">', '</abbr> ')
	rows[ #rows + 1 ] = '! scope=col colspan="3" | ' .. title
	rows[ #rows + 1 ] = '! scope=col | ' .. getMessage( 'station_after', '<abbr title="', '">', '</abbr> <abbr title="', '">', '</abbr> ', ' <abbr title="', '">', '</abbr> ' )

	local found = p.Adjacent_stations( id, onlyLineService, rows )

	if found then
		rows[ #rows + 1 ] = '|}'
		return table.concat( rows, '\n' )
	else
		return nil
	end
end

return p