-- ***********************************************************************
--
-- Module to genmerate a B-movie plot.
-- Copyright 2019 by Sean Conner.
--
-- This program is free software: you can redistribute it and/or modify it
-- under the terms of the GNU General Public License as published by the
-- Free Software Foundation, either version 3 of the License, or (at your
-- option) any later version.
--
-- This program is distributed in the hope that it will be useful, but
-- WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
-- Public License for more details.
--
-- You should have received a copy of the GNU General Public License along
-- with this program.  If not, see <http://www.gnu.org/licenses/>.
--
-- Comments, questions and criticisms can be sent to: [email protected]
-- ***********************************************************************
-- luacheck: globals handler
-- luacheck: ignore 611

local randomseed = require "org.conman.math".randomseed
local str        = require "org.conman.string"
local abnf       = require "org.conman.parsers.abnf"
local lpeg       = require "lpeg"
local io         = require "io"
local math       = require "math"
local string     = require "string"
local table      = require "table"
local ipairs     = ipairs
local require    = require
local tonumber   = tonumber
local _VERSION   = _VERSION

if _VERSION == "Lua 5.1" then
 module("movie")
else
 _ENV = {}
end

-- ***********************************************************************

local FILES do
 local function readlist(filename)
   local list = {}
   for line in io.lines(filename) do
     table.insert(list,line)
   end
   return list
 end

 -- ===========================================================

 local filename = require "CONFIG".movie
 local f        = io.open(filename,"r")
 local data     = f:read("*a")
 f:close()

 local Carg = lpeg.Carg
 local Cc   = lpeg.Cc
 local Cg   = lpeg.Cg
 local Cs   = lpeg.Cs
 local Ct   = lpeg.Ct
 local P    = lpeg.P
 local R    = lpeg.R

 local token  = R"!~"^1
 local cmd    = P"BaseDir:"        * abnf.WSP^0 * Cg(token,'basedir')    * abnf.CRLF
              + P"Male-Names:"     * abnf.WSP^0 * Cg(token,'males')      * abnf.CRLF
              + P"Female-Names:"   * abnf.WSP^0 * Cg(token,'females')    * abnf.CRLF
              + P"Family-Names:"   * abnf.WSP^0 * Cg(token,'family')     * abnf.CRLF
              + P"Adjectives:"     * abnf.WSP^0 * Cg(token,'adjective')  * abnf.CRLF
              + P"Mission:"        * abnf.WSP^0 * Cg(token,'mission')    * abnf.CRLF
              + P"Occupation:"     * abnf.WSP^0 * Cg(token,'occupation') * abnf.CRLF
              + P"Double-Mission:" * abnf.WSP^0 * Cg(token,'dmission')   * abnf.CRLF
              + P"Template:"       * abnf.WSP^0 * Cg(token,'template')   * abnf.CRLF
              + R" ~"^0                                                  * abnf.CRLF
 local parser = Ct(cmd^0)
 local rebase = Cs((-P"/" * Carg(1) * Cc'/')^-1 * P(1)^1)

 FILES            = parser:match(data)
 FILES.males      = readlist(rebase:match(FILES.males,     1,FILES.basedir))
 FILES.females    = readlist(rebase:match(FILES.females,   1,FILES.basedir))
 FILES.family     = readlist(rebase:match(FILES.family,    1,FILES.basedir))
 FILES.adjective  = readlist(rebase:match(FILES.adjective, 1,FILES.basedir))
 FILES.mission    = readlist(rebase:match(FILES.mission,   1,FILES.basedir))
 FILES.occupation = readlist(rebase:match(FILES.occupation,1,FILES.basedir))
 FILES.dmission   = readlist(rebase:match(FILES.dmission,  1,FILES.basedir))
end

-- ***********************************************************************

local function pick_unique(list)
 local p1,p2

 p1 = list[math.random(#list)]
 repeat
   p2 = list[math.random(#list)]
 until p1 ~= p2

 return { p1 , p2 }
end

-- ***********************************************************************

local article = lpeg.S"BCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz" / "a"
             + lpeg.P"one" / "a"
             + lpeg.Cc'an'

function handler(req)
 local config  = require "CONFIG"
 local handler = require "handler"
 local seed    = randomseed(tonumber(req))
 local bytes   = 0

 local function write(fmt,...)
   local s = string.format(fmt,...)
   io.stdout:write(s)
   bytes = bytes + #s
 end

 local hero       = pick_unique(FILES.males)
 local heroine    = pick_unique(FILES.females)
 local lastname   = pick_unique(FILES.family)
 local madj       = pick_unique(FILES.adjective)
 local fadj       = pick_unique(FILES.adjective)
 local occupation = pick_unique(FILES.occupation)
 local mission    = pick_unique(FILES.mission)
 local title      = FILES.dmission[math.random(#FILES.dmission)]

 local man = str.template(
   string.format(
       "%s %s %s is %s %s %s %s %s",
       hero[1],hero[2],lastname[1],
       article:match(madj[1]),madj[1],madj[2],
       occupation[1],
       mission[1]
   ),
   { his = "his" , her = "his" , he = "he" , she = "he" }
 )

 local woman = str.template(
   string.format(
       "%s %s %s is %s %s %s %s %s",
       heroine[1],heroine[2],lastname[2],
       article:match(fadj[1]),fadj[1],fadj[2],
       occupation[2],
       mission[2]
   ),
   { his = "her" , her = "her" , he = "she" , she = "she" }
 )

 local story  = string.format("%s %s And together, they must %s",man,woman,title)
 local output = str.wrapt(story,68)

 write(handler.INFO { handler.INFO , "" })
 write(handler.INFO { handler.INFO , "     -- The Quick and Dirty B-Movie Plot Generator --" })
 write(handler.INFO { handler.INFO , "" })
 write(handler.INFO { handler.INFO , "Only the finest script writers were hired to come up with thie plot:" })
 write(handler.INFO { handler.INFO , "" })

 for _,line in ipairs(output) do
   write(handler.INFO { handler.INFO , line })
 end

 write(handler.INFO { handler.INFO , "" })

 local port do
   if config.interface.port == 70 then
     port = ""
   else
     port = string.format(":%d",config.interface.port)
   end
 end

 local selector = string.format("Movie:%u",seed)
 local url      = string.format("gopher://%s%s/1%s",config.interface.hostname,port,selector)

 write(handler.INFO { handler.INFO , "Link for this B-Movie Plot:" })
 write(handler.DIR  { handler.DIR  , url , selector })

 return bytes
end

-- ***********************************************************************

if _VERSION >= "Lua 5.2" then
 return _ENV
end