-- objects
local Joint       = require('Legacy.Systems.Gen.ShapeLib.Joint')
local Shape       = require('Legacy.Systems.Gen.ShapeLib.Shape')
local Style       = require('Legacy.Systems.Gen.ShapeLib.Style')
-- shapes
local BasicShapes = require('Legacy.Systems.Gen.ShapeLib.BasicShapes')
local Cluster     = require('Legacy.Systems.Gen.ShapeLib.Cluster')
-- warps
require('Legacy.Systems.Gen.ShapeLib.Warp')
-- util
local Parametric = require('Legacy.Systems.Gen.ShapeLib.Parametric')

local Module     = {}

function Module.ConstructionYard(style)
    local shape = Shape()
    local rng = style.rng

    -- ring cluster
    -- (joint @ center of shape,
    -- instead of on a poly,
    -- to guaruntee the shape is perfectly vertical)
    local radius = 2
    local ring = Cluster.GenerateRingSafe(style, radius)
    local joint = Joint()
    joint.pos = Vec3d(0, 0, 0)
    joint.dir = Vec3d(0, 0, 1)
    joint.up = Vec3d(0, 1, 0)
    joint.scale = Vec3d(1, 1, 1)
    local n = rng:getInt(3, 5)
    local spacing = rng:getUniformRange(2, 4)
    shape = Cluster.GenerateLinear(style, n, spacing, ring, joint)

    -- side attachments
    local aabb = shape:getAABB()
    local sc = style:getScaffolding()
    local length = abs(aabb.upper.z - aabb.lower.z)
    local width = abs(aabb.upper.x - aabb.lower.x)
    local height = abs(aabb.upper.y - aabb.lower.y)

    local plane = Cluster.GeneratePlane(style, floor(length), 1, floor(width), 1, sc, joint)
    local plane1 = plane:clone():rotate(math.pi / 2.0, 0, math.pi / 2.0):translate(0, aabb[1].y - 0.5, 0)
    local plane2 = plane:clone():rotate(math.pi / 2.0, 0, math.pi / 2.0):translate(0, aabb[2].y + 0.5, 0)

    local col = Cluster.GeneratePlane(style, n, spacing, floor(height) + 2, 1, sc, joint)
    local col1 = col:clone():rotate(math.pi / 2.0, 0, 0):translate(aabb[1].x, 0, 0)
    local col2 = col:clone():rotate(math.pi / 2.0, 0, 0):translate(aabb[2].x, 0, 0)

    shape:add(plane1, plane2, col1, col2)

    return shape
end

function Module.Core(style)
    local shape = Shape()

    local numRings = style.rng:getInt(1, 7)
    local ringRadius = style.rng:getExp() * 10.0 + 3.0
    local ring = Cluster.GenerateRing(style, ringRadius, true)
    for i = 0, numRings do
        shape:add(
            ring:clone()
            :rotate(style.rng:getAngle(), style.rng:getAngle(), style.rng:getAngle())
        )
    end

    local core = style:getShape():sphereize()
    shape:add(core)

    return shape
end

return Module
