local settings = minetest.settings
local debug = settings:get_bool("goblins_debug", false)

-- 1 in n chance for goblin lairs to replace dungeons on mapgen
local goblins_lair_chance =
    tonumber(settings:get("goblins_lair_chance") or 2) 
if goblins_lair_chance == 0 then return end

-- Maximum elevation for goblin lairs in dungeons, 0 = no maximum
local goblins_lair_elev_max =
    tonumber(settings:get("goblins_lair_elev_max") or -30)

-- Minimum elevation for goblin lairs in dungeons, 0 = no minimum
local goblins_lair_elev_min =
    tonumber(settings:get("goblins_lair_elev_min") or -5000)

-- This is only effective in MCx based games like VoxeLibre and Mineclonia
local goblins_lair_overworld_only =
   settings:get_bool("goblins_lair_overworld_only", true)

if  goblins_lair_overworld_only and
    goblins.compat_mode == "mc2" and
    goblins_lair_elev_min <= mcl_vars.mg_overworld_min then
    
      goblins_lair_elev_min = mcl_vars.mg_overworld_min

end

local function vtos(input)
   return dump(input):gsub("\r?\n?%s", " ")
end

local setting_check

if
   goblins_lair_chance ~= 0 
   
then
  setting_check = 1


    --look for mapgen generated dungeons
    if not goblins.db_fields["dungeons"] then
      goblins.db_write("dungeons",{})
    end

    minetest.set_gen_notify("dungeon")

    local dungeons = {}


 -- print("lair_chance: " ..goblins_lair_chance .. ", lair_elev_max: " .. goblins_lair_elev_max ..", lair_elev_min "..goblins_lair_elev_min)

    local water_source
    local lava_source
    local mossycobble = goblins.comp.default.mossycobble
    local dirt_grass

    local function grass(size)
              if type(goblins.comp.default.grass) == "table" then
                  return goblins.comp.default.grass[1](size)

              else
                  return goblins.comp.default.grass
              end
    end
 -- print("grass = " ..vtos(grass(5)))

    local function gob_mushroom(size)
      size = size or 4
      return "goblins:mushroom_goblin"..tostring(math.random(size))
    end
 -- print( gob_mushroom(4).." "..gob_mushroom(4).." "..gob_mushroom(4).." "..gob_mushroom(4))

    local slab_mossycobble = goblins.comp.default.slab_mossycobble
    local dg_replace = {"group:water", "group:cracky","group:pickaxey","group:shovely","group:sand" }

 -- print("\n***checking for water source***\n")
    --if #minetest.registered_nodes >= 1 then
     -- print(#minetest.registered_nodes.." nodes registered")
    --end

        for k in pairs(minetest.registered_nodes) do  
          --print(k)
            if string.find(k, ":water_source") then
                water_source = k
             -- print("water: " ..  k)
            end

            if string.find(k, ":lava_source") then
              lava_source = k
           -- print("lava: " ..  k)
            end

            if string.find(k, ":dirt_with_grass") then
              dirt_grass = k
           -- print("dirt_grass: " ..  k)
            end

        end


  minetest.register_on_generated(function(minp, maxp, blockseed)

      local dg = minetest.get_mapgen_object("gennotify")
      local chest_node = goblins.comp.default.chest
      local ring_iter = {"goblins:moss", water_source, "goblins:moss"}
      local cur_dg

      if dg and dg.dungeon and #dg.dungeon > 1  then
         -- print("dungeon elevation of " .. vtos(vector.new(dg.dungeon[#dg.dungeon])) .. "detected")
            cur_dg = vector.new(dg.dungeon[#dg.dungeon])
            --print("cur_dg: " .. vtos(cur_dg))
      end

      local dg_check
      if cur_dg and
         cur_dg.y <= goblins_lair_elev_max or
         goblins_lair_elev_max == 0 then 
          if
            cur_dg.y >= goblins_lair_elev_min or
            goblins_lair_elev_min == 0 then
            dg_check = 1
          else
            dg_check = nil
          end
        else 
          dg_check = nil
      end

      if setting_check == 1 and dg_check == 1 and math.random(1, goblins_lair_chance) == 1

        then -- LET'S DO IT!

          local dg_chest
          local dg_chest_ex = {}
          local dg_area
          local ch_area
          local replaced = {}
          --print(vtos(minetest.registered_nodes))

       -- print("dungeon "..#dg.dungeon.. " found at: ".. vtos(cur_dg).." ( " .. vector.distance(minp,maxp).." )")

          --dg_chest = minetest.find_node_near(cur_dg, 50, chest_node , true)
          --dg_area = {minp, maxp}
          dg_area = {vector.add(cur_dg, 20), vector.subtract(cur_dg, 20)}
          ch_area = {vector.add(cur_dg, 60), vector.subtract(cur_dg, 60)}

          --print("looking for chest: " .. vtos(dg_area))

          local dg_chest_f = minetest.find_nodes_in_area_under_air(ch_area[1], ch_area[2], chest_node)
       -- print(vtos(dg_chest_f))
          if #dg_chest_f >= 1 then

              dg_chest = dg_chest_f

              --gather a list of forbidden node pos to avoid
              dg_chest_ex = {}
              for i in ipairs(dg_chest) do
                table.insert(dg_chest_ex, dg_chest[i])
                table.insert(dg_chest_ex, vector.subtract(dg_chest[i],{x=0,y=1,z=0}))
                table.insert(dg_chest_ex, vector.add(dg_chest[i],{x=0,y=1,z=0}))
                table.insert(dg_chest_ex, vector.add(dg_chest[i],{x=0,y=2,z=0}))

             -- print("****  chest found at: "..vtos(dg_chest[i]) ..", "..vector.distance(dg_chest[i], cur_dg).." from dungeon center")
              end
          end

          -- goblin floor treatment
          local dg_floor_f = minetest.find_nodes_in_area_under_air(dg_area[1], dg_area[2], { "group:stone","group:cracky","group:cobble" })
          local lava_count = 0
          local lava_max = 1
          for i in ipairs(dg_floor_f) do

            local function dgfix(n)
                --print(vtos(n))
                local vn = vector.new(vector.add(dg_floor_f[i],vector.new({ x = 0, y = n , z = 0 })))
                return vn
              end
            --print (vtos(dgfix(3)))
            -- do not mess with the stairs!
            local stair_ex = minetest.get_node_or_nil(dg_floor_f[i]).name

            if stair_ex and string.find(stair_ex, "stair") then
                table.insert(dg_chest_ex, dg_floor_f[i])
            end

            if table.indexof(dg_chest_ex, dg_floor_f[i]) == -1 then

              if math.random(50) == 1 and lava_count < lava_max then

                lava_count = lava_count + 1
                minetest.set_node(dgfix(0), { name = "air" })
                minetest.set_node(dgfix(-1), { name = "air" })
                minetest.set_node(dgfix(-2), { name = lava_source })

              elseif  math.random(10) == 1 then
                minetest.set_node(dgfix(1), { name = gob_mushroom(4) })
              elseif  math.random(10) == 1 then
                  minetest.set_node(dgfix(0), { name = gob_mushroom(4) })
              elseif math.random(10) == 1 then
                  minetest.set_node(dgfix(0), { name = dirt_grass })
              elseif math.random(20) == 1 then
                  minetest.set_node(dgfix(0), { name = water_source })
              elseif math.random(10) == 1 then
                  minetest.set_node(dgfix(0), { name = slab_mossycobble })
              elseif math.random(5) == 1 then
                  minetest.set_node(dgfix(1), { name = grass(5) })
              elseif math.random(6) == 1 then
                  minetest.set_node(dgfix(0), { name = "goblins:moss" })
              elseif math.random(5) == 1 then
                  minetest.set_node(dgfix(1), { name = mossycobble })
              elseif math.random(3) == 1 then
                  minetest.set_node(dgfix(1), { name = slab_mossycobble })
              end
            end
          end

          local function columns(center)
              if center then
                  local n_ring
               -- print("*  creating ring at: "..vtos(center))
                  local rmax
                  local rmin
                  if table.indexof(replaced, dg_chest_ex ) == -1 then
                    table.insert(replaced, dg_chest_ex ) 
                  end
                  for i in ipairs(ring_iter) do
                    --local num = #ring_iter + 1 - i

                    local num = i
                    rmax = vector.add(center, vector.new(num,0,num))
                    rmin = vector.subtract(center, vector.new(num,0,num)) 
                    n_ring = minetest.find_nodes_in_area_under_air(rmin, rmax, dg_replace )

                    if n_ring then
                     -- print("*  setting nodes around ring: ".. num)

                        for r_node in ipairs(n_ring) do
                            local rpos = minetest.serialize(n_ring[r_node])
                            if table.indexof(replaced, rpos) == -1 then
                             -- print(ring_iter[num].. " = " .. vtos(n_ring[r_node]))
                                minetest.set_node(n_ring[r_node], { name = ring_iter[num] })
                                table.insert(replaced, rpos)
                            end
                        end
                    end 
                  end

                  local cols1 = {
                      vector.new(rmax.x+1, rmax.y, rmax.z+1),
                      vector.new(rmax.x+1, rmax.y, rmin.z -1),
                      vector.new(rmin.x-1, rmax.y, rmin.z-1),
                      vector.new(rmin.x-1, rmax.y, rmax.z+1),
                  }
                  local cols2 ={ 
                      vector.add(cols1[1], vector.new(-2,0,0)),
                      vector.add(cols1[1], vector.new(0,0,-2)),
                      vector.add(cols1[2], vector.new(-2,0,0)),
                      vector.add(cols1[2], vector.new(0,0,2)),
                      vector.add(cols1[3], vector.new(2,0,0)),
                      vector.add(cols1[3], vector.new(0,0,2)),
                      vector.add(cols1[4], vector.new(2,0,0)),
                      vector.add(cols1[4], vector.new(0,0,-2)),
                  }

                  for i in ipairs(cols1) do

                    local col=vector.new(cols1[i])
                 -- print("column1 at "..vtos(col))
                    local toppers = { grass(5), slab_mossycobble, gob_mushroom(4) }
                    --local h = 5
                    local h = 0
                    --col = vector.add( col, vector.new(0,1,0) ) 
                    local colc = vector.add( col, vector.new(0,0,0) ) 
                    local max = 20  

                    while max >=1 and minetest.get_node(colc) and minetest.get_node(colc).name == "air" do
                      max = max - 1
                      h = h + 1
                      colc = vector.add( colc, vector.new(0,1,0) ) 
                    end  

                 -- print(" col h:  "..h)
                    for j=1, h do

                        if math.random(2) == 1 then
                            minetest.set_node( col, { name = "goblins:moss" } )
                        else
                            minetest.set_node( col, { name = mossycobble } )
                        end
                        col = vector.add( col, vector.new(0,1,0))

                        if math.random(5) == 1 then
                          minetest.set_node( col, { name = toppers[math.random(#toppers)] } )
                          break
                        end
                    end

                  end

                  for i in ipairs(cols2) do
                    local col=vector.new(cols2[i])
                 -- print("column2 at "..vtos(col))
                    local toppers = { grass(5), slab_mossycobble, gob_mushroom(4) }
                       --local h = 5
                       local h = 0
                       --col = vector.add( col, vector.new(0,1,0) ) 
                       local colc = vector.add( col, vector.new(0,0,0) ) 
                       local max = 20  

                       while max >=1 and minetest.get_node(colc) and minetest.get_node(colc).name == "air" do
                         max = max - 1
                         h = h + 1
                         colc = vector.add( colc, vector.new(0,1,0) ) 
                       end  

                   -- print(" col h:  "..h)
                      for j=1, h do

                          if math.random(2) == 1 then
                              minetest.set_node( col, { name = "goblins:moss" } )
                          else
                              minetest.set_node( col, { name = mossycobble } )
                          end
                          col = vector.add( col, vector.new(0,1,0))

                          if math.random(3) == 1 then
                            minetest.set_node( col, { name = toppers[math.random(#toppers)] } )
                            break
                          end
                      end
                  end
              end
          end

          columns(cur_dg)
          if dg_chest then
            for i in ipairs(dg_chest) do
              columns(vector.subtract(dg_chest[i], vector.new(0,1,0)))
            end
          end

        end

    end)
  end