local _ENV = mkmodule('plugins.dfusion.tools')
local dfu=require("plugins.dfusion")
local ms=require "memscan"
menu=dfu.SimpleMenu()
RaceNames={}
function build_race_names()
    if #RaceNames~=0 then
        return RaceNames
    else
        for k,v in pairs(df.global.world.raws.creatures.all) do
            RaceNames[v.creature_id]=k
        end
        dfhack.onStateChange.invalidate_races=function(change_id) --todo does this work?
            if change_id==SC_WORLD_UNLOADED then
                dfhack.onStateChange.invalidate_races=nil
                RaceNames={}
            end
        end
        return RaceNames
    end
end
function setrace(name) 
	local RaceTable=build_race_names()
	print("Your current race is:"..df.global.world.raws.creatures.all[df.global.ui.race_id].creature_id)
	local id
	if name == nil then
		print("Type new race's token name in full caps (q to quit):")
		repeat
			local entry=dfhack.lineedit()
			if entry=="q" then
				return
			end
			id=RaceTable[entry]
		until id~=nil
	else
		id=RaceTable[name]
		if id==nil then
			error("Name not found!")
		end
	end
	df.global.ui.race_id=id
end
menu:add("Set current race",setrace)
function GiveSentience(names) 
	local RaceTable=build_race_names() --slow.If loaded don't load again
    local id,ids
	if names ==nil then
		ids={}
		print("Type race's  token name in full caps to give sentience to:")
		repeat
			id=dfhack.lineedit()
			id=RaceTable[entry]
            if id~=nil then
                table.insert(ids,id)
            end
		until id==nil
		
	else
		ids={}
		for _,name in pairs(names) do
			id=RaceTable[name]
			table.insert(ids,id)
		end
	end
	for _,id in pairs(ids) do
		local races=df.global.world.raws.creatures.all

		local castes=races[id].caste
		print(string.format("Caste count:%i",#castes))
		for i =0,#castes-1 do
			
			print("Caste name:"..castes[i].caste_id.."...")
			
			local flags=castes[i].flags
			--print(string.format("%x",flagoffset))
			if flags.CAN_SPEAK then
				print("\tis sentient.")
			else
				print("\tnon sentient. Allocating IQ...")
				flags.CAN_SPEAK=true
			end
		end
	end
end
menu:add("Give Sentience",GiveSentience)
function MakeFollow(unit,trgunit)
	if unit == nil then
		unit=dfhack.gui.getSelectedUnit()
	end
	if unit== nil then
		error("Invalid creature")
	end
	if trgunit==nil then
		trgunit=df.global.world.units.active[0]
	end
	unit.relations.group_leader_id=trgunit.id
	local u_nem=dfhack.units.getNemesis(unit)
	local t_nem=dfhack.units.getNemesis(trgunit)
	if u_nem then
		u_nem.group_leader_id=t_nem.id
	end
	if t_nem and u_nem then
		t_nem.companions:insert(#t_nem.companions,u_nem.id)
	end
end
menu:add("Make creature follow",MakeFollow)
function project(unit,trg) --TODO add to menu?
	if unit==nil then
		unit=getCreatureAtPointer()
	end
	
	if unit==nil then
		error("Failed to project unit. Unit not selected/valid")
	end
	-- todo: add projectile to world, point to unit, add flag to unit, add gen-ref to projectile.
	local p=df.proj_unitst:new()
	local startpos={x=unit.pos.x,y=unit.pos.y,z=unit.pos.z}
	p.origin_pos=startpos
	p.target_pos=trg
	p.cur_pos=startpos
	p.prev_pos=startpos
	p.unit=unit
	--- wtf stuff
	p.unk14=100
	p.unk16=-1
	p.unk23=-1
	p.fall_delay=5
	p.fall_counter=5
	p.collided=true
	-- end wtf
	local citem=df.global.world.proj_list
	local maxid=1
	local newlink=df.proj_list_link:new()
	newlink.item=p
	while citem.item~= nil do
		if citem.item.id>maxid then maxid=citem.item.id end
		if citem.next ~= nil then 
			citem=citem.next
		else
			break
		end
	end
	p.id=maxid+1
	newlink.prev=citem
	citem.next=newlink
	local proj_ref=df.general_ref_projectile:new()
	proj_ref.projectile_id=p.id
	unit.general_refs:insert(#unit.general_refs,proj_ref)
	unit.flags1.projectile=true
end
function empregnate(unit)
	if unit==nil then
		unit=dfhack.gui.getSelectedUnit()
	end
	if unit==nil then
		error("Failed to empregnate. Unit not selected/valid")
	end
	if unit.curse then
		unit.curse.add_tags2.STERILE=false
	end
	local genes = unit.appearance.genes
	if unit.relations.pregnancy_ptr == nil then
		print("creating preg ptr.")
		if false then
			print(string.format("%x %x",df.sizeof(unit.relations:_field("pregnancy_ptr"))))
			return
		end
		unit.relations.pregnancy_ptr = { new = true, assign = genes }
	end
	local ngenes = unit.relations.pregnancy_ptr
	if #ngenes.appearance ~= #genes.appearance or #ngenes.colors ~= #genes.colors then
		print("Array sizes incorrect, fixing.")
		ngenes:assign(genes);
	end
	print("Setting preg timer.")
	unit.relations.pregnancy_timer=10
	unit.relations.pregnancy_mystery=1
end
menu:add("Empregnate",empregnate)
function healunit(unit)
    if unit==nil then
		unit=dfhack.gui.getSelectedUnit()
	end

	if unit==nil then
		error("Failed to Heal unit. Unit not selected/valid")
	end
    
    unit.body.wounds:resize(0) -- memory leak here :/
	unit.body.blood_count=unit.body.blood_max
	--set flags for standing and grasping...
	unit.status2.limbs_stand_max=4
	unit.status2.limbs_stand_count=4
	unit.status2.limbs_grasp_max=4
	unit.status2.limbs_grasp_count=4
	--should also set temperatures, and flags for breath etc...
	unit.flags1.dead=false
	unit.flags2.calculated_bodyparts=false
	unit.flags2.calculated_nerves=false
	unit.flags2.circulatory_spray=false
	unit.flags2.vision_good=true
	unit.flags2.vision_damaged=false
	unit.flags2.vision_missing=false
	unit.counters.winded=0
	unit.counters.unconscious=0
	for k,v in pairs(unit.body.components) do
		for kk,vv in pairs(v) do
			if k == 'body_part_status' then v[kk].whole = 0  else v[kk] = 0 end
		end
	end
end
menu:add("Heal unit",healunit)
function powerup(unit,labor_rating,military_rating,skills)
    if unit==nil then
		unit=dfhack.gui.getSelectedUnit()
	end
	if unit==nil then
		error("Failed to power up unit. Unit not selected/valid")
	end
    
    if unit.status.current_soul== nil then
        error("Failed to power up unit. Unit has no soul")
    end
    local utils = require 'utils'
    labor_rating = labor_rating or 15
    military_rating = military_rating or 70

    skill =skill or { 0,2,3,4,5,6,7,8,9,10,11,12,13,14,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,41,42,43,44,45,46,47,48,49,54,55,57,58,59,60,61,62,63,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,95,96,97,98,99,100,101,102,103,104,105,109,110,111,112,113,114,115 }
    local military = { 38,39,41,42,43,44,45,46,54,99,100,101,102,103,104,105 }

    for sk,sv in ipairs(skill) do
    local new_rating = labor_rating
    for _,v in ipairs(military) do
      if v == sv then
        local new_rating = military_rating
      end
    end
    utils.insert_or_update(unit.status.current_soul.skills, { new = true, id = sv, rating = new_rating, experience = (new_rating * 500) + (new_rating * (new_rating - 1)) * 50}, 'id')
    end
  
end
menu:add("Power up",powerup)
return _ENV