// Layout code
// Contain is for how it will treat its children. If they should be laid out as a row, or column, or in a flex style, etc.

var layout = use('layout')
var geometry = use('geometry')
var draw = use('draw2d')
var graphics = use('graphics')
var util = use('util')
var input = use('input')

var lay_ctx = layout.make_context();

var clay_base = {
  font: null,
  background_image: null,
  slice: 0,
  font: 'smalle.16',
  font_size: null,
  color: [1,1,1,1],
  spacing:0,
  padding:0,
  margin:0,
  offset:[0,0],
  size:null,
  background_color: null
};

var root_item;
var root_config;
var boxes = [];
var clay = {}

clay.behave = layout.behave;
clay.contain = layout.contain;

clay.draw = function draw(size, fn, config = {})
{
  lay_ctx.reset();
  boxes = [];
  var root = lay_ctx.item();
  lay_ctx.set_size(root,size);
  lay_ctx.set_contain(root,layout.contain.row);
  root_item = root;
  root_config = Object.assign({}, clay_base);
  boxes.push({
    id:root,
    config:root_config
  });
  fn();
  lay_ctx.run();

  // Adjust bounding boxes for padding
  for (var i = 0; i < boxes.length; i++) {
    var box = boxes[i];
    box.content = lay_ctx.get_rect(box.id);
    box.boundingbox = Object.assign({}, box.content);

    var padding = util.normalizeSpacing(box.config.padding || 0);
    if (padding.l || padding.r || padding.t || padding.b) {
      // Adjust the boundingbox to include the padding
      box.boundingbox.x -= padding.l;
      box.boundingbox.y -= padding.t;
      box.boundingbox.width += padding.l + padding.r;
      box.boundingbox.height += padding.t + padding.b;
    }
    box.marginbox = Object.assign({}, box.content);
    var margin = util.normalizeSpacing(box.config.margin || 0);
    box.marginbox.x -= margin.l;
    box.marginbox.y -= margin.t;
    box.marginbox.width += margin.l+margin.r;
    box.marginbox.height += margin.t+margin.b;
    box.content.y *= -1;
    box.content.y += size.y;
    box.boundingbox.y *= -1;
    box.boundingbox.y += size.y;
    box.content.anchor_y = 1;
    box.boundingbox.anchor_y = 1;
  }

  return boxes;
}

function create_view_fn(base_config)
{
  var base = Object.assign(Object.create(clay_base), base_config);
  return function view(config = {}, fn) {
    config.__proto__ = base;
    var item = add_item(config);

    var prev_item = root_item;
    var prev_config = root_config;
    root_item = item;
    root_config = config;
    root_config._childIndex = 0; // Initialize child index
    fn?.();
    root_item = prev_item;
    root_config = prev_config;
  }
}

clay.vstack = create_view_fn({
  contain: layout.contain.column | layout.contain.start,
});

clay.hstack = create_view_fn({
  contain: layout.contain.row | layout.contain.start,
});

clay.spacer = create_view_fn({
  behave: layout.behave.hfill | layout.behave.vfill
});

function image_size(img)
{
  return [img.rect[2]*img.texture.width, img.rect[3]*img.texture.height]; 
}

function add_item(config)
{
  // Normalize the child's margin
  var margin = util.normalizeSpacing(config.margin || 0);
  var padding = util.normalizeSpacing(config.padding || 0);
  var childGap = root_config.child_gap || 0;

  // Adjust for child_gap
  if (root_config._childIndex > 0) {
    var parentContain = root_config.contain || 0;
    var isVStack = (parentContain & layout.contain.column) != 0;
    var isHStack = (parentContain & layout.contain.row) != 0;

    if (isVStack) {
      margin.t += childGap;
    } else if (isHStack) {
      margin.l += childGap;
    }
  }

  var use_config = Object.create(config);

  use_config.margin = {
    t: margin.t+padding.t,
    b: margin.b+padding.b,
    r:margin.r+padding.r,
    l:margin.l+padding.l
  };

  var item = lay_ctx.item();
  lay_ctx.set_margins(item, use_config.margin);
  lay_ctx.set_size(item,use_config.size);
  lay_ctx.set_contain(item,use_config.contain);
  lay_ctx.set_behave(item,use_config.behave);
  boxes.push({
    id:item,
    config:use_config
  });
  lay_ctx.insert(root_item,item);

  // Increment the parent's child index
  root_config._childIndex++;
  return item;
}

function rectify_configs(config_array)
{
  if (config_array.length == 0)
    config_array = [{}];

  for (var i = config_array.length-1; i > 0; i--)
    config_array[i].__proto__ = config_array[i-1];

  config_array[0].__proto__ = clay_base;
  var cleanobj = Object.create(config_array[config_array.length-1]);

  return cleanobj;
}

clay.image = function image(path, ...configs)
{
  var config = rectify_configs(configs);
  var image = graphics.texture(path);
  config.image = image;  
  config.size ??= [image.texture.width, image.texture.height];
  add_item(config);
}

clay.text = function text(str, ...configs)
{
  var config = rectify_configs(configs);
  config.size ??= [0,0];
  config.font = graphics.get_font(config.font)
  var tsize = config.font.text_size(str, 0, 0, config.size.x);
  config.size = config.size.map((x,i) => Math.max(x, tsize[i]));
  config.text = str;
  add_item(config);
}

/*
  For a given size,
  the layout engine should "see" size + margin
  but its interior content should "see" size - padding
  hence, the layout box should be size-padding, with margin of margin+padding
*/

var button_base = Object.assign(Object.create(clay_base), {
  padding:0,
  hovered:{
  }
});
clay.button = function button(str, action, config = {})
{
  config.__proto__ = button_base;
  config.font = graphics.get_font(config.font)
  config.size = config.font.text_size(str)
  add_item(config);
  config.text = str;
  config.action = action;
}

var hovered = null;
clay.newframe = function() { hovered = null; }

// mousepos given in hud coordinates
clay.draw_commands = function draw_commands(cmds, pos = [0,0], mousepos = prosperon.camera.screen2hud(input.mouse.screenpos()))
{
  for (var cmd of cmds) {
    var config = cmd.config;  
    var boundingbox = geometry.rect_move(cmd.boundingbox,pos.add(config.offset));
    var content = geometry.rect_move(cmd.content,pos.add(config.offset));

    if (config.hovered && geometry.rect_point_inside(boundingbox, mousepos)) {
      config.hovered.__proto__ = config;
      config = config.hovered;
      hovered = config;
    }

    if (config.background_image)
      if (config.slice)
        draw.slice9(config.background_image, boundingbox, config.slice, config.background_color);
      else
        draw.image(config.background_image, boundingbox, 0, config.color);
    else if (config.background_color)
      draw.rectangle(boundingbox, config.background_color);
      
    if (config.text)
      draw.text(config.text, content, config.font, config.font_size, config.color, config.size.x);
    if (config.image)
      draw.image(config.image, content, 0, config.color);
  }
}

var dbg_colors = {};
clay.debug_colors = dbg_colors;
dbg_colors.content = [1,0,0,0.1];
dbg_colors.boundingbox = [0,1,0,0,0.1];
dbg_colors.margin = [0,0,1,0.1];
clay.draw_debug = function draw_debug(cmds, pos = [0,0])
{
  for (var i = 0; i < cmds.length; i++) {
    var cmd = cmds[i];
    var boundingbox = geometry.rect_move(cmd.boundingbox,pos);
    var content = geometry.rect_move(cmd.content,pos);
    draw.rectangle(content, dbg_colors.content);
    draw.rectangle(boundingbox, dbg_colors.boundingbox);
//    draw.rectangle(geometry.rect_move(cmd.marginbox,pos), dbg_colors.margin);
  }
}

clay.inputs = {};
clay.inputs.mouse = {}
clay.inputs.mouse.left = function()
{
  if (hovered && hovered.action) hovered.action();
}

return clay
