local callback_off = false;

-- Remember all, delete all, rebuild all as it was
-- (well, at least with a similarity we can achieve for now)
function rebuild_all()
local units, cities, tn, cn = {}, {}, {}, {}
local cqrr
local restore_unit

-- Don't cascade
if callback_off then
  return false
else
  callback_off = true
end

restore_unit = function(i)
  if "table" == type(units[i]) then
    local trr = units[i][8]

    units[i][5] = cities[units[i][5]]
    if trr then
      units[i][8] = restore_unit(trr)
    end
    -- hm, unpack() is missing in Freeciv Lua???
    units[i] = edit.create_unit_full
    (units[i][1], units[i][2], units[i][3], units[i][4], units[i][5],
     units[i][6], units[i][7], units[i][8])
  end
  return units[i]
end

-- Destroy a city on tile ct from tile t, set cqrr that can do it
-- pc is city owner, p is a player at war
local function destroy_city(p, pc, t, ct)
  local ut = cqrr
  local i = 0
  local u
  local pu = pc
  local sz = ct:city().size

  repeat
    if u and u:exists() then
      --Unsuitable conqueror
      u:kill("editor")
    end
    if ut then
      u = edit.create_unit(p, t, cqrr, 0, nil, -1)
    end
    if not u then
      -- Find a conqueror that can exist here.
      -- We have no way to know if a unit can conquer a city, so try and see
      while true do
        ut = find.unit_type(i)
        if not ut then
          -- can't conquer from here by anything!
          return false
        end
        i = i + 1
      end
    else
      u:move(ct, 3--[[just a random cost]])
    end
  until u and u.tile == ct
  u:kill("editor")
  cqrr = ut
  if ct:city().size >= sz then
    -- Bad player p!
    return nil
  end
  while ct:city() do
    u = edit.create_unit(pu, t, cqrr, 0, nil, -1)
    u:move(ct, 3--[[just a random cost]])
    u:kill("editor")
    if pu == p then pu = pc else pu = p end
  end
  return true
end

-- Fix what we can
for p in players_iterate() do
  local i = 1

  for c in p:cities_iterate() do
    table.insert(cities, {p, c.tile, c.name--[[, c.size, c.buildings??]]})
    cn[c] = #cities
  end
  for u in p:units_iterate() do
    table.insert(units,
                 {p, u.tile, u.utype, 0--[[u.veteran]],
                  cn[u:get_homecity()], -1--[[u.moves_left]], -1--[[u.hp]]})
    tn[u] = {#units, 0}
  end
  for u in p:units_iterate() do
    local t = u:transporter()

    if t then
      local ttn = tn[t]
      units[i][8] = ttn[1]
      ttn[2] = ttn[2] + 1
    end
    i = i+1
  end
end

-- Ensure we have a barbarian player that will be at war with everybody
for t in whole_map_iterate() do
  if not t:city() and t:num_units() == 0 then
    t:unleash_barbarians()
    break
  end
end

-- Now, clear the map.
-- Remove units. Try no to sink anything, just delete it
for p in players_iterate() do
  -- Recursively delete transported units
  while p:num_units() > 0 do
    for u in p:units_iterate() do
      if not tn[u] or tn[u][2] == 0 then
        local t = u:transporter()

        if t and tn[t] then
          tn[t][2] = tn[t][2] - 1
        end
        u:kill("editor")
      end
    end
  end
end
-- Remove the cities.
-- We don't have the method, so just act so that they disappear
-- Well, some cities can't be destroyed that simple, forget it
for p in players_iterate() do
  local paw

  for c in p:cities_iterate() do
    local ct = c.tile

    if not paw then
      -- Find a player at war
      for pw in players_iterate() do
        if pw ~= p then
          for at in ct:square_iterate(1) do
            if at ~= ct then
              if destroy_city(pw, p, at, ct) then
                paw = pw
                break --square_iterate
              end
            end
          end
          if paw then
            break --players_iterate /inner/
          end
        end
      end --players_iterate /inner/
    else
      for at in ct:square_iterate(1) do
        if at ~= ct then
          if destroy_city(paw, p, at, ct) then
            break --square_iterate
          end
        end
      end
    end --if
  end --cities_iterate
end --players_iterate

-- Now, rebuild what we have cleaned... or something
for i = 1, #cities do
  local xc = cities[i][2]:city()
  if xc then
    cities[i] = xc
  else
    cities[i] = edit.create_city(cities[i][1], cities[i][2], cities[i][3])
  end
end
for i = 1, #units do
  -- Recursively generate transports before cargo
  restore_unit(i)
end

callback_off = false
return false
end