dofile(minetest.get_modpath("mesecons_autotools").."/fsm/lib.lua");
dofile(minetest.get_modpath("mesecons_autotools").."/fsm/alg.lua");
dofile(minetest.get_modpath("mesecons_autotools").."/fsm/compiler.lua");
dofile(minetest.get_modpath("mesecons_autotools").."/fsm/generate.lua");
dofile(minetest.get_modpath("mesecons_autotools").."/fsm/priority.lua");

local  esc = minetest.formspec_escape

function get_stats_string(data)
  if data == nil then return "<no circuit>" end
  if data.circ == nil then return "<no circuit>" end
  if data.circ.nodes == nil then return "<no circuit>" end
 
  local nodes = data.circ.nodes
  local stats = "<no circuit>"
  local block, gate, wire
  local sx,xy,sz
  
  block, gate, wire = get_stats(nodes)    
  sx = nodes.sx
  sy = nodes.sy
  sz = nodes.sz

  stats = "size : " .. sx .. "x"..sy .. "x"..sz .. "(=".. sx*sy*sz .. ")\n" ..
                "wires : " .. wire .. "\n" ..
                "gates : " .. gate .. "\n" ..
                "others : ".. block - wire - gate .. "\n" .. 
                "blocks: " .. block
  return stats
end

local function get_formspec(data)
    local code = minetest.formspec_escape(data.code or "")
    local name = minetest.formspec_escape(data.name or "")
    local log = minetest.formspec_escape(data.log or "")
    
    local stats_string = get_stats_string(data)
    
    local create_button = ""
    if data.circ ~= nil then 
      if data.circ.nodes ~= nil then
        create_button =    "image[27.5,23;1,1;circuit_full.png]" ..
                "button[28.5,23;3,1;create;" .. "Create" .. "]" 
      end
    end
            
      
    
    local formspec = 
                "formspec_version[3]".. 
               
                "size[32,25]"..    
                "style_type[textarea;font=mono]" .. 
               
                "label[15,0.7;FSM generator]".. 
                --"label[20,0.7;" .. file .. "]" ..
                "field[0.5,2;15,1;name;Name;" .. name .. "]"..
                "textarea[0.5,4;15,15;code;" .. "Code:;" .. code ..  "]" ..
                "textarea[16.5,2;15,17;;" .. "Compilation Logs:" .. ";" .. log .. "]" ..
                "button[0.5,19;3,1;save;" .. "Save" .. "]" .. 
                "button[14.5,20;3,1;compile;" .. "Compile" .. "]" ..
                
                
                "textarea[23.5,21;8,5;;Circuit Parameters;" .. esc(stats_string) .. "]" ..
                
                                
                "label[0.5,21;Generation Options:]" ..
                "label[1,22;Circuit Type:]" .. 
                "dropdown[4,21.5;5,1;type;flat_raw;1]" ..
                
                create_button .. 
                
                ""
    return formspec
end

function on_place_fsm_book(itemstack, player, pointed_thing)
        local user = player:get_player_name()
        local rad = player:get_look_horizontal()
        local direction = radians_to_direction_looking_forward(rad)
        local fields = itemstack:get_meta():to_table().fields
        local file = fields.file
                
        if not mesecons_autotools.is_full_selection(user) then return nil end
        local  pos1 = mesecons_autotools.get_pos(user,1)
        local  pos2 = mesecons_autotools.get_pos(user,2)
        local sel = {pos1=pos1,pos2=pos2}
        
        local data = read_table_from_file(file)
        if data.circ == nil then return end
        local circ = data.circ
        
        
        paste_circuit_from_table(sel,circ,direction) 
end


local function show_dialog_fsm(player,itemstack)
  local user = player:get_player_name()
  local fields = itemstack:get_meta():to_table().fields
  local file = fields.file
  local stack = player:get_wielded_item()  
  local db = {}
  local data = {}
  
   if file == nil then
    file = generate_file_name_fsm(user)
    fields.file = file
    stack:get_meta():from_table({ fields = fields})
    player:set_wielded_item(stack)
    
    data.code = ""
    data.name = ""
    data.log = ""
    save_table_to_file(file,data)
  else
    data  = read_table_from_file(file)
    if data == nil then data = {} end
  end

  local formspec = get_formspec(data)
  
  minetest.show_formspec(user, "mesecons_autotools:fsm_show", formspec)
end


function fsm_make_selection(user,file,direction,pos)
  if file == nil then return end
  
  local data  = read_table_from_file(file)
  if data.circ == nil then return end
  local nodes = data.circ.nodes
  
  if nodes == nil then return end
  
  
  local sx = nodes.sx
  local sy = nodes.sy
  local sz = nodes.sz
  
  
  local pos2 = make_pos2(pos,direction,sx,sy,sz)
  
  -- Updatecd 
  mesecons_autotools.set_pos(user,1,pos)
  mesecons_autotools.set_pos(user,2,pos2)
  mesecons_autotools.render(user)
  mesecons_autotools.zero_stack_counter(user)
  mesecons_autotools.zero_stack_direction(user)  
end


local function on_use_fsm_book(itemstack, player, pointed_thing)
   
  local user = player:get_player_name()
  local data = itemstack:get_meta():to_table().fields
  local rad = player:get_look_horizontal()
  local direction = radians_to_direction_looking_forward(rad)
  local file = data.file
--  local stack = player:get_wielded_item()  
 
  if( pointed_thing.type == "node" ) then 
     fsm_make_selection(user,file,direction,pointed_thing.above)   
  else
     show_dialog_fsm(player,itemstack)     
  end

  return nil 
  
 
end

minetest.register_on_player_receive_fields(function(player, formname, fields)
     if formname ~= "mesecons_autotools:fsm_show" then return end   
        local user = player:get_player_name()                
        local stack = player:get_wielded_item()
        local ffields = stack:get_meta():to_table().fields
        
        local data = {}
        local file = ffields.file
   
        if file == nil then
          file = generate_file_name_fsm(user)
          ffields.file = file
          data.name =""
          data.code =""
          data.log =""
          
          save_table_to_file(file,data) -- just to generate file
        else
          data  = read_table_from_file(file)
          if data == nil then data = {} end
        end
        
        data.name = fields.name or ""
        data.code = fields.code or ""

        
        if (fields.save) or fields.key_enter_field == "name" then 
                ffields.description = data.name
                stack:get_meta():from_table({ fields = ffields})
                player:set_wielded_item(stack)
                save_table_to_file(file,data) 
                
        elseif fields.compile then
                ffields.description = data.name
                stack:get_meta():from_table({ fields = ffields})
                player:set_wielded_item(stack)
                
                
                -- saving code before compiling 
                -- (just in case the game crashes during compilation)
                data.log = "\ngame crashed?\nkeep the code and report bug :)"
                save_table_to_file(file,data)
                
                --compilation area
                
                
                local bin,err  = compile_code(data.code)
                if bin == nil then
                  data.log = err
                  data.circ = nil
                else
                  local circ = generate_circuit(bin,{})
                  data.circ = circ
                  data.log = err
                end
                
                --end of copmilation area
                
                save_table_to_file(file,data)
                
                local formspec = get_formspec(data)
                minetest.show_formspec(user, "mesecons_autotools:fsm_show", formspec)
           
        elseif fields.create then
            if data.circ == nil then return end
            if data.circ.nodes == nil then return end
            
            -- create file
            local blue  = {}
            blue.nodes = data.circ.nodes
            blue.metas = data.circ.metas
            blue.title = data.name
            blue.text = ""
            blue.direction = {x=0,y=0,z=1}
            
            -- save file
            
            local blue_file  = generate_file_name(user)
            save_table_to_file(blue_file,blue)
            
            -- create item in inventory
            
            local new_stack = ItemStack("mesecons_autotools:circuit_full")
            local b  = {}
            b.file = blue_file             
            b.description = blue.title
            new_stack:get_meta():from_table({ fields = b})

            local inv = player:get_inventory()
            if inv:room_for_item("main", new_stack) then
                  inv:add_item("main", new_stack)
            else
                  minetest.add_item(player:get_pos(), new_stack)
            end
        end
        
        
end)

minetest.register_tool("mesecons_autotools:fsm", {
                description = "FSM generator",
                inventory_image = "fsm_book.png",                                
                stack_max = 1,
               
                on_use = on_use_fsm_book,
                on_place = on_place_fsm_book,
                on_secondary_use = none,                
               
        })
