-- Search and display the book pages from the TOC page, in order to create a printable version and a previous / next navigation.
debug = false
include_book_subpages_only = true
do_not_evaluate_each_chapter = false
local p = {}
ModuleTnt = require('Module:TNT')
Error = ModuleTnt.format('I18n/Module:Printable version', 'error_invalid_toc')
Beginning1 = ModuleTnt.format('I18n/Module:Printable version', 'header_notice')
Beginning2 = ModuleTnt.format('I18n/Module:Printable version', 'header_cover')
Break = ModuleTnt.format('I18n/Module:Printable version', 'page_break')
Ending1 = ModuleTnt.format('I18n/Module:Printable version', 'footer_license')
Ending2 = ModuleTnt.format('I18n/Module:Printable version', 'footer2')
templateLeft  = ModuleTnt.format('I18n/Module:Printable version', 'template_left')
templateRight = ModuleTnt.format('I18n/Module:Printable version', 'template_right')
TOC = ModuleTnt.format('I18n/Module:Printable version', 'TOC')
sep = ModuleTnt.format('I18n/Module:Printable version', 'subpage_separator')
page_before = ModuleTnt.format('I18n/Module:Printable version', 'page_before')
page_after = ModuleTnt.format('I18n/Module:Printable version', 'page_after')
function p._escapePattern(pattern)
    return mw.ustring.gsub(pattern, "([%(%)%.%%%+%-%*%?%[%^%$%]])", "%%%1");
end
function p.displays_book(frame)
    if not debug then Error = '' end
    if frame == nil then return '' end
    if frame.args == nil then return '' end
    if frame.args[1] == nil then return '' end
    local BookName = frame.args[1]
    if (BookName ~= nil and mw.text.trim(BookName) ~= '') then
        title = mw.title.new(BookName)
        if frame.args[2] ~= nil and frame.args[2] ~= '' then
            BookName = frame.args[2]
        else
            if mw.ustring.find(BookName, sep .. TOC, 1, true) ~= nil then BookName = mw.ustring.gsub(BookName, "^(.*)" .. sep .. TOC .. "$", "%1") end
        end
        if frame.args[3] ~= nil then include_book_subpages_only = false end
    else
        return Error
    end
    if frame.args[4] ~= nil and frame.args[4] ~= '' then do_not_evaluate_each_chapter = true end
    if (title == nil or title == '') then return Error end
    text = title.getContent(title)
    if (text == nil or text == '') then return Error end
    -- Book subpages titles normalization to absolute names
    local lines_ = mw.text.split(text, "\n")
    local fullPageName
    local PrintVersion = {}
    if (page_before ~= '') then
        -- Add book header
        fullPageName = BookName .. sep .. page_before
        ChapterTitle = mw.title.new(fullPageName)
        if (ChapterTitle ~= nil and ChapterTitle.exists) then
            -- Title should be defined in the page itself
            table.insert(PrintVersion, frame:expandTemplate{ title = ':' .. fullPageName } .. '\n\n')
        end
    end
    -- Add book chapters
    for i,v in ipairs(lines_) do
        if mw.text.trim(v) ~= '' then
            fullPageName = p.getFullPageName(BookName, v)
            if fullPageName ~= nil then
                ChapterTitle = mw.title.new(fullPageName)
                if (ChapterTitle ~= nil and (do_not_evaluate_each_chapter or ChapterTitle.exists)) then
                    PageName = p.getSubpageName(BookName, fullPageName)
                    if (PageName ~= nil and PageName ~= '') then
                        if Break ~= "" then table.insert(PrintVersion, frame:expandTemplate{title = Break}) end
                            table.insert(PrintVersion, '\n\n=' .. PageName .. '=\n')
                    end
                    table.insert(PrintVersion, frame:expandTemplate{ title = ':' .. fullPageName } .. '\n\n')
                else
                    if debug then table.insert(PrintVersion, 'Missing subpage "' .. fullPageName .. '" on line "' .. v .. '" for the book: ' .. BookName .. '\n\n') end
                end
            end
        end
    end
 
    if (page_after ~= '') then
        -- Add book footer
        fullPageName = BookName .. sep .. page_after
        ChapterTitle = mw.title.new(fullPageName)
        if (ChapterTitle ~= nil and ChapterTitle.exists) then
            -- Title should be defined in the page itself
            table.insert(PrintVersion, frame:expandTemplate{ title = ':' .. fullPageName } .. '\n\n')
        end
    end
    Templates1 = ""
    if Beginning1 ~= "" then Templates1 = Templates1 .. frame:expandTemplate{title = Beginning1} .. '\n' end
    if Beginning2 ~= "" then Templates1 = Templates1 .. frame:expandTemplate{title = Beginning2} .. '\n' end
    Templates2 = ""
    if Ending1 ~= "" then Templates2 = Templates2 .. frame:expandTemplate{title = Ending1} .. '\n' end
    if Ending2 ~= "" then Templates2 = Templates2 .. frame:expandTemplate{title = Ending2} .. '\n' end
    return Templates1 .. table.concat(PrintVersion, "\r\n") .. Templates2
end
function p.extract_fullPageName(frame)
    if frame == nil then return '' end
    if frame.args == nil then return '' end
    if frame.args[1] == nil then return '' end
    if frame.args[2] == nil then return '' end
    return p.getFullPageName(frame.args[1], frame.args[2])
end
function p.getFullPageName(BookName, chapter)
    if (BookName ~= nil and mw.text.trim(BookName) ~= '') or (chapter ~= nil and mw.text.trim(chapter) ~= '') then
        BookName = mw.text.trim(BookName)
        chapter = mw.text.trim(chapter)
        BookName = mw.ustring.gsub(BookName, "_", " ")
        chapter = mw.ustring.gsub(chapter, "_", " ")
    else
        if debug then chapter = 'Incorrect book or chapter name' else chapter = '' end
    end
", BookName)
", "%1")
", "" .. BookName .. sep .. "%1")
", "" .. BookName .. sep .. "%1")
    chapter = mw.ustring.gsub(chapter, " *%[%[Image:[^%]]+%]%]", "")
", "")
    chapter = mw.ustring.gsub(chapter, "^[%#%*:; ]*", "")
    chapter = mw.ustring.gsub(chapter, "%[%[%.%.?/", "[[" .. BookName .. sep)
    chapter = mw.ustring.gsub(chapter, "%[%[/", "[[" .. BookName .. sep)
    chapter = mw.ustring.gsub(chapter, "%/%]%]", "]]")
    chapter = mw.ustring.gsub(chapter, "%/$", "")
    if mw.ustring.find(chapter, "%[%[") ~= nil then
        -- Pages titles extraction from the TOC
        if mw.ustring.find(chapter, "%|") == nil or (mw.ustring.find(chapter, "%]") ~= nil and mw.ustring.find(chapter, "%|") > mw.ustring.find(chapter, "%]")) then
                Ending = "%]"
        else
                if mw.ustring.find(chapter, "%/%|") == nil or mw.ustring.find(chapter, "%/%|") > mw.ustring.find(chapter, "%|") then
                    Ending = "%|"
            else
                    Ending = "%/%|"
            end
        end
        chapter = mw.text.split(chapter, Ending)[1]   -- extraction of the line beginning
        --chapter = mw.text.split(chapter, "%[%[")[2]
        chapter = mw.ustring.gsub(chapter, "[^%[]*%[%[(.*)", "%1") -- brackets and pipes removal
        if chapter == BookName or chapter == BookName .. sep or mw.ustring.find(chapter, "%#") ~= nil then
            if debug then chapter = 'Chapter = ' .. chapter .. ' => book name or another subpage name with Ending = ' .. Ending else chapter = '' end
        else
            if include_book_subpages_only then
                -- Book subpages only (and ignoring the other links like "see also")
                if mw.ustring.find(chapter, BookName .. sep, 1, true) == nil then
                    if debug then chapter = "No book subpage into the internal link: '" .. chapter .. "' doesn't include '" .. BookName .. sep .. "'" else chapter = '' end
                end
            end
        end
    else
        if debug then chapter = "No internal link for: " .. chapter .. "\n" else chapter = '' end
    end
    return chapter
end
function p.getSubpageName(bookName, fullPageName)
    k, v = mw.ustring.gsub(fullPageName, '^' .. p._escapePattern(bookName .. sep), '')
    return k
end
function p.extract_subpageName(frame)
    if frame == nil then return '' end
    if frame.args == nil then return '' end
    if frame.args[1] == nil then return '' end
    if frame.args[2] == nil then return '' end
    return p.getSubpageName(frame.args[1], frame.args[2])
end
function p.displays_footer(frame)
    if not debug then Error = '' end
    if frame == nil then return "" end
    if frame.args == nil then return "" end
    if frame.args[1] == nil then return "" end
    local footer = {}
    local BookName = frame.args[1]
    if (BookName ~= nil and mw.text.trim(BookName) ~= "") then
        title = mw.title.new(BookName)
        if mw.ustring.find(BookName, sep .. TOC, 1, true) ~= nil then BookName = mw.ustring.gsub(BookName, "^(.*)" .. sep .. TOC .. "$", "%1") end
    else
        return Error
    end
    local currentPageName
    if frame.args[2] ~= nil and frame.args[2] ~= '' then
        currentPageName = frame.args[2]
    else
        currentPageName = p.getSubpageName(BookName, mw.title.getCurrentTitle().fullText)
    end
    if (currentPageName ~= nil and mw.text.trim(currentPageName) ~= "") then 
        currentPageName = mw.text.trim(currentPageName)
    else
        return Error
    end
    if debug then table.insert(footer, " currentPageName = " .. currentPageName .. "\n") end
    if (title == nil or title == "") then return Error end
    text = title.getContent(title)
    if (text == nil or text == "") then return Error end
    if frame.args[3] ~= nil and frame.args[3] ~= '' then
        if frame.args[3] == 'programming' then
            if debug then table.insert(footer, " skin=programming\n\n") end
            templateLeft = ''
        end
    end
    -- Book subpages titles normalization to absolute names
    local lines_ = mw.text.split(text, "\n")
    local previousChapter = ""
    local found = false
    local fullPageName
    local homepage = false
    local subpageName
    local rawFullPageName
    if (currentPageName == BookName) then
        if debug then table.insert(footer, " homepage\n") end
        homepage = true
    end
    for i, v in ipairs(lines_) do
        rawFullPageName = mw.text.trim(v)
        if rawFullPageName ~= '' then
            fullPageName = p.getFullPageName(BookName, rawFullPageName)
            if debug then
                if mw.ustring.find(fullPageName, "No internal link") ~= nil then
                    fullPageName = nil
                else
                    table.insert(footer, " research into: " .. rawFullPageName .. "\n")
                    table.insert(footer, " extraction of: " .. fullPageName .. "\n")
                end
            end
            if fullPageName ~= nil then
                if mw.ustring.find(fullPageName, BookName .. sep, 1, true) == nil then
                    if debug then table.insert(footer, " replacement of " .. fullPageName .. " by " .. BookName .. sep .. fullPageName .. "\n") end
                    fullPageName = BookName .. sep .. fullPageName
                end
                ChapterTitle = mw.title.new(fullPageName)
                if (ChapterTitle ~= nil and ChapterTitle.exists) then
                    subpageName = p.getSubpageName(BookName, fullPageName)
                    if debug then table.insert(footer, " cut subpage: " .. subpageName .. "\n") end
                    if (subpageName ~= nil and subpageName ~= "") then
                        if found == true or homepage == true then
                            if debug then table.insert(footer, "Previous & next chapter insertion\n") end
                            if homepage == false then
                                if previousChapter == "" then
                                    theTemplateLeft, nb = mw.ustring.gsub(templateLeft, "printf", BookName .. "|" .. TOC)
                                else
                                    theTemplateLeft, nb = mw.ustring.gsub(templateLeft, "printf", BookName .. sep .. previousChapter .. "|" .. previousChapter)
                                end
                                table.insert(footer, theTemplateLeft)
                            end
                            theTemplateRight, nb = mw.ustring.gsub(templateRight, "printf", BookName .. sep .. subpageName .. "|" .. subpageName)
                            table.insert(footer, theTemplateRight)
                            break
                        elseif subpageName == currentPageName then
                            if debug then table.insert(footer, "Page '" .. currentPageName .. "' found\n\n") end
                            found = true
                        elseif fullPageName ~= "" then
                            if debug then table.insert(footer, " " .. subpageName .. " is different from " .. currentPageName .. "\n") end
                            previousChapter = subpageName
                        else
                            if debug then table.insert(footer, "The current page '" .. subpageName .. "' is not '" .. currentPageName .. "'") end
                        end
                    end
                else
                    if debug then table.insert(footer, "The page '" .. fullPageName .. "' doesn't exist, for '" .. currentPageName .. "'\n\n") end
                end
            end
        end
    end
    if found == true and table.getn(footer) == 0 then
        if debug then table.insert(footer, "No next chapter\n") end
        theTemplateLeft, nb = mw.ustring.gsub(templateLeft, "printf", BookName .. sep .. previousChapter .. "|" .. previousChapter)
        table.insert(footer, theTemplateLeft)
        theTemplateRight, nb = mw.ustring.gsub(templateRight, "printf", BookName .. "|" .. TOC)
        table.insert(footer, theTemplateRight)
    end
    return table.concat(footer, "")
end
return p