-- ***********************************************************************
--
-- 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: sean@conman.org
-- ***********************************************************************
-- 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