/*
 * SDK Pullenti Unitext, version 4.33, fabruary 2026. Copyright (c) 2013-2026, Pullenti. All rights reserved. 
 * Non-Commercial Freeware and Commercial Software. 
 * This class is generated using the converter Unisharping (www.unisharping.ru) from Pullenti C# project. 
 * The latest version of the code is available on the site www.pullenti.ru
 */

package com.pullenti.unitext;

/**
 * Таблица, представляет собой матрицу из клеток. 
 * Ячейки могут заполнять прямоугольные области из клеток. 
 * Ячейки не могут пересекаться друг с другом.
 * Таблица
 */
public class UnitextTable extends UnitextItem {

    @Override
    public UnitextItem optimize(boolean isContent, CreateDocumentParam pars) {
        if (m_ColsCount == 3 && m_Cells.size() == 2) {
        }
        for (java.util.ArrayList<UnitextTablecell> ro : m_Cells) {
            for (UnitextTablecell c : ro) {
                if (c != null) 
                    c.optimize(false, pars);
            }
        }
        if (pars != null && !pars.correctParams.removeEmptyTables) 
            return this;
        if (m_Cells.size() == 0) 
            return null;
        if (ignorable) 
            return this;
        for (int r = 0; r < m_Cells.size(); r++) {
            for (int c = 0; c < m_Cells.get(r).size(); c++) {
                if (m_Cells.get(r).get(c) != null) 
                    continue;
                int cc;
                for (cc = c + 1; cc < m_Cells.get(r).size(); cc++) {
                    if (m_Cells.get(r).get(cc) != null) 
                        break;
                }
                this.addCell(r, r, c, cc - 1, null, false);
            }
            if (m_Cells.get(r).size() < m_ColsCount) 
                this.addCell(r, r, m_Cells.get(r).size(), m_ColsCount - 1, null, false);
        }
        int colsCount0 = getColsCount();
        int rowCount0 = getRowsCount();
        for (int i = m_ColsCount - 1; i >= 0; i--) {
            int r;
            for (r = 0; r < m_Cells.size(); r++) {
                UnitextTablecell c = m_Cells.get(r).get(i);
                if (c == null) 
                    continue;
                if (c.content != null) {
                    if (c.getColBegin() == i) 
                        break;
                }
            }
            if (r < m_Cells.size()) 
                continue;
            for (r = 0; r < m_Cells.size(); r++) {
                for (int c = 0; c < m_Cells.get(r).size(); c++) {
                    UnitextTablecell ce = m_Cells.get(r).get(c);
                    if (ce == null) 
                        continue;
                    if (ce.getColBegin() != c || ce.getRowBegin() != r) 
                        continue;
                    if (ce.getColBegin() >= i) 
                        ce.setColBegin(ce.getColBegin() - 1);
                    if (ce.getColEnd() >= i) 
                        ce.setColEnd(ce.getColEnd() - 1);
                }
            }
            for (r = 0; r < m_Cells.size(); r++) {
                UnitextTablecell col = m_Cells.get(r).get(i);
                if (col.m_StyledFrag != null) {
                }
                m_Cells.get(r).remove(i);
            }
            m_ColsCount--;
        }
        for (int r = m_Cells.size() - 1; r >= 0; r--) {
            int i;
            for (i = 0; i < m_Cells.get(r).size(); i++) {
                UnitextTablecell cel = m_Cells.get(r).get(i);
                if (cel == null) 
                    continue;
                if (cel.getRowBegin() == r && cel.getColBegin() == i) {
                    if (cel.content != null) {
                        UnitextContainer cnt = (UnitextContainer)com.pullenti.unisharp.Utils.cast(cel.content, UnitextContainer.class);
                        if (cnt != null && cnt.children.size() > 0 && (cnt.children.get(0) instanceof UnitextPlaintext)) {
                            if (com.pullenti.unisharp.Utils.startsWithString(((UnitextPlaintext)com.pullenti.unisharp.Utils.cast(cnt.children.get(0), UnitextPlaintext.class)).text, "КОНСУЛЬТАНТПЛЮС", true)) {
                                if (m_Cells.size() < 4) 
                                    ignorable = true;
                                for (int j = 0; j < m_Cells.get(r).size(); j++) {
                                    if (m_Cells.get(r).get(j) != null) 
                                        m_Cells.get(r).get(j).ignorable = true;
                                }
                            }
                        }
                        break;
                    }
                }
            }
            if (i < m_Cells.get(r).size()) 
                continue;
            for (int rr = 0; rr < m_Cells.size(); rr++) {
                for (int c = 0; c < m_Cells.get(r).size(); c++) {
                    UnitextTablecell col = m_Cells.get(rr).get(c);
                    if (col == null) 
                        continue;
                    if (col.getColBegin() != c || col.getRowBegin() != rr) 
                        continue;
                    if (col.getRowBegin() >= r) 
                        col.setRowBegin(col.getRowBegin() - 1);
                    if (col.getRowEnd() >= r) 
                        col.setRowEnd(col.getRowEnd() - 1);
                    if (col.content != null) 
                        continue;
                    if (col.m_StyledFrag != null) {
                        if (col.m_StyledFrag.parent != null && col.m_StyledFrag.parent.children.contains(col.m_StyledFrag)) 
                            col.m_StyledFrag.parent.children.remove(col.m_StyledFrag);
                    }
                }
            }
            m_Cells.remove(r);
        }
        if (m_ColsCount == 1) {
            if (ignorable) 
                return this;
            UnitextContainer cnt = new UnitextContainer();
            cnt.setInline(false);
            for (int r = 0; r < m_Cells.size(); r++) {
                if (m_Cells.get(r).get(0).content != null && m_Cells.get(r).get(0).getRowBegin() == r) {
                    cnt.children.add(m_Cells.get(r).get(0).content);
                    cnt.children.add(UnitextNewline._new635(cnt));
                }
            }
            if (colsCount0 == 4 && rowCount0 == 1) {
                String str = cnt.getPlaintextString(GetPlaintextParam._new357(false));
                if (str != null) {
                    if ((com.pullenti.unisharp.Utils.startsWithString(str, "ПО ВОПРОС", true) || (str.indexOf("вступает в силу") >= 0) || (str.indexOf("вступают в силу") >= 0)) || (str.indexOf("утратил силу") >= 0) || (str.indexOf("утратила силу") >= 0)) {
                        ignorable = true;
                        return this;
                    }
                }
            }
            cnt.children.add(0, UnitextNewline._new635(cnt));
            return cnt.optimize(false, pars);
        }
        if (m_ColsCount == 0) 
            return null;
        if (pars != null && pars.splitTableRows) {
            for (int r = 0; r < getRowsCount(); r++) {
                int c;
                int ppp = 0;
                int cou = 0;
                for (c = 0; c < getColsCount(); c++) {
                    UnitextTablecell cel = this.getCell(r, c);
                    if (cel == null) 
                        break;
                    if (cel.getColBegin() != cel.getColEnd() || cel.getRowBegin() != cel.getRowEnd()) 
                        break;
                    if (cel.content == null) 
                        continue;
                    UnitextContainer cnt = (UnitextContainer)com.pullenti.unisharp.Utils.cast(cel.content, UnitextContainer.class);
                    if (cnt == null) 
                        break;
                    int i;
                    int p = 0;
                    for (i = 0; i < cnt.children.size(); i++) {
                        UnitextItem ch = cnt.children.get(i);
                        if (((ch instanceof UnitextPlaintext) || (ch instanceof UnitextHyperlink) || (ch instanceof UnitextImage)) || (ch instanceof UnitextPagebreak)) {
                        }
                        else if (ch instanceof UnitextNewline) {
                            if (((UnitextNewline)com.pullenti.unisharp.Utils.cast(ch, UnitextNewline.class)).count > 1) 
                                p++;
                        }
                        else 
                            break;
                    }
                    if (i < cnt.children.size()) 
                        break;
                    if (p == 0) 
                        break;
                    if (ppp == 0) 
                        ppp = p;
                    else if (ppp != p) 
                        break;
                    cou++;
                }
                if ((c < getColsCount()) || ppp == 0 || (cou < 2)) 
                    continue;
                java.util.ArrayList<UnitextTablecell> nrow = new java.util.ArrayList<UnitextTablecell>();
                for (int rr = r + 1; rr < m_Cells.size(); rr++) {
                    for (c = 0; c < getColsCount(); c++) {
                        if (m_Cells.get(rr).get(c) != null) 
                            m_Cells.get(rr).get(c).tag = null;
                    }
                }
                for (int rr = r + 1; rr < m_Cells.size(); rr++) {
                    for (c = 0; c < getColsCount(); c++) {
                        if (m_Cells.get(rr).get(c) != null && m_Cells.get(rr).get(c).tag == null) {
                            m_Cells.get(rr).get(c).tag = m_Cells;
                            m_Cells.get(rr).get(c).setRowBegin(m_Cells.get(rr).get(c).getRowBegin() + 1);
                            m_Cells.get(rr).get(c).setRowEnd(m_Cells.get(rr).get(c).getRowEnd() + 1);
                        }
                    }
                }
                m_Cells.add(r + 1, nrow);
                for (c = 0; c < getColsCount(); c++) {
                    UnitextTablecell cel = this.getCell(r, c);
                    UnitextTablecell cel1 = UnitextTablecell._new638(true, c, c, r + 1, r + 1);
                    nrow.add(cel1);
                    if (cel.content == null) 
                        continue;
                    UnitextContainer cnt = (UnitextContainer)com.pullenti.unisharp.Utils.cast(cel.content, UnitextContainer.class);
                    int i;
                    for (i = cnt.children.size() - 1; i >= 0; i--) {
                        if (cnt.children.get(i) instanceof UnitextPagebreak) 
                            cnt.children.remove(i);
                    }
                    for (i = 0; i < cnt.children.size(); i++) {
                        if ((cnt.children.get(i) instanceof UnitextNewline) && ((UnitextNewline)com.pullenti.unisharp.Utils.cast(cnt.children.get(i), UnitextNewline.class)).count > 1) 
                            break;
                    }
                    if (i >= cnt.children.size()) 
                        continue;
                    if (i == 1) {
                        cel1.content = cnt;
                        cel.content = cnt.children.get(0);
                        cnt.children.remove(0);
                        cnt.children.remove(0);
                        cel1.content = cel1.content.optimize(true, pars);
                    }
                    else {
                        UnitextContainer cnt1 = new UnitextContainer();
                        for (int ii = i + 1; ii < cnt.children.size(); ii++) {
                            cnt1.children.add(cnt.children.get(ii));
                        }
                        for(int jjj = i + cnt.children.size() - i - 1, mmm = i; jjj >= mmm; jjj--) cnt.children.remove(jjj);
                        cel1.content = cnt1.optimize(true, pars);
                    }
                }
            }
        }
        if (m_ColsCount > 1 && getRowsCount() > 10) {
            int i;
            boolean ok = false;
            for (i = 0; i < getRowsCount(); i++) {
                if ((m_Cells.get(i) != null && m_Cells.get(i).size() > 0 && m_Cells.get(i).get(0).getColBegin() == 0) && m_Cells.get(i).get(0).getColEnd() == (getColsCount() - 1)) {
                    if (i == 0 && m_Cells.get(i).get(0).content != null) {
                        String str = m_Cells.get(i).get(0).content.getPlaintextString(null).trim();
                        if (com.pullenti.unisharp.Utils.startsWithString(str, "РАЗДЕЛ", true) || com.pullenti.unisharp.Utils.startsWithString(str, "ПОДРАЗДЕЛ", true) || com.pullenti.unisharp.Utils.startsWithString(str, "ГЛАВА", true)) 
                            ok = true;
                    }
                }
                else 
                    break;
            }
            if (i > ((getRowsCount() * 3) / 4)) 
                ok = true;
            if (ok) {
                UnitextContainer cnt = new UnitextContainer();
                cnt.setInline(false);
                UnitextTable tab = null;
                for (i = 0; i < getRowsCount(); i++) {
                    if ((m_Cells.get(i) != null && m_Cells.get(i).size() > 0 && m_Cells.get(i).get(0).getColBegin() == 0) && m_Cells.get(i).get(0).getColEnd() == (getColsCount() - 1)) {
                        tab = null;
                        cnt.children.add(m_Cells.get(i).get(0).content);
                        cnt.children.add(UnitextNewline._new635(cnt));
                    }
                    else {
                        if (tab == null) {
                            tab = (UnitextTable)com.pullenti.unisharp.Utils.cast(this.clone(), UnitextTable.class);
                            tab.m_Cells.clear();
                            cnt.children.add(tab);
                            cnt.children.add(UnitextNewline._new635(cnt));
                        }
                        int r = tab.getRowsCount();
                        for (int j = 0; j < getColsCount(); j++) {
                            if (m_Cells.get(i).get(j) != null) {
                                tab.addCell(r, r, m_Cells.get(i).get(j).getColBegin(), m_Cells.get(i).get(j).getColEnd(), m_Cells.get(i).get(j).content, false);
                                j = m_Cells.get(i).get(j).getColEnd();
                            }
                        }
                    }
                }
                cnt.children.add(0, UnitextNewline._new635(cnt));
                return cnt.optimize(false, pars);
            }
        }
        for (int i = 1; i < (m_ColsCount - 1); i++) {
            if ((m_ColWidth != null && (i < m_ColWidth.size()) && m_ColWidth.get(i) != null) && (m_ColWidth.get(i).length() < 3) && m_ColWidth.get(i).endsWith("%")) {
                int first = 0;
                int last = 0;
                int nul = 0;
                int r;
                for (r = 0; r < getRowsCount(); r++) {
                    UnitextTablecell cel = this.getCell(r, i);
                    if (cel == null || cel.content == null) 
                        nul++;
                    else if (cel.getColBegin() == cel.getColEnd()) 
                        break;
                    else if (cel.getColBegin() == i) 
                        first++;
                    else if (cel.getColEnd() == i) 
                        last++;
                }
                if (r < getRowsCount()) 
                    continue;
                if (first == 0 || last == 0) 
                    continue;
                for (r = 0; r < getRowsCount(); r++) {
                    java.util.ArrayList<UnitextTablecell> row = m_Cells.get(r);
                    if (row == null) 
                        continue;
                    for (int c = 0; c < row.size(); c++) {
                        UnitextTablecell cel = row.get(c);
                        if (cel.getRowBegin() != r || cel.getColBegin() != c) 
                            continue;
                        if (cel.getColBegin() > i && c > 0 && cel == row.get(c - 1)) 
                            continue;
                        if (cel.getColBegin() > i) 
                            cel.setColBegin(cel.getColBegin() - 1);
                        if (cel.getColEnd() >= i) 
                            cel.setColEnd(cel.getColEnd() - 1);
                    }
                    if (i < row.size()) 
                        row.remove(i);
                }
                if (m_ColWidth != null && (i < m_ColWidth.size())) 
                    m_ColWidth.remove(i);
                m_ColsCount--;
                i--;
            }
        }
        if (m_Cells.size() > 1 && m_Cells.get(m_Cells.size() - 1).size() > 1) {
            UnitextTablecell cel0 = m_Cells.get(m_Cells.size() - 1).get(0);
            UnitextTablecell cel1 = m_Cells.get(m_Cells.size() - 1).get(m_Cells.get(m_Cells.size() - 1).size() - 1);
            if (cel0 == cel1 && (cel0.content instanceof UnitextTable)) {
                m_Cells.remove(m_Cells.size() - 1);
                UnitextContainer cnt = new UnitextContainer();
                cnt.children.add(this);
                cnt.children.add(new UnitextNewline());
                cnt.children.add(cel0.content);
                return cnt.optimize(isContent, pars);
            }
        }
        return this;
    }

    /**
     * Добавить ячейку
     * @param rowBegin начальная строка
     * @param rowEnd конечная строка
     * @param colBegin начальный столбец
     * @param colEnd конечный столбец
     * @param content возможное содержимое
     * @param overwrite полностью перезаписать то, что было на том месте (если было)
     * @return если null, то значит область пересекается с существующей ячейкой
     */
    public UnitextTablecell addCell(int rowBegin, int rowEnd, int colBegin, int colEnd, UnitextItem content, boolean overwrite) {
        if ((rowBegin < 0) || rowBegin > rowEnd) 
            return null;
        if ((colBegin < 0) || colBegin > colEnd) 
            return null;
        if ((colEnd + 1) > m_ColsCount) 
            m_ColsCount = colEnd + 1;
        while (m_Cells.size() <= rowEnd) {
            m_Cells.add(new java.util.ArrayList<UnitextTablecell>());
        }
        if (!overwrite) {
            for (int r = rowEnd; r >= rowBegin; r--) {
                while (m_Cells.get(r).size() <= colEnd) {
                    m_Cells.get(r).add(null);
                }
                for (int c = colBegin; c <= colEnd; c++) {
                    if (m_Cells.get(r).get(c) != null) {
                        if (r > rowBegin) {
                            rowEnd = r - 1;
                            break;
                        }
                        if (c > colBegin) {
                            colEnd = c - 1;
                            break;
                        }
                        return null;
                    }
                }
            }
        }
        UnitextTablecell cel = UnitextTablecell._new642(content, colBegin, colEnd, rowBegin, rowEnd);
        for (int r = rowBegin; r <= rowEnd; r++) {
            for (int c = colBegin; c <= colEnd; c++) {
                while (m_Cells.get(r).size() <= colEnd) {
                    m_Cells.get(r).add(null);
                }
                com.pullenti.unisharp.Utils.putArrayValue(m_Cells.get(r), c, cel);
            }
        }
        return cel;
    }

    private java.util.ArrayList<java.util.ArrayList<UnitextTablecell>> m_Cells = new java.util.ArrayList<java.util.ArrayList<UnitextTablecell>>();

    private java.util.ArrayList<String> m_ColWidth = new java.util.ArrayList<String>();

    /**
     * Получить ячейку таблицы, накрывающую указанную клетку
     * @param row строка клетки
     * @param col столбец клетки
     * @return ячейка (null - отсутствует)
     * 
     */
    public UnitextTablecell getCell(int row, int col) {
        if ((row < 0) || row >= m_Cells.size()) 
            return null;
        if ((col < 0) || col >= m_Cells.get(row).size()) 
            return null;
        return m_Cells.get(row).get(col);
    }

    /**
     * Получить текст для ячейки, накрывающую указанную клетку
     * @param row строка клетки
     * @param col столбец клетки
     * @return плоский текст, полученный функцией GetPlaintextString для содержимого ячейки или null при пустой ячейке
     */
    public String getCellPlaintextString(int row, int col) {
        UnitextTablecell cel = this.getCell(row, col);
        if (cel == null || cel.content == null) 
            return null;
        return cel.content.getPlaintextString(null);
    }

    /**
     * Получить ширину столбца (если таковая была задана во входном файле)
     * @param col номер столбца
     * @return ширина (как она была задана в Html или Doc) или null
     */
    public String getColWidth(int col) {
        if (col >= 0 && (col < m_ColWidth.size())) 
            return m_ColWidth.get(col);
        else 
            return null;
    }

    public void setColWidth(int col, String val) {
        if (col < 0) 
            return;
        while (col >= m_ColWidth.size()) {
            m_ColWidth.add(null);
        }
        com.pullenti.unisharp.Utils.putArrayValue(m_ColWidth, col, val);
    }

    public int getColsCount() {
        return m_ColsCount;
    }


    private int m_ColsCount;

    public int getRowsCount() {
        return m_Cells.size();
    }


    /**
     * Ширина таблицы (если входной файл - Html или подобный). 
     * Если не задана, то при выводе в HTML считается 100%
     */
    public String width;

    /**
     * Признак того, что рамки таблицы и ячеек не прорисовывать
     */
    public boolean hideBorders = false;

    /**
     * Признак того, что при печати заголовок выводится на каждой странице 
     * (пока заголовком считаем первую строку)
     */
    public boolean tableHeaderPaginate = false;

    /**
     * Признак того, что таблица может содержать ошибки (например, для Doc неправильно объединены ячейки по вертикали).
     */
    public boolean mayHasError;

    @Override
    public UnitextItem clone() {
        UnitextTable res = new UnitextTable();
        res._cloneFrom(this);
        res.m_ColsCount = m_ColsCount;
        res.tableHeaderPaginate = tableHeaderPaginate;
        if (m_ColWidth != null) 
            res.m_ColWidth = new java.util.ArrayList<String>(m_ColWidth);
        res.width = width;
        res.hideBorders = hideBorders;
        res.mayHasError = mayHasError;
        for (java.util.ArrayList<UnitextTablecell> r : m_Cells) {
            java.util.ArrayList<UnitextTablecell> rr = new java.util.ArrayList<UnitextTablecell>();
            res.m_Cells.add(rr);
            for (int i = 0; i < r.size(); i++) {
                if (r.get(i) == null) 
                    rr.add(null);
                else {
                    UnitextTablecell cc = (UnitextTablecell)com.pullenti.unisharp.Utils.cast(r.get(i).clone(), UnitextTablecell.class);
                    cc.tag = r.get(i);
                    cc.parent = this;
                    rr.add(cc);
                }
            }
        }
        return res;
    }

    @Override
    public boolean getStartsOnNewline() {
        return true;
    }


    /**
     * Добавить строки второй таблицы (количество колонок должно быть одинаковым, иначе не добавит)
     * @param tab таблица с добавляемыми строками
     * @param dontClone при true строки будут не клонироваться, а вставляться напрямую
     * @param checkWidth при true будет проверяться ширина колонок, при этом возможно, что в добавляемой таблице одной колонки не будет
     * @return удалось ли добавить
     */
    public boolean appendTable(UnitextTable tab, boolean dontClone, boolean checkWidth) {
        if (tab == null) 
            return false;
        if (tab.getColsCount() > getColsCount()) 
            return false;
        if ((tab.getColsCount() + 1) < getColsCount()) 
            return false;
        if (tab.getColsCount() != getColsCount() && !checkWidth) 
            return false;
        int mergeCol = -1;
        if (checkWidth) {
            int k0 = 0;
            for (int k = 0; k < tab.getColsCount(); k++,k0++) {
                String w1 = this.getColWidth(k0);
                String w2 = tab.getColWidth(k);
                if (com.pullenti.unisharp.Utils.stringsEq(w1, w2)) 
                    continue;
                if (w1.endsWith("%")) 
                    w1 = w1.substring(0, 0 + w1.length() - 1);
                if (w2.endsWith("%")) 
                    w2 = w2.substring(0, 0 + w2.length() - 1);
                int n1;
                int n2;
                com.pullenti.unisharp.Outargwrapper<Integer> wrapn1645 = new com.pullenti.unisharp.Outargwrapper<Integer>();
                boolean inoutres646 = com.pullenti.unisharp.Utils.parseInteger(w1, 0, null, wrapn1645);
                com.pullenti.unisharp.Outargwrapper<Integer> wrapn2647 = new com.pullenti.unisharp.Outargwrapper<Integer>();
                boolean inoutres648 = com.pullenti.unisharp.Utils.parseInteger(w2, 0, null, wrapn2647);
                n1 = (wrapn1645.value != null ? wrapn1645.value : 0);
                n2 = (wrapn2647.value != null ? wrapn2647.value : 0);
                if (!inoutres646 || !inoutres648) 
                    return false;
                int d = n1 - n2;
                if (d < 0) 
                    d = -d;
                if (d < 2) 
                    continue;
                if (((k0 + 1) < getColsCount()) && (mergeCol < 0)) {
                    String w3 = tab.getColWidth(k0 + 1);
                    if (w3 != null && w3.endsWith("%")) 
                        w3 = w3.substring(0, 0 + w3.length() - 1);
                    int n3;
                    com.pullenti.unisharp.Outargwrapper<Integer> wrapn3643 = new com.pullenti.unisharp.Outargwrapper<Integer>();
                    boolean inoutres644 = com.pullenti.unisharp.Utils.parseInteger((w3 != null ? w3 : ""), 0, null, wrapn3643);
                    n3 = (wrapn3643.value != null ? wrapn3643.value : 0);
                    if (inoutres644) {
                        d = n2 - n3;
                        if (d < 0) 
                            d = -d;
                        if (d < 2) {
                            mergeCol = k0;
                            k0++;
                            continue;
                        }
                    }
                }
                return false;
            }
        }
        int rcou0 = m_Cells.size();
        for (java.util.ArrayList<UnitextTablecell> r : tab.m_Cells) {
            java.util.ArrayList<UnitextTablecell> rr = new java.util.ArrayList<UnitextTablecell>();
            m_Cells.add(rr);
            for (int i = 0; i < r.size(); i++) {
                if (r.get(i) == null) 
                    rr.add(null);
                else if (dontClone) {
                    rr.add(r.get(i));
                    r.get(i).setRowBegin(r.get(i).getRowBegin() + rcou0);
                    r.get(i).setRowEnd(r.get(i).getRowEnd() + rcou0);
                }
                else {
                    UnitextTablecell cc = (UnitextTablecell)com.pullenti.unisharp.Utils.cast(r.get(i).clone(), UnitextTablecell.class);
                    cc.tag = r.get(i);
                    cc.parent = this;
                    rr.add(cc);
                    cc.setRowBegin(cc.getRowBegin() + rcou0);
                    cc.setRowEnd(cc.getRowEnd() + rcou0);
                }
                if (i == mergeCol) 
                    rr.add(null);
            }
        }
        if (tab.endChar > endChar) 
            endChar = tab.endChar;
        return true;
    }

    public void removeRows(int ind, int cou) {
        for (int r = (ind + cou) - 1; r >= ind; r--) {
            this.removeRow(r);
        }
    }

    public void removeLastColumn() {
        m_ColsCount--;
        if (m_ColWidth != null && m_ColWidth.size() > m_ColsCount) 
            for(int jjj = m_ColsCount + m_ColWidth.size() - m_ColsCount - 1, mmm = m_ColsCount; jjj >= mmm; jjj--) m_ColWidth.remove(jjj);
        for (java.util.ArrayList<UnitextTablecell> r : m_Cells) {
            if (r.size() > m_ColsCount) 
                for(int jjj = m_ColsCount + r.size() - m_ColsCount - 1, mmm = m_ColsCount; jjj >= mmm; jjj--) r.remove(jjj);
        }
    }

    @Override
    public boolean isInline() {
        return false;
    }


    @Override
    public String getInnerTag() {
        return "tbl";
    }


    @Override
    public UnitextItem findById(String _id) {
        if (com.pullenti.unisharp.Utils.stringsEq(id, _id)) 
            return this;
        for (int r = 0; r < m_Cells.size(); r++) {
            for (int c = 0; c < m_Cells.get(r).size(); c++) {
                if (m_Cells.get(r).get(c) != null) {
                    UnitextItem res = m_Cells.get(r).get(c).findById(_id);
                    if (res != null) 
                        return res;
                }
            }
        }
        return null;
    }

    private UnitextTablecell[] m_Map;

    public UnitextTablecell _findCellByPos(int plainPos) {
        if (m_Map == null && (beginChar < endChar)) {
            m_Map = new UnitextTablecell[(endChar + 1) - beginChar];
            for (int r = 0; r < m_Cells.size(); r++) {
                for (int c = 0; c < m_Cells.get(r).size(); c++) {
                    if (m_Cells.get(r).get(c) != null) {
                        UnitextTablecell cel = m_Cells.get(r).get(c);
                        for (int i = cel.beginChar; i <= cel.endChar; i++) {
                            if (i >= beginChar && i <= endChar) 
                                m_Map[i - beginChar] = cel;
                        }
                    }
                }
            }
        }
        if ((m_Map != null && plainPos >= beginChar && plainPos <= endChar) && ((plainPos - beginChar) < m_Map.length)) 
            return m_Map[plainPos - beginChar];
        for (int r = 0; r < m_Cells.size(); r++) {
            for (int c = 0; c < m_Cells.get(r).size(); c++) {
                if (m_Cells.get(r).get(c) != null) {
                    UnitextTablecell cel = m_Cells.get(r).get(c);
                    if (cel.beginChar <= plainPos && plainPos <= cel.endChar) 
                        return cel;
                }
            }
        }
        return null;
    }

    public boolean tryAppend(UnitextTable tab) {
        if (tab.getColsCount() != m_ColsCount) 
            return false;
        if (com.pullenti.unisharp.Utils.stringsNe(pageSectionId, tab.pageSectionId)) 
            return false;
        if (tab.getRowsCount() < 1) 
            return false;
        int k;
        for (k = 0; k < tab.getColsCount(); k++) {
            String w1 = this.getColWidth(k);
            String w2 = tab.getColWidth(k);
            if (w1 == null && w2 == null) 
                continue;
            if (w1 == null || w2 == null) 
                return false;
            if (com.pullenti.unisharp.Utils.stringsEq(w1, w2)) 
                continue;
            com.pullenti.util.SizeunitConverter su1 = new com.pullenti.util.SizeunitConverter(w1);
            com.pullenti.util.SizeunitConverter su2 = new com.pullenti.util.SizeunitConverter(w2);
            if (com.pullenti.unisharp.Utils.stringsNe(su1.unit, su2.unit)) 
                return false;
            double d = Math.abs(su1.val - su2.val);
            if (d > 1) 
                return false;
        }
        for (k = 0; k < 2; k++) {
            int r = (k == 0 ? 0 : m_Cells.size() - 1);
            int c;
            for (c = 0; c < m_Cells.get(r).size(); c++) {
                if (m_Cells.get(r).get(c) == null) 
                    break;
                UnitextTablecell cel = tab.getCell(0, c);
                if (cel == null) 
                    break;
                if (cel.getColBegin() != m_Cells.get(r).get(c).getColBegin() || cel.getColEnd() != m_Cells.get(r).get(c).getColEnd()) 
                    break;
            }
            if (c >= m_Cells.get(r).size()) 
                break;
        }
        if (k >= 2) 
            return false;
        int delt = m_Cells.size();
        for (int r = tab.getRowsCount() - 1; r >= 0; r--) {
            for (int c = 0; c < tab.getColsCount(); c++) {
                UnitextTablecell cel = tab.getCell(r, c);
                if (cel == null) 
                    continue;
                if (cel.getColBegin() == c && cel.getRowBegin() == r) {
                    cel.setRowBegin(cel.getRowBegin() + delt);
                    cel.setRowEnd(cel.getRowEnd() + delt);
                }
            }
        }
        com.pullenti.unisharp.Utils.addToArrayList(m_Cells, tab.m_Cells);
        tab.m_Cells.clear();
        return true;
    }

    @Override
    public String toString() {
        return ("Table [" + this.getRowsCount() + "x" + this.getColsCount() + "]" + (mayHasError ? " may be error" : "") + (ignorable ? " ignorable" : ""));
    }

    @Override
    public void getPlaintext(StringBuilder res, GetPlaintextParam pars) {
        if (pars != null && pars.setPositions) 
            beginChar = res.length();
        boolean nullPars = false;
        if (pars == null) {
            nullPars = true;
            pars = UnitextItem.m_DefParams;
        }
        int pos0 = res.length();
        if (pars.tableStart != null) 
            res.append(pars.tableStart);
        for (int r = 0; r < m_Cells.size(); r++) {
            for (int c = 0; c < m_Cells.get(r).size(); c++) {
                UnitextTablecell cel = m_Cells.get(r).get(c);
                if (cel == null) 
                    continue;
                if (r == cel.getRowBegin() && c == cel.getColBegin()) 
                    cel.getPlaintext(res, pars);
            }
            if (pars == null) 
                res.append("\r\n").append(((char)7));
            else {
                res.append((pars.newLine != null ? pars.newLine : ""));
                res.append((pars.tableRowEnd != null ? pars.tableRowEnd : ""));
            }
            if (pars != null && pars.maxTextLength > 0 && res.length() > pars.maxTextLength) 
                break;
        }
        if (pars.tableEnd != null) 
            res.append(pars.tableEnd);
        if (pars != null && pars.setPositions) 
            endChar = res.length() - 1;
        if (ignorable && ((nullPars || !pars.keepIgnored))) {
            for (int i = pos0; i < res.length(); i++) {
                res.setCharAt(i, ' ');
            }
            if (pars.newLine != null) {
                for (int j = 0; j < pars.newLine.length(); j++) {
                    res.setCharAt((res.length() - pars.newLine.length()) + j, pars.newLine.charAt(j));
                }
            }
        }
    }

    @Override
    public void getHtml(StringBuilder res, GetHtmlParam par) {
        if (!par.callBefore(this, res)) 
            return;
        if (ignorable) 
            return;
        res.append("\r\n<table border=\"").append((mayHasError ? 3 : (hideBorders ? 0 : 1))).append("\" width=\"").append(((width != null ? width : "100%"))).append("\"").append((mayHasError ? " style=\"border-color:red\"" : ""));
        if (id != null) {
            res.append(" id=\"").append(id).append("\"");
            if (par != null && par.styles.containsKey(id)) 
                res.append(" style=\"").append(par.styles.get(id)).append("\"");
            UnitextStyledFragment fr = this.getStyledFragment(-1);
            if (fr != null && fr.typ != UnitextStyledFragmentType.TABLE) 
                fr = fr.parent;
            if ((fr != null && fr.typ == UnitextStyledFragmentType.TABLE && fr.styleId > 0) && fr.getStyle() != null) {
                res.append(" style=\"");
                fr.getStyle().getHtml(res);
                res.append("\"");
            }
        }
        res.append(">");
        if (m_ColWidth.size() > 0) {
            res.append("<colgroup>");
            for (int i = 0; i < getColsCount(); i++) {
                res.append("<col");
                if ((i < m_ColWidth.size()) && m_ColWidth.get(i) != null) 
                    res.append(" width=\"").append(m_ColWidth.get(i)).append("\"");
                res.append("/>");
            }
            res.append("</colgroup>");
        }
        for (int r = 0; r < m_Cells.size(); r++) {
            res.append("\r\n <tr>");
            for (int c = 0; c < m_Cells.get(r).size(); c++) {
                UnitextTablecell cel = m_Cells.get(r).get(c);
                if (cel == null) 
                    continue;
                if (r == cel.getRowBegin() && c == cel.getColBegin()) {
                    res.append("\r\n   ");
                    cel.getHtml(res, par);
                }
            }
            res.append("\r\n </tr>");
            boolean stop = false;
            if (par != null && res.length() > par.maxHtmlSize) 
                stop = true;
            if (par != null && par.maxTableRowCount > 0 && (r + 1) >= par.maxTableRowCount) 
                stop = true;
            if (stop) {
                res.append("<tr><td colspan=\"").append(this.getColsCount()).append("\" style=\"background:lightpink\">Остальные ").append((m_Cells.size() - r)).append(" строк не выведены из-за ограничений html</td></tr>");
                break;
            }
        }
        res.append("\r\n</table>\r\n");
        if (par != null) 
            par._outFootnotes(res);
        par.callAfter(this, res);
    }

    @Override
    public void getXml(com.pullenti.unisharp.XmlWriterWrapper xml) throws javax.xml.stream.XMLStreamException {
        xml.wr.writeStartElement("table");
        this._writeXmlAttrs(xml);
        xml.wr.writeAttribute("rows", ((Integer)this.getRowsCount()).toString());
        xml.wr.writeAttribute("columns", ((Integer)this.getColsCount()).toString());
        if (width != null) 
            xml.wr.writeAttribute("width", width);
        if (hideBorders) 
            xml.wr.writeAttribute("border", "hide");
        if (tableHeaderPaginate) 
            xml.wr.writeAttribute("headerpaginate", "true");
        for (int i = 0; i < m_ColWidth.size(); i++) {
            if (m_ColWidth.get(i) != null) {
                xml.wr.writeStartElement("col");
                xml.wr.writeAttribute("num", ((Integer)i).toString());
                xml.wr.writeAttribute("width", m_ColWidth.get(i));
                xml.wr.writeEndElement();
            }
        }
        for (int r = 0; r < m_Cells.size(); r++) {
            xml.wr.writeStartElement("row");
            for (int c = 0; c < m_Cells.get(r).size(); c++) {
                UnitextTablecell cel = m_Cells.get(r).get(c);
                if (cel == null) 
                    continue;
                if (r == cel.getRowBegin() && c == cel.getColBegin()) 
                    cel.getXml(xml);
            }
            xml.wr.writeEndElement();
        }
        xml.wr.writeEndElement();
    }

    @Override
    public void fromXml(org.w3c.dom.Node xml) throws NumberFormatException {
        super.fromXml(xml);
        int rows = 0;
        int cols = 0;
        if (xml.getAttributes() != null) {
            for (org.w3c.dom.Node a : (new com.pullenti.unisharp.XmlAttrListWrapper(xml.getAttributes())).arr) {
                if (com.pullenti.unisharp.Utils.stringsEq(com.pullenti.unisharp.Utils.getXmlLocalName(a), "rows")) 
                    rows = com.pullenti.unisharp.Utils.parseInteger(a.getNodeValue(), 0, null);
                else if (com.pullenti.unisharp.Utils.stringsEq(com.pullenti.unisharp.Utils.getXmlLocalName(a), "columns")) 
                    m_ColsCount = (cols = com.pullenti.unisharp.Utils.parseInteger(a.getNodeValue(), 0, null));
                else if (com.pullenti.unisharp.Utils.stringsEq(com.pullenti.unisharp.Utils.getXmlLocalName(a), "width")) 
                    width = a.getNodeValue();
                else if (com.pullenti.unisharp.Utils.stringsEq(com.pullenti.unisharp.Utils.getXmlLocalName(a), "border")) {
                    if (com.pullenti.unisharp.Utils.stringsEq(a.getNodeValue(), "hide")) 
                        hideBorders = true;
                }
                else if (com.pullenti.unisharp.Utils.stringsEq(com.pullenti.unisharp.Utils.getXmlLocalName(a), "headerpaginate")) 
                    tableHeaderPaginate = com.pullenti.unisharp.Utils.stringsEq(a.getNodeValue(), "true");
            }
        }
        for (int r = 0; r < rows; r++) {
            java.util.ArrayList<UnitextTablecell> row = new java.util.ArrayList<UnitextTablecell>();
            for (int c = 0; c < cols; c++) {
                row.add(null);
            }
            m_Cells.add(row);
        }
        for (org.w3c.dom.Node x : (new com.pullenti.unisharp.XmlNodeListWrapper(xml.getChildNodes())).arr) {
            if (com.pullenti.unisharp.Utils.stringsEq(com.pullenti.unisharp.Utils.getXmlLocalName(x), "row")) {
                for (org.w3c.dom.Node xx : (new com.pullenti.unisharp.XmlNodeListWrapper(x.getChildNodes())).arr) {
                    UnitextTablecell cel = (UnitextTablecell)com.pullenti.unisharp.Utils.cast(com.pullenti.unitext.internal.uni.UnitextHelper.createItem(xx, this), UnitextTablecell.class);
                    if (cel == null) 
                        continue;
                    if (cel.getColEnd() >= cols || cel.getRowEnd() >= rows) 
                        continue;
                    for (int r = cel.getRowBegin(); r <= cel.getRowEnd(); r++) {
                        for (int c = cel.getColBegin(); c <= cel.getColEnd(); c++) {
                            com.pullenti.unisharp.Utils.putArrayValue(m_Cells.get(r), c, cel);
                        }
                    }
                }
            }
            else if (com.pullenti.unisharp.Utils.stringsEq(com.pullenti.unisharp.Utils.getXmlLocalName(x), "col")) {
                int num = 0;
                String val = null;
                if (x.getAttributes() != null) {
                    for (org.w3c.dom.Node a : (new com.pullenti.unisharp.XmlAttrListWrapper(x.getAttributes())).arr) {
                        if (com.pullenti.unisharp.Utils.stringsEq(com.pullenti.unisharp.Utils.getXmlLocalName(a), "width")) 
                            val = a.getNodeValue();
                        else if (com.pullenti.unisharp.Utils.stringsEq(com.pullenti.unisharp.Utils.getXmlLocalName(a), "num")) {
                            com.pullenti.unisharp.Outargwrapper<Integer> wrapnum649 = new com.pullenti.unisharp.Outargwrapper<Integer>();
                            com.pullenti.unisharp.Utils.parseInteger((String)com.pullenti.unisharp.Utils.notnull(a.getNodeValue(), ""), 0, null, wrapnum649);
                            num = (wrapnum649.value != null ? wrapnum649.value : 0);
                        }
                    }
                }
                if (val != null) 
                    this.setColWidth(num, val);
            }
        }
    }

    @Override
    public void getAllItems(java.util.ArrayList<UnitextItem> res, int lev) {
        if (res != null) 
            res.add(this);
        for (int r = 0; r < m_Cells.size(); r++) {
            for (int c = 0; c < m_Cells.get(r).size(); c++) {
                UnitextTablecell cel = m_Cells.get(r).get(c);
                if (cel == null) 
                    continue;
                if (r == cel.getRowBegin() && c == cel.getColBegin()) {
                    cel.parent = this;
                    cel.getAllItems(res, lev + 1);
                }
            }
        }
    }

    @Override
    public void addPlainTextPos(int d) {
        super.addPlainTextPos(d);
        for (int r = 0; r < m_Cells.size(); r++) {
            for (int c = 0; c < m_Cells.get(r).size(); c++) {
                UnitextTablecell cel = m_Cells.get(r).get(c);
                if (cel == null) 
                    continue;
                if (r == cel.getRowBegin() && c == cel.getColBegin()) 
                    cel.addPlainTextPos(d);
            }
        }
    }

    @Override
    public void correct(com.pullenti.unitext.internal.uni.LocCorrTyp typ, Object data) {
        for (int r = 0; r < m_Cells.size(); r++) {
            for (int c = 0; c < m_Cells.get(r).size(); c++) {
                UnitextTablecell cel = m_Cells.get(r).get(c);
                if (cel == null) 
                    continue;
                if (r == cel.getRowBegin() && c == cel.getColBegin()) 
                    cel.correct(typ, data);
            }
        }
    }

    @Override
    public void setDefaultTextPos(com.pullenti.unisharp.Outargwrapper<Integer> cp, StringBuilder res) {
        beginChar = cp.value;
        for (int r = 0; r < m_Cells.size(); r++) {
            for (int c = 0; c < m_Cells.get(r).size(); c++) {
                UnitextTablecell cel = m_Cells.get(r).get(c);
                if (cel == null) 
                    continue;
                if (r == cel.getRowBegin() && c == cel.getColBegin()) {
                    cel.setDefaultTextPos(cp, res);
                    cel.parent = this;
                }
            }
        }
        endChar = cp.value - 1;
    }

    /**
     * Удалить всю строку
     * @param r номер строки
     * @return true, если удалилась
     */
    public boolean removeRow(int r) {
        if ((r < 0) || r >= m_Cells.size()) 
            return false;
        for (int rr = 0; rr < getRowsCount(); rr++) {
            for (int cc = 0; cc < getColsCount(); cc++) {
                UnitextTablecell cel = this.getCell(rr, cc);
                if (cel == null) 
                    break;
                if (cel.getRowBegin() != rr || cel.getColBegin() != cc) 
                    continue;
                if (cel.getRowBegin() >= r) 
                    cel.setRowBegin(cel.getRowBegin() - 1);
                if (cel.getRowEnd() >= r) 
                    cel.setRowEnd(cel.getRowEnd() - 1);
                cc = cel.getColEnd();
            }
        }
        m_Cells.remove(r);
        return true;
    }
    public UnitextTable() {
        super();
    }
}
