#include <ui.h>

#include "uiLibrary.h"
#include "widget/table.h"
#include "widget/widget.h"

#include <cassert.h>

static void ResizeTable(uiTable* table, int width, int height) {
  assert(table);

  if (table->cols == 0) {
    return;
  }

  // Determine if there is vertical overflow. This determines whether we need to
  // render a scroll bar, in which case room must be made for it.
  table->flags.vertical_overflow =
      (table->rows * g_ui.font->header.glyph_height) >
      table->widget.rect.height;

  // Surface width: W.
  // Columns: N
  //
  // First, find the minimum width of each column based on their contents.
  //
  // If the sum of column widths < N, then distribute the extra space first
  // among the smallest columns and building up towards the larger.
  //
  // If the sum of column widths > N, subtract from the largest column first and
  // move towards the smaller ones to distribute the space as evenly as
  // possible.

  // Find the minimum width for each column.
  int* widths = table->widths;
  // Header.
  for (int col = 0; col < table->cols; ++col) {
    const uiCell*  cell   = &table->header[col];
    const uiLabel* label  = (uiLabel*)cell->child;
    const int      length = (int)string_length(label->text);

    widths[col] = length;
  }
  // Table contents.
  for (int row = 0; row < table->rows; ++row) {
    for (int col = 0; col < table->cols; ++col) {
      const uiCell* cell = GetCell(table, row, col);
      if (cell->child) {
        const uiLabel* label  = (uiLabel*)cell->child;
        const int      length = (int)string_length(label->text);

        widths[col] = length > widths[col] ? length : widths[col];
      }
    }
  }
  // Multiply string lengths times glyph width to compute pixel size.
  for (int col = 0; col < table->cols; ++col) {
    widths[col] *= g_ui.font->header.glyph_width;
  }

  // Find the sum of widths.
  int used_width = 0;
  for (int col = 0; col < table->cols; ++col) {
    used_width += widths[col];
  }

  // Pad if available width is larger than sum of widths.
  if (used_width < width) {
    // Divide evenly among columns.
    // const int extra = width - used_width;
    //    const int pad   = extra / table->cols;
    //    const int mod   = extra % table->cols;
    //    for (int col = 0; col < table->cols; ++col) {
    //      table->widths[col] += pad + (col < mod ? 1 : 0);
    //    }

    int extra = width - used_width;
    while (extra > 0) {
      // Find smallest column.
      int smallest = 0;
      for (int col = 1; col < table->cols; ++col) {
        if (widths[col] < widths[smallest]) {
          smallest = col;
        }
      }
      // Pad it and subtract from the budget.
      widths[smallest] += 1;
      extra--;
    }
  }
  // Shrink if available width is smaller than the sum of widths.
  else if (used_width > width) {
    int deficit = used_width - width;
    while (deficit > 0) {
      // Find largest column.
      int largest = 0;
      for (int col = 1; col < table->cols; ++col) {
        if (widths[col] > widths[largest]) {
          largest = col;
        }
      }
      // Shrink it and subtract from the deficit.
      widths[largest] -= 1;
      deficit--;
    }
  }

  // Now make room for the scroll bar, if necessary.
  if (table->flags.vertical_overflow) {
    const int offset    = ScrollBarWidth / table->cols;
    const int remainder = ScrollBarWidth % table->cols;
    for (int col = 0; col < table->cols; ++col) {
      table->widths[col] -= offset + (col < remainder ? 1 : 0);
      assert(table->widths[col] >= 0);
    }
  }
}

static void ResizeWidget(uiWidget* widget, int width, int height) {
  assert(widget);

  widget->rect.width  = width;
  widget->rect.height = height;

  switch (widget->type) {
  case uiTypeButton:
    break;
  case uiTypeFrame:
    list_foreach_mut(
        widget->children, child, { ResizeWidget(child, width, height); });
    break;
  case uiTypeLabel:
    break;
  case uiTypeTable:
    ResizeTable((uiTable*)widget, width, height);
    break;
  case uiTypeMax:
    TRAP();
    break;
  }
}

void uiResizeFrame(uiFrame* frame, int width, int height) {
  assert(frame);
  ResizeWidget(&frame->widget, width, height);
}