11cb0ef41Sopenharmony_ciconst { warn, debug } = require('./debug');
21cb0ef41Sopenharmony_ciconst Cell = require('./cell');
31cb0ef41Sopenharmony_ciconst { ColSpanCell, RowSpanCell } = Cell;
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci(function () {
61cb0ef41Sopenharmony_ci  function next(alloc, col) {
71cb0ef41Sopenharmony_ci    if (alloc[col] > 0) {
81cb0ef41Sopenharmony_ci      return next(alloc, col + 1);
91cb0ef41Sopenharmony_ci    }
101cb0ef41Sopenharmony_ci    return col;
111cb0ef41Sopenharmony_ci  }
121cb0ef41Sopenharmony_ci
131cb0ef41Sopenharmony_ci  function layoutTable(table) {
141cb0ef41Sopenharmony_ci    let alloc = {};
151cb0ef41Sopenharmony_ci    table.forEach(function (row, rowIndex) {
161cb0ef41Sopenharmony_ci      let col = 0;
171cb0ef41Sopenharmony_ci      row.forEach(function (cell) {
181cb0ef41Sopenharmony_ci        cell.y = rowIndex;
191cb0ef41Sopenharmony_ci        // Avoid erroneous call to next() on first row
201cb0ef41Sopenharmony_ci        cell.x = rowIndex ? next(alloc, col) : col;
211cb0ef41Sopenharmony_ci        const rowSpan = cell.rowSpan || 1;
221cb0ef41Sopenharmony_ci        const colSpan = cell.colSpan || 1;
231cb0ef41Sopenharmony_ci        if (rowSpan > 1) {
241cb0ef41Sopenharmony_ci          for (let cs = 0; cs < colSpan; cs++) {
251cb0ef41Sopenharmony_ci            alloc[cell.x + cs] = rowSpan;
261cb0ef41Sopenharmony_ci          }
271cb0ef41Sopenharmony_ci        }
281cb0ef41Sopenharmony_ci        col = cell.x + colSpan;
291cb0ef41Sopenharmony_ci      });
301cb0ef41Sopenharmony_ci      Object.keys(alloc).forEach((idx) => {
311cb0ef41Sopenharmony_ci        alloc[idx]--;
321cb0ef41Sopenharmony_ci        if (alloc[idx] < 1) delete alloc[idx];
331cb0ef41Sopenharmony_ci      });
341cb0ef41Sopenharmony_ci    });
351cb0ef41Sopenharmony_ci  }
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_ci  function maxWidth(table) {
381cb0ef41Sopenharmony_ci    let mw = 0;
391cb0ef41Sopenharmony_ci    table.forEach(function (row) {
401cb0ef41Sopenharmony_ci      row.forEach(function (cell) {
411cb0ef41Sopenharmony_ci        mw = Math.max(mw, cell.x + (cell.colSpan || 1));
421cb0ef41Sopenharmony_ci      });
431cb0ef41Sopenharmony_ci    });
441cb0ef41Sopenharmony_ci    return mw;
451cb0ef41Sopenharmony_ci  }
461cb0ef41Sopenharmony_ci
471cb0ef41Sopenharmony_ci  function maxHeight(table) {
481cb0ef41Sopenharmony_ci    return table.length;
491cb0ef41Sopenharmony_ci  }
501cb0ef41Sopenharmony_ci
511cb0ef41Sopenharmony_ci  function cellsConflict(cell1, cell2) {
521cb0ef41Sopenharmony_ci    let yMin1 = cell1.y;
531cb0ef41Sopenharmony_ci    let yMax1 = cell1.y - 1 + (cell1.rowSpan || 1);
541cb0ef41Sopenharmony_ci    let yMin2 = cell2.y;
551cb0ef41Sopenharmony_ci    let yMax2 = cell2.y - 1 + (cell2.rowSpan || 1);
561cb0ef41Sopenharmony_ci    let yConflict = !(yMin1 > yMax2 || yMin2 > yMax1);
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ci    let xMin1 = cell1.x;
591cb0ef41Sopenharmony_ci    let xMax1 = cell1.x - 1 + (cell1.colSpan || 1);
601cb0ef41Sopenharmony_ci    let xMin2 = cell2.x;
611cb0ef41Sopenharmony_ci    let xMax2 = cell2.x - 1 + (cell2.colSpan || 1);
621cb0ef41Sopenharmony_ci    let xConflict = !(xMin1 > xMax2 || xMin2 > xMax1);
631cb0ef41Sopenharmony_ci
641cb0ef41Sopenharmony_ci    return yConflict && xConflict;
651cb0ef41Sopenharmony_ci  }
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_ci  function conflictExists(rows, x, y) {
681cb0ef41Sopenharmony_ci    let i_max = Math.min(rows.length - 1, y);
691cb0ef41Sopenharmony_ci    let cell = { x: x, y: y };
701cb0ef41Sopenharmony_ci    for (let i = 0; i <= i_max; i++) {
711cb0ef41Sopenharmony_ci      let row = rows[i];
721cb0ef41Sopenharmony_ci      for (let j = 0; j < row.length; j++) {
731cb0ef41Sopenharmony_ci        if (cellsConflict(cell, row[j])) {
741cb0ef41Sopenharmony_ci          return true;
751cb0ef41Sopenharmony_ci        }
761cb0ef41Sopenharmony_ci      }
771cb0ef41Sopenharmony_ci    }
781cb0ef41Sopenharmony_ci    return false;
791cb0ef41Sopenharmony_ci  }
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_ci  function allBlank(rows, y, xMin, xMax) {
821cb0ef41Sopenharmony_ci    for (let x = xMin; x < xMax; x++) {
831cb0ef41Sopenharmony_ci      if (conflictExists(rows, x, y)) {
841cb0ef41Sopenharmony_ci        return false;
851cb0ef41Sopenharmony_ci      }
861cb0ef41Sopenharmony_ci    }
871cb0ef41Sopenharmony_ci    return true;
881cb0ef41Sopenharmony_ci  }
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_ci  function addRowSpanCells(table) {
911cb0ef41Sopenharmony_ci    table.forEach(function (row, rowIndex) {
921cb0ef41Sopenharmony_ci      row.forEach(function (cell) {
931cb0ef41Sopenharmony_ci        for (let i = 1; i < cell.rowSpan; i++) {
941cb0ef41Sopenharmony_ci          let rowSpanCell = new RowSpanCell(cell);
951cb0ef41Sopenharmony_ci          rowSpanCell.x = cell.x;
961cb0ef41Sopenharmony_ci          rowSpanCell.y = cell.y + i;
971cb0ef41Sopenharmony_ci          rowSpanCell.colSpan = cell.colSpan;
981cb0ef41Sopenharmony_ci          insertCell(rowSpanCell, table[rowIndex + i]);
991cb0ef41Sopenharmony_ci        }
1001cb0ef41Sopenharmony_ci      });
1011cb0ef41Sopenharmony_ci    });
1021cb0ef41Sopenharmony_ci  }
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_ci  function addColSpanCells(cellRows) {
1051cb0ef41Sopenharmony_ci    for (let rowIndex = cellRows.length - 1; rowIndex >= 0; rowIndex--) {
1061cb0ef41Sopenharmony_ci      let cellColumns = cellRows[rowIndex];
1071cb0ef41Sopenharmony_ci      for (let columnIndex = 0; columnIndex < cellColumns.length; columnIndex++) {
1081cb0ef41Sopenharmony_ci        let cell = cellColumns[columnIndex];
1091cb0ef41Sopenharmony_ci        for (let k = 1; k < cell.colSpan; k++) {
1101cb0ef41Sopenharmony_ci          let colSpanCell = new ColSpanCell();
1111cb0ef41Sopenharmony_ci          colSpanCell.x = cell.x + k;
1121cb0ef41Sopenharmony_ci          colSpanCell.y = cell.y;
1131cb0ef41Sopenharmony_ci          cellColumns.splice(columnIndex + 1, 0, colSpanCell);
1141cb0ef41Sopenharmony_ci        }
1151cb0ef41Sopenharmony_ci      }
1161cb0ef41Sopenharmony_ci    }
1171cb0ef41Sopenharmony_ci  }
1181cb0ef41Sopenharmony_ci
1191cb0ef41Sopenharmony_ci  function insertCell(cell, row) {
1201cb0ef41Sopenharmony_ci    let x = 0;
1211cb0ef41Sopenharmony_ci    while (x < row.length && row[x].x < cell.x) {
1221cb0ef41Sopenharmony_ci      x++;
1231cb0ef41Sopenharmony_ci    }
1241cb0ef41Sopenharmony_ci    row.splice(x, 0, cell);
1251cb0ef41Sopenharmony_ci  }
1261cb0ef41Sopenharmony_ci
1271cb0ef41Sopenharmony_ci  function fillInTable(table) {
1281cb0ef41Sopenharmony_ci    let h_max = maxHeight(table);
1291cb0ef41Sopenharmony_ci    let w_max = maxWidth(table);
1301cb0ef41Sopenharmony_ci    debug(`Max rows: ${h_max}; Max cols: ${w_max}`);
1311cb0ef41Sopenharmony_ci    for (let y = 0; y < h_max; y++) {
1321cb0ef41Sopenharmony_ci      for (let x = 0; x < w_max; x++) {
1331cb0ef41Sopenharmony_ci        if (!conflictExists(table, x, y)) {
1341cb0ef41Sopenharmony_ci          let opts = { x: x, y: y, colSpan: 1, rowSpan: 1 };
1351cb0ef41Sopenharmony_ci          x++;
1361cb0ef41Sopenharmony_ci          while (x < w_max && !conflictExists(table, x, y)) {
1371cb0ef41Sopenharmony_ci            opts.colSpan++;
1381cb0ef41Sopenharmony_ci            x++;
1391cb0ef41Sopenharmony_ci          }
1401cb0ef41Sopenharmony_ci          let y2 = y + 1;
1411cb0ef41Sopenharmony_ci          while (y2 < h_max && allBlank(table, y2, opts.x, opts.x + opts.colSpan)) {
1421cb0ef41Sopenharmony_ci            opts.rowSpan++;
1431cb0ef41Sopenharmony_ci            y2++;
1441cb0ef41Sopenharmony_ci          }
1451cb0ef41Sopenharmony_ci          let cell = new Cell(opts);
1461cb0ef41Sopenharmony_ci          cell.x = opts.x;
1471cb0ef41Sopenharmony_ci          cell.y = opts.y;
1481cb0ef41Sopenharmony_ci          warn(`Missing cell at ${cell.y}-${cell.x}.`);
1491cb0ef41Sopenharmony_ci          insertCell(cell, table[y]);
1501cb0ef41Sopenharmony_ci        }
1511cb0ef41Sopenharmony_ci      }
1521cb0ef41Sopenharmony_ci    }
1531cb0ef41Sopenharmony_ci  }
1541cb0ef41Sopenharmony_ci
1551cb0ef41Sopenharmony_ci  function generateCells(rows) {
1561cb0ef41Sopenharmony_ci    return rows.map(function (row) {
1571cb0ef41Sopenharmony_ci      if (!Array.isArray(row)) {
1581cb0ef41Sopenharmony_ci        let key = Object.keys(row)[0];
1591cb0ef41Sopenharmony_ci        row = row[key];
1601cb0ef41Sopenharmony_ci        if (Array.isArray(row)) {
1611cb0ef41Sopenharmony_ci          row = row.slice();
1621cb0ef41Sopenharmony_ci          row.unshift(key);
1631cb0ef41Sopenharmony_ci        } else {
1641cb0ef41Sopenharmony_ci          row = [key, row];
1651cb0ef41Sopenharmony_ci        }
1661cb0ef41Sopenharmony_ci      }
1671cb0ef41Sopenharmony_ci      return row.map(function (cell) {
1681cb0ef41Sopenharmony_ci        return new Cell(cell);
1691cb0ef41Sopenharmony_ci      });
1701cb0ef41Sopenharmony_ci    });
1711cb0ef41Sopenharmony_ci  }
1721cb0ef41Sopenharmony_ci
1731cb0ef41Sopenharmony_ci  function makeTableLayout(rows) {
1741cb0ef41Sopenharmony_ci    let cellRows = generateCells(rows);
1751cb0ef41Sopenharmony_ci    layoutTable(cellRows);
1761cb0ef41Sopenharmony_ci    fillInTable(cellRows);
1771cb0ef41Sopenharmony_ci    addRowSpanCells(cellRows);
1781cb0ef41Sopenharmony_ci    addColSpanCells(cellRows);
1791cb0ef41Sopenharmony_ci    return cellRows;
1801cb0ef41Sopenharmony_ci  }
1811cb0ef41Sopenharmony_ci
1821cb0ef41Sopenharmony_ci  module.exports = {
1831cb0ef41Sopenharmony_ci    makeTableLayout: makeTableLayout,
1841cb0ef41Sopenharmony_ci    layoutTable: layoutTable,
1851cb0ef41Sopenharmony_ci    addRowSpanCells: addRowSpanCells,
1861cb0ef41Sopenharmony_ci    maxWidth: maxWidth,
1871cb0ef41Sopenharmony_ci    fillInTable: fillInTable,
1881cb0ef41Sopenharmony_ci    computeWidths: makeComputeWidths('colSpan', 'desiredWidth', 'x', 1),
1891cb0ef41Sopenharmony_ci    computeHeights: makeComputeWidths('rowSpan', 'desiredHeight', 'y', 1),
1901cb0ef41Sopenharmony_ci  };
1911cb0ef41Sopenharmony_ci})();
1921cb0ef41Sopenharmony_ci
1931cb0ef41Sopenharmony_cifunction makeComputeWidths(colSpan, desiredWidth, x, forcedMin) {
1941cb0ef41Sopenharmony_ci  return function (vals, table) {
1951cb0ef41Sopenharmony_ci    let result = [];
1961cb0ef41Sopenharmony_ci    let spanners = [];
1971cb0ef41Sopenharmony_ci    let auto = {};
1981cb0ef41Sopenharmony_ci    table.forEach(function (row) {
1991cb0ef41Sopenharmony_ci      row.forEach(function (cell) {
2001cb0ef41Sopenharmony_ci        if ((cell[colSpan] || 1) > 1) {
2011cb0ef41Sopenharmony_ci          spanners.push(cell);
2021cb0ef41Sopenharmony_ci        } else {
2031cb0ef41Sopenharmony_ci          result[cell[x]] = Math.max(result[cell[x]] || 0, cell[desiredWidth] || 0, forcedMin);
2041cb0ef41Sopenharmony_ci        }
2051cb0ef41Sopenharmony_ci      });
2061cb0ef41Sopenharmony_ci    });
2071cb0ef41Sopenharmony_ci
2081cb0ef41Sopenharmony_ci    vals.forEach(function (val, index) {
2091cb0ef41Sopenharmony_ci      if (typeof val === 'number') {
2101cb0ef41Sopenharmony_ci        result[index] = val;
2111cb0ef41Sopenharmony_ci      }
2121cb0ef41Sopenharmony_ci    });
2131cb0ef41Sopenharmony_ci
2141cb0ef41Sopenharmony_ci    //spanners.forEach(function(cell){
2151cb0ef41Sopenharmony_ci    for (let k = spanners.length - 1; k >= 0; k--) {
2161cb0ef41Sopenharmony_ci      let cell = spanners[k];
2171cb0ef41Sopenharmony_ci      let span = cell[colSpan];
2181cb0ef41Sopenharmony_ci      let col = cell[x];
2191cb0ef41Sopenharmony_ci      let existingWidth = result[col];
2201cb0ef41Sopenharmony_ci      let editableCols = typeof vals[col] === 'number' ? 0 : 1;
2211cb0ef41Sopenharmony_ci      if (typeof existingWidth === 'number') {
2221cb0ef41Sopenharmony_ci        for (let i = 1; i < span; i++) {
2231cb0ef41Sopenharmony_ci          existingWidth += 1 + result[col + i];
2241cb0ef41Sopenharmony_ci          if (typeof vals[col + i] !== 'number') {
2251cb0ef41Sopenharmony_ci            editableCols++;
2261cb0ef41Sopenharmony_ci          }
2271cb0ef41Sopenharmony_ci        }
2281cb0ef41Sopenharmony_ci      } else {
2291cb0ef41Sopenharmony_ci        existingWidth = desiredWidth === 'desiredWidth' ? cell.desiredWidth - 1 : 1;
2301cb0ef41Sopenharmony_ci        if (!auto[col] || auto[col] < existingWidth) {
2311cb0ef41Sopenharmony_ci          auto[col] = existingWidth;
2321cb0ef41Sopenharmony_ci        }
2331cb0ef41Sopenharmony_ci      }
2341cb0ef41Sopenharmony_ci
2351cb0ef41Sopenharmony_ci      if (cell[desiredWidth] > existingWidth) {
2361cb0ef41Sopenharmony_ci        let i = 0;
2371cb0ef41Sopenharmony_ci        while (editableCols > 0 && cell[desiredWidth] > existingWidth) {
2381cb0ef41Sopenharmony_ci          if (typeof vals[col + i] !== 'number') {
2391cb0ef41Sopenharmony_ci            let dif = Math.round((cell[desiredWidth] - existingWidth) / editableCols);
2401cb0ef41Sopenharmony_ci            existingWidth += dif;
2411cb0ef41Sopenharmony_ci            result[col + i] += dif;
2421cb0ef41Sopenharmony_ci            editableCols--;
2431cb0ef41Sopenharmony_ci          }
2441cb0ef41Sopenharmony_ci          i++;
2451cb0ef41Sopenharmony_ci        }
2461cb0ef41Sopenharmony_ci      }
2471cb0ef41Sopenharmony_ci    }
2481cb0ef41Sopenharmony_ci
2491cb0ef41Sopenharmony_ci    Object.assign(vals, result, auto);
2501cb0ef41Sopenharmony_ci    for (let j = 0; j < vals.length; j++) {
2511cb0ef41Sopenharmony_ci      vals[j] = Math.max(forcedMin, vals[j] || 0);
2521cb0ef41Sopenharmony_ci    }
2531cb0ef41Sopenharmony_ci  };
2541cb0ef41Sopenharmony_ci}
255