protected function calculateColLengths($columns)
    {
        $idx = 0;
        $border = $this->strlen($this->border);
        $fixed = (count($columns) - 1) * $border; // borders are used already
        $fluid = -1;

        // first pass for format check and fixed columns
        foreach ($columns as $idx => $col) {
            // handle fixed columns
            if ((string)intval($col) === (string)$col) {
                $fixed += $col;
                continue;
            }
            // check if other colums are using proper units
            if (substr($col, -1) == '%') {
                continue;
            }
            if ($col == '*') {
                // only one fluid
                if ($fluid < 0) {
                    $fluid = $idx;
                    continue;
                } else {
                    throw new Exception('Only one fluid column allowed!');
                }
            }
            throw new Exception("unknown column format $col");
        }

        $alloc = $fixed;
        $remain = $this->max - $alloc;

        // second pass to handle percentages
        foreach ($columns as $idx => $col) {
            if (substr($col, -1) != '%') {
                continue;
            }
            $perc = floatval($col);

            $real = (int)floor(($perc * $remain) / 100);

            $columns[$idx] = $real;
            $alloc += $real;
        }

        $remain = $this->max - $alloc;
        if ($remain < 0) {
            throw new Exception("Wanted column widths exceed available space");
        }

        // assign remaining space
        if ($fluid < 0) {
            $columns[$idx] += ($remain); // add to last column
        } else {
            $columns[$fluid] = $remain;
        }

        return $columns;
    }