/*
 * iNamik Text Tables for Java
 * 
 * Copyright (C) 2016 David Farrell ([email protected])
 *
 * Licensed under The MIT License (MIT), see LICENSE.txt
 */
package top.thinkin.wjcli.show.texttable;

import top.thinkin.wjcli.show.texttable.cell.base.Function;

import java.util.Collection;
import java.util.LinkedList;

/*
 * SimpleTable - Optimized for quick table construction without having to know the
 * final table dimensions beforehand.  It Allows you to build a table one row/cell at
 * a time.
 * 
 * Cell functions do not provide any global context.
 * 
 * You can use toGrid() to convert to GridTable for more complex manipulations.
 */
public class SimpleTable
{
    private LinkedList<LinkedList<Collection<String>>> table = new LinkedList<LinkedList<Collection<String>>>();
    private int numRows = 0;
    private int numCols = 0;
    
    public static SimpleTable of() { return new SimpleTable(); }

    public SimpleTable() { /* Empty */ }

    public SimpleTable nextRow() {
        LinkedList<Collection<String>> row = new LinkedList<Collection<String>>();
        table.add(row);
        numRows++;
        return this;
    }

    public SimpleTable nextCell() {
        if (table.isEmpty()) {
            throw new IllegalStateException("Table is empty. Call nextRow() first");
        }
        final LinkedList<Collection<String>> row = table.getLast();
        row.add(Cell.EMPTY);
        numCols = Math.max(numCols, row.size());
        return this;
    }

    public SimpleTable nextCell(String...lines) {
        return nextCell().addLines(lines);
    }
    
    public SimpleTable nextCell(Collection<String> lines) {
        return nextCell().addLines(lines);
    }

    public SimpleTable addLine(String line) {
        if (table.isEmpty()) {
            throw new IllegalStateException("Table is empty. Call nextRow() first");
        }
        LinkedList<Collection<String>> row = table.getLast();
        if (row.isEmpty()) {
            throw new IllegalStateException("Row is empty.  Call nextCell() first");
        }
        Collection<String> cell = row.removeLast();
        cell = Cell.append(cell, line);
        row.add(cell);
        return this;
    }

    public SimpleTable addLines(String...lines) {
        if (table.isEmpty()) {
            throw new IllegalStateException("Table is empty. Call nextRow() first");
        }
        LinkedList<Collection<String>> row = table.getLast();
        if (row.isEmpty()) {
            throw new IllegalStateException("Row is empty.  Call nextCell() first");
        }
        Collection<String> cell = row.removeLast();
        cell = Cell.append(cell, lines);
        row.add(cell);
        return this;
    }

    public SimpleTable addLines(Collection<String> lines) {
        if (table.isEmpty()) {
            throw new IllegalStateException("Table is empty. Call nextRow() first");
        }
        LinkedList<Collection<String>> row = table.getLast();
        if (row.isEmpty()) {
            throw new IllegalStateException("Row is empty.  Call nextCell() first");
        }
        Collection<String> cell = row.removeLast();
        cell = Cell.append(cell, lines);
        row.add(cell);
        return this;
    }

    public SimpleTable applyToCell(Function f) {
        if (table.isEmpty()) {
            throw new IllegalStateException("Table is empty. Call nextRow() first");
        }
        LinkedList<Collection<String>> row = table.getLast();
        if (row.isEmpty()) {
            throw new IllegalStateException("Row is empty.  Call nextCell() first");
        }
        Collection<String> cell = row.removeLast();
        cell = f.apply(cell);
        row.add(cell);
        return this;
    }

    public SimpleTable applyToCell(Cell.Function f) {
        if (table.isEmpty()) {
            throw new IllegalStateException("Table is empty. Call nextRow() first");
        }
        LinkedList<Collection<String>> row = table.getLast();
        if (row.isEmpty()) {
            throw new IllegalStateException("Row is empty.  Call nextCell() first");
        }
        Collection<String> cell = row.removeLast();
        cell = f.apply(cell);
        row.add(cell);
        return this;
    }

    public int nextRowNum() { return table.size(); }

    public int nextColNum() { return (table.isEmpty()) ? 0 : table.getLast().size(); }

    public int numRows() { return numRows; }

    public int numCols() { return numCols; }

    public GridTable toGrid() {
        GridTable grid = GridTable.of(numRows, numCols);
        int rowNum = 0;
        for (LinkedList<Collection<String>> row: table) {
            int colNum = 0;
            for (Collection<String> cell: row) {
                grid.put(rowNum, colNum, cell);
                colNum++;
            }
            rowNum++;
        }
        return grid;        
    }

}