require("story")
require('util')

local think = function(thought)
  game.players[1].print({"","[img=entity/character][color=orange]",{"engineer-title"},": [/color]",{"think-"..thought}})
end

local set_arrow = function(arrow_settings)
  if storage.arrow then
    storage.arrow.destroy()
  end
  if arrow_settings == nil then
    storage.arrow = nil
  else
    storage.arrow = game.players[1].surface.create_entity(arrow_settings)
  end
end

local on_player_created = function(event)
  local player = game.players[event.player_index]
  player.disable_recipe_groups()
  player.disable_recipe_subgroups()
  player.minimap_enabled = false
  player.force.disable_all_prototypes()
  player.force.disable_research()
  player.surface.always_day = true -- Don't bother the player with night in this early mission
  player.game_view_settings =
  {
    show_hotkey_suggestions = false
  }
  local recipe_list = player.force.recipes
  recipe_list["iron-plate"].enabled = true
  recipe_list["copper-plate"].enabled = true
  recipe_list["stone-furnace"].enabled = true
  recipe_list["wooden-chest"].enabled = true
  recipe_list["iron-gear-wheel"].enabled = true
  recipe_list["burner-mining-drill"].enabled = true
  recipe_list["transport-belt"].enabled = true
  recipe_list["burner-inserter"].enabled = true
  game.players[1].clear_recipe_notifications()
  if player.character then
    player.character.insert{name = "coal", count = 20}
  end

end

local init = function()
  game.allow_tip_activation = true
  storage.story = story_init()
  game.map_settings.pollution.enabled = false

  storage.inserter_chest = game.get_entity_by_tag("inserter-chest")  or error("Inserter chest missing")
  storage.inserter_chest_position = storage.inserter_chest.position
  storage.inserter_chest_position.energy = 0

  storage.inserter_furnace = game.get_entity_by_tag("inserter-furnace") or error("Inserter furnace missing")
  storage.inserter_furnace_position = storage.inserter_furnace.position
end

function check_for_player_death(event)
  if event.name == defines.events.on_player_died then
    game.set_game_state({game_finished=true, player_won=false, can_continue=false})
  end
end

local story_table =
{
  ["update-functions"]=
  {
   ["check-inserter-1"]=
   function(event, story)
     if not storage.inserter_chest.valid then
       story_jump_to(story, "build-the-accidentally-mined-inserter")
     end
   end,
   ["check-inserter-2"]=
   function(event, story)
     if not storage.inserter_furnace.valid then
       story_jump_to(story, "build-the-accidentally-mined-inserter-2")
     end
   end
  },
  {
    {
      init = function(event, story)
        story_add_update(story, "check-inserter-1")
      end,
      condition = story_elapsed_check(3),
      action = function()
        think("found-mining-site")
      end
    },
    {
      condition = story_elapsed_check(4),
      action = function()
        think("robotic-arm")
      end
    },
    {
      condition = story_elapsed_check(4.6),
      action =
      function(event,story)
        if storage.inserter_chest.energy > 0 then
          story_jump_to(story,"inserter-explaination")
        else
          story_show_message_dialog{text={"msg-inserter-no-power"},
                                    point_to={type="entity", entity=storage.inserter_chest}}
        end
      end
    },
    {
      condition = story_elapsed_check(1),
      action =
      function()
        set_goal({"goal-open-machine-gui"})
        game.players[1].set_gui_arrow({type="entity", entity=storage.inserter_chest})
      end
    },
    {
      name = "wait-to-open-inserter-1",
      condition = function() return storage.inserter_chest == game.players[1].opened end,
      action =
      function()
        set_goal({"goal-insert-fuel-into-inserter-1"})
        game.players[1].clear_gui_arrow()
      end
    },
    {
      condition = function() return storage.inserter_chest.energy > 0 end,
      action = function()
        set_goal({"goal-close-inserter-gui"})
      end
    },
    {
      name = 'inserter-explaination',
      condition = function() return game.players[1].opened == nil end,
      action =
      function()
        set_goal("")
        local shown_text;
        if game.players[1].input_method == defines.input_method.game_controller then
          shown_text = "msg-inserter-introduction-1-controller"
        else
          shown_text = "msg-inserter-introduction-1"
        end
        story_show_message_dialog{text={shown_text},
                                 image = "inserter-explanation.png",
                                 point_to={type="entity", entity=storage.inserter_chest}}
      end
    },
    {
      action =
      function(event, story)
          story_show_message_dialog{text={"msg-inserter-introduction-2"},
                                 image = "inserter-usage-explanation.png",
                                 point_to={type="entity", entity=storage.inserter_chest}}
        story_remove_update(story, "check-inserter-1")
        game.players[1].game_view_settings.update_entity_selection = true
      end
    },
    {
      condition = story_elapsed_check(5),
      action = function()
        local pistol_chest = game.get_entity_by_tag('pistol-chest')
        if pistol_chest and pistol_chest.valid then
          set_goal({"goal-inspect-chest"})
          storage.arrow = game.players[1].surface.create_entity{name="orange-arrow-with-circle", position = pistol_chest.position}
        end
      end
    },
    {

      condition = function()
        local pistol_chest = game.get_entity_by_tag('pistol-chest')
        return pistol_chest == nil or (pistol_chest.get_inventory(defines.inventory.chest).is_empty() and
        game.players[1].cursor_stack.valid_for_read == false)
      end,
      action = function()
        if storage.arrow then storage.arrow.destroy() end
        set_goal({"goal-close-inventory"})
      end
    },
    {
      condition = function()
        return game.players[1].opened == nil
      end,
      action = function()
        think("chest-content-useful")
        set_goal("")
      end
    },
    {
      condition = story_elapsed_check(2),
      action = function(event, story)
        if not (game.players[1].character.get_inventory(defines.inventory.character_guns)[1].valid_for_read and
          game.players[1].character.get_inventory(defines.inventory.character_guns)[1].name == "pistol") then
          local shown_text;
          if game.players[1].input_method == defines.input_method.game_controller then
            shown_text = "msg-gun-equipment-controller"
          else
            shown_text = "msg-gun-equipment"
          end
          story_show_message_dialog
          {
            text = {shown_text},
            point_to =
            {
              type = "item_stack",
              inventory_index = defines.inventory.character_guns,
              item_stack_index = 1,
              source = "player"
            }
          }
        end
        if game.players[1].input_method ~= defines.input_method.game_controller then
          story_jump_to(story, "equip-start")
        end
      end
    },
    {
      init = function()
        game.players[1].set_goal_description({"goal-controller-open-character-gui"})
      end,
      condition = function (event)
        return game.players[1].opened_gui_type == defines.gui_type.controller
      end
    },
    {
      name = 'wait-for-window-to-open',
      condition = story_elapsed_check(0.0000001),
    },
    {
      init = function()
        game.show_message_dialog({text={"msg-controller-character-tab"}, point_to= {type="active_window"}})
      end,
      condition = story_elapsed_check(0.0000001),
    },
    {
      name = 'equip-start',
      condition = story_elapsed_check(0.5),
      action = function()
        if not (game.players[1].character.get_inventory(defines.inventory.character_guns)[1].valid_for_read and
          game.players[1].character.get_inventory(defines.inventory.character_guns)[1].name == "pistol") then
          set_goal({"goal-equip-gun"})
          if game.players[1].input_method ~= defines.input_method.game_controller then
            game.players[1].set_gui_arrow{type = "item_stack", inventory_index = defines.inventory.character_guns, item_stack_index = 1, source="player"}
          else
            game.players[1].character.clear_gui_arrow()
          end
        end
      end
    },
    {
      condition = function() return game.players[1].character.get_inventory(defines.inventory.character_guns)[1].valid_for_read and
          game.players[1].character.get_inventory(defines.inventory.character_guns)[1].name == "pistol" end,
      action = function()
        if game.players[1].character.get_inventory(defines.inventory.character_ammo).get_item_count("firearm-magazine") == 0 then
          set_goal({"goal-equip-ammo"})
          if game.players[1].input_method ~= defines.input_method.game_controller then
	        game.players[1].set_gui_arrow{type = "item_stack", inventory_index = defines.inventory.character_ammo, item_stack_index = 1, source="player"}
          else
            game.players[1].character.clear_gui_arrow()
          end
        end
      end
    },
    {
      condition = function() return game.players[1].character.get_inventory(defines.inventory.character_ammo)[1].valid_for_read and
          game.players[1].character.get_inventory(defines.inventory.character_ammo)[1].name == "firearm-magazine" end,
      action = function()
        set_goal("")
        game.players[1].character.clear_gui_arrow()
      end
    },
    {
      init = function()
        set_goal({"goal-close-inventory"})
      end,
      condition = function()
        return game.players[1].opened == nil and game.players[1].opened_self == false
      end,
      action = function()
        set_goal("")
        if game.players[1].surface.count_entities_filtered({name='small-biter'}) < 2 then
          local pos = {
            x=0,
            y=game.players[1].surface.map_gen_settings.height/-2
          }
          for k=1,4 do
            game.players[1].surface.create_entity({
              name='small-biter',
              position=game.players[1].surface.find_non_colliding_position('small-biter',pos,5,0.1)
            })
          end
        end
      end
    },
    {
      condition = story_elapsed_check(2),
      action =
      function()
        think("creepers-coming")
        game.players[1].character.clear_gui_arrow()
      end
    },
    {
      condition = story_elapsed_check(3),
      action = function()
        local shown_text;
        if game.players[1].input_method == defines.input_method.game_controller then
          shown_text = "msg-shooting-controller"
        else
          shown_text = "msg-shooting"
        end
        story_show_message_dialog
        {
          text = {shown_text},
          point_to = {type = "entity", entity = game.players[1].character}
        }
        storage.biters_killed = 0
      end
    },
    {
      condition = story_elapsed_check(1.5),
      action = function()
        set_goal({"kill-creepers"})
      end
    },
    {
      init = function()
        game.surfaces[1].create_entity({name='small-biter',position={x=-51,y=-55}})
        game.surfaces[1].create_entity({name='small-biter',position={x=-55,y=-55}})

        game.players[1].surface.set_multi_command
        {
          command =
          {
            type=defines.command.attack,
            target=game.players[1].character,
            distraction=defines.distraction.none
          },
          unit_count = 2
        }
      end,
      update = function(event)
        if event.name == defines.events.on_entity_died and
           event.entity.name == "small-biter" then
          storage.biters_killed = storage.biters_killed + 1
        end
      end,
      condition = function() return storage.biters_killed >= 2 end,
      action = function()
        set_goal("")
        think("creepers-dead")
      end
    },
    {
      condition = story_elapsed_check(3),
      action = function()
        set_goal("")
        think("prepare")
      end
    },
    {
      init = function(event, story) story_add_update(story, "check-inserter-2") end,
      condition = story_elapsed_check(5),
      action = function(event, story)
        if storage.inserter_furnace.direction == defines.direction.east then
          story_jump_to(story,"more-machines")
        else
          story_show_message_dialog
          {
            text = {"msg-inserter-2-reversed"},
            point_to = {type="entity", entity = storage.inserter_furnace}
          }
        end
      end
    },
    {
      condition = story_elapsed_check(0.5),
      action = function()
        game.players[1].set_gui_arrow({type="entity", entity=storage.inserter_furnace})
        if game.players[1].input_method == defines.input_method.game_controller then
          set_goal({"goal-rotate-inserter-2-controller"})
        else
          set_goal({"goal-rotate-inserter-2"})
        end
      end
    },
    {
      name = "wait-to-rotate-inserter-2",
      condition = function()
          return storage.inserter_furnace.drop_target ~= nil and
                 storage.inserter_furnace.drop_target.name == "stone-furnace"
        end,
      action = function(event, story)
        set_goal("")
        game.players[1].clear_gui_arrow()
        think("inserter2-working")
        story_remove_update(story, "check-inserter-2")
      end
    },
    {
      condition = story_elapsed_check(3),
      action = function()
        game.players[1].clear_gui_arrow()
        story_show_message_dialog
        {
          text = {"msg-rotations-explained"},
          point_to = {type = "entity", entity = game.players[1].character}
        }
      end
    },
    {
      name = 'more-machines',
      condition = story_elapsed_check(3),
      action = function()
        think("need-more-machines")
      end
    },
    {
      condition = story_elapsed_check(4)
    },
    {
      init = function(event, story)
        storage.mined_stone_count = 0
        story_remove_update(story, "check-inserter-1")
        story_remove_update(story, "check-inserter-2")
      end,
      update = (function()
        --jesus...
        --yeah i know what you mean...
        local only_update = false

        return function(event)

          progress = event.name == defines.events.on_built_entity and
                     (event.entity.name == "burner-mining-drill" or
                      event.entity.name == "stone-furnace")

          if event.name == defines.events.on_player_mined_item and
             event.item_stack.name == "stone" then
             storage.mined_stone_count = storage.mined_stone_count + 1
          end

          if storage.mined_stone_count >= 5 and storage.advice_to_mine_stone == nil then
            think("automated-stone-mining")
            storage.advice_to_mine_stone = true
          end

          set_goal
          (
            {
              "goal-build-machines",
              game.players[1].force.get_entity_count("burner-mining-drill"),
              10,
              game.players[1].force.get_entity_count("stone-furnace"),
              5
            },
            true
          )

          only_update = true
        end
      end)(),
      condition = function()
        return game.players[1].force.get_entity_count("burner-mining-drill") >= 10 and
               game.players[1].force.get_entity_count("stone-furnace") >= 5
      end,
      action = function()
        think("got-machines")
        set_goal("")
      end
    },
    {
      condition = story_elapsed_check(5),
      action = function()
        think("need-more-resources")
      end
    },
    {
      update = (function()
        local only_update = false
        return function(event)
          local iron_plate_count = game.players[1].character.get_item_count("iron-plate")
          local copperplatecount = game.players[1].character.get_item_count("copper-plate")
          local coal_count = game.players[1].character.get_item_count("coal")
          set_goal
          (
            {
              "goal-get-resources",
              iron_plate_count,
              150,
              copperplatecount,
              50,
              coal_count,
              75
            },
            only_update
          )
          only_update = true
        end
      end)(),
      condition = function()
        return game.players[1].character.get_item_count("iron-plate") >= 150 and
               game.players[1].character.get_item_count("copper-plate") >= 50 and
               game.players[1].character.get_item_count("coal") >= 75
      end,
      action = function()
        think("got-resources-1")
        set_goal("")
      end
    },
    {
      condition = story_elapsed_check(5),
      action = function()
        think("time-to-move-on")
      end
    },
    {
      condition = story_elapsed_check(5),
      action = function()
        game.set_game_state({game_finished=true, player_won=true, can_continue=true,next_level='level-03'})
      end
    }
  },
  {
    {
     name = "build-the-accidentally-mined-inserter",
     init = function(event, story)
       story_remove_update(story, "check-inserter-1")
     end,
     action = function()
       story_show_message_dialog
       {
         text={"msg-mined-inserter-instead-of-open"},
         point_to = {type = "position", position = storage.inserter_chest_position}}
       set_arrow({name="orange-arrow-with-circle", position = storage.inserter_chest_position})
     end
    },
    {
      action = function()
        set_goal({"goal-build-inserter-back"})
      end
    },
    {
      condition = function(event)
        if event.name == defines.events.on_built_entity and
           event.entity.name == "burner-inserter" then

          if not (event.entity.position.x == storage.inserter_chest_position.x and
            event.entity.position.y == storage.inserter_chest_position.y) then
            story_show_message_dialog
            {
              text = {"msg-inserter-1-wrong-position"},
              point_to = {type = "entity", entity = event.entity}
            }
            return false
          else
            event.entity.direction = defines.direction.west
            storage.inserter_chest = event.entity
            return true
          end
        end
      end,
      action = function(event, story)
        set_arrow()
        story_jump_to(story, "wait-to-open-inserter-1")
        story_add_update(story, "check-inserter-1")
      end
    }
  },
  {
    {
     name = "build-the-accidentally-mined-inserter-2",
     init = function(event, story)
       story_remove_update(story, "check-inserter-2")
     end,
     action = function()
       story_show_message_dialog
       {
         text = {"msg-mined-inserter-instead-of-open-2"},
         point_to = {type="position", position = storage.inserter_furnace_position}
       }
       set_arrow({name="orange-arrow-with-circle", position = storage.inserter_furnace_position})
     end
    },
    {
      action = function()
        set_goal({"goal-build-inserter-back"})
      end
    },
    {
      condition = function(event)
        if event.name == defines.events.on_built_entity and
           event.entity.name == "burner-inserter" then

          if not table.compare(event.entity.position, storage.inserter_furnace_position or {0,0}) then
            story_show_message_dialog
            {
              text = {"msg-inserter-2-wrong-position"},
              point_to = {type = "entity", entity = event.entity}
            }
            return false
          end

          storage.inserter_furnace = event.entity
          return true
        end
      end,
      action = function(event, story)
        set_arrow()
        story_jump_to(story, "wait-to-rotate-inserter-2")
        story_add_update(story, "check-inserter-2")
      end
    }
  }
}

story_init_helpers(story_table)

local story_events =
{
  defines.events.on_tick,
  defines.events.on_entity_died,
  defines.events.on_built_entity,
  defines.events.on_player_mined_item,
  defines.events.on_player_died
}

script.on_event(story_events, function(event)
  if game.players[1].character then
    check_for_player_death(event)
    story_update(storage.story, event, "level-03")
  end
end)

script.on_init(init)

script.on_event(defines.events.on_player_created, function(event)
  on_player_created(event)
end)