/*
 * 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;

/**
 * Unitext - документ
 * 
 */
public class UnitextDocument extends UnitextItem {

    /**
     * Содержимое (тело) структурно-текстового представления (СТП)
     * 
     */
    public UnitextItem content;

    /**
     * Внутренние документы (например, для архива его разархивированные файлы или 
     * вложения для писем)
     */
    public java.util.ArrayList<UnitextDocument> innerDocuments = new java.util.ArrayList<UnitextDocument>();

    /**
     * Последовательность страниц UnilayPage с расположенными на них прямоугольниками с текстами и картинками. 
     * Тексто-графическое представление (ТГП) - для форматов PDF, DjVu
     * 
     */
    public java.util.ArrayList<UnilayPage> pages = new java.util.ArrayList<UnilayPage>();

    /**
     * Стили текста и абзацев
     */
    public java.util.ArrayList<UnitextStyle> styles = new java.util.ArrayList<UnitextStyle>();

    /**
     * Информация о страницах и колонтитулах
     */
    public java.util.ArrayList<UnitextPagesection> sections = new java.util.ArrayList<UnitextPagesection>();

    /**
     * Формат исходного документа
     * 
     */
    public FileFormat sourceFormat = FileFormat.UNKNOWN;

    /**
     * Имя исходного файла (если есть)
     */
    public String sourceFileName;

    /**
     * Страницы исходного файла (это когда файл PDF разбивается на несколько документов)
     */
    public String sourceFilePages;

    /**
     * Сообщение об ошибке, формируемое при обработке исходного файла (например, что файл зашифрован)
     */
    public String errorMessage;

    /**
     * Некоторые дополнительные атрибуты (зависят от формата)
     */
    public java.util.HashMap<String, String> attrs = new java.util.HashMap<String, String>();

    /**
     * Если документ получен функцией CreateFromText, то это входной текст, 
     * причём никак не корректированный. Функция GetPlaintext возвращает его независимо 
     * от настроек параметров генерации.
     */
    public String sourcePlainText;

    /**
     * Это дополнительные определения стилей для вывода полноценного документа в Html (содержимое секции styles)
     */
    public String htmlStyles;

    @Override
    public String toString() {
        String res = (sourceFormat.toString() + (sourceFileName == null ? "" : " :") + ((sourceFileName != null ? sourceFileName : "")));
        if (sourceFilePages != null) 
            res = (res + " (стр." + sourceFilePages + ")");
        return res;
    }

    @Override
    public UnitextItem clone() {
        UnitextDocument res = new UnitextDocument();
        res._cloneFrom(this);
        for (UnitextStyle s : styles) {
            res.styles.add(s.clone(false));
        }
        if (content != null) {
            res.content = content.clone();
            if (content.m_StyledFrag != null) 
                res.content.m_StyledFrag = content.m_StyledFrag.clone();
        }
        for (UnitextDocument d : innerDocuments) {
            res.innerDocuments.add((UnitextDocument)com.pullenti.unisharp.Utils.cast(d.clone(), UnitextDocument.class));
        }
        for (UnitextPagesection s : sections) {
            res.sections.add((UnitextPagesection)com.pullenti.unisharp.Utils.cast(s.clone(), UnitextPagesection.class));
        }
        res.pages = new java.util.ArrayList<UnilayPage>(pages);
        res.sourceFormat = sourceFormat;
        res.sourceFileName = sourceFileName;
        res.sourceFilePages = sourceFilePages;
        res.sourceInfo = sourceInfo;
        res.errorMessage = errorMessage;
        res.sourcePlainText = sourcePlainText;
        res.defaultGetHtmlParam = defaultGetHtmlParam;
        res.htmlStyles = htmlStyles;
        for (java.util.Map.Entry<String, String> a : attrs.entrySet()) {
            res.attrs.put(a.getKey(), a.getValue());
        }
        this.refreshParents();
        return res;
    }

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


    /**
     * Сгенерировать плоский текст
     * @param res куда записать
     * @param pars параметры генерации
     * 
     */
    @Override
    public void getPlaintext(StringBuilder res, GetPlaintextParam pars) {
        if (sourcePlainText != null) {
            res.append(sourcePlainText);
            return;
        }
        if (pars == null) 
            pars = new GetPlaintextParam();
        if (pars.setPositions) 
            beginChar = res.length();
        if (content != null) {
            com.pullenti.unitext.internal.uni.ChangeTextPosInfo ii = null;
            if (content.m_StyledFrag != null && pars.setPositions) 
                ii = new com.pullenti.unitext.internal.uni.ChangeTextPosInfo(content.m_StyledFrag, content);
            content.getPlaintext(res, pars);
            if (ii != null) 
                ii.restore(res.length());
        }
        if (innerDocuments.size() > 0 && pars.useInnerDocuments) {
            for (UnitextDocument d : innerDocuments) {
                if (res.length() > 0) {
                    if (pars.newLine != null) {
                        res.append(pars.newLine);
                        res.append(pars.newLine);
                    }
                    if (pars.pageBreak != null) 
                        res.append(pars.pageBreak);
                }
                d.getPlaintext(res, pars);
            }
        }
        if (pars.setPositions) {
            endChar = res.length() - 1;
            if (sections.size() == 1) 
                sections.get(0).endChar = endChar;
            else if (sections.size() > 1 && content != null) {
                java.util.ArrayList<UnitextItem> its = new java.util.ArrayList<UnitextItem>();
                this.getAllItems(its, 0);
                int i0 = -1;
                for (UnitextItem it : its) {
                    UnitextPagesection ps = it.getPageSection();
                    if (ps == null) 
                        continue;
                    int ii = sections.indexOf(ps);
                    if (ii < i0) 
                        continue;
                    i0 = ii;
                    if (it.beginChar > 0 && ps.beginChar == 0) 
                        ps.beginChar = it.beginChar;
                    if (it.endChar > ps.endChar) 
                        ps.endChar = it.endChar;
                }
                sections.get(0).beginChar = 0;
                sections.get(sections.size() - 1).endChar = endChar;
            }
        }
    }

    /**
     * Сгенерировать плоский текст
     * @param pars параметры генерации
     * @return результат
     * 
     */
    @Override
    public String getPlaintextString(GetPlaintextParam pars) {
        StringBuilder res = new StringBuilder();
        this.getPlaintext(res, pars);
        if (res.length() == 0) 
            return null;
        return res.toString();
    }

    // Параметры генерации Html по умолчанию
    public GetHtmlParam defaultGetHtmlParam;

    /**
     * Сгенерировать HTML
     * @param res куда записать
     * @param par параметры генерации
     * 
     */
    @Override
    public void getHtml(StringBuilder res, GetHtmlParam par) {
        if (par == null) 
            par = defaultGetHtmlParam;
        if (par == null) 
            par = new GetHtmlParam();
        if (!par.callBefore(this, res)) 
            return;
        if (par.outHtmlAndBodyTags) {
            res.append("<html><meta charset=\"utf-8\"/>");
            if (!com.pullenti.unisharp.Utils.isNullOrEmpty(par.title)) {
                res.append("\r\n<title>");
                com.pullenti.util.MiscHelper.correctHtmlValue(res, par.title, false, false, false);
                res.append("</title>");
            }
            if (!com.pullenti.unisharp.Utils.isNullOrEmpty(htmlStyles)) {
                res.append("\r\n<style>");
                res.append(htmlStyles);
                res.append("</style>");
            }
            res.append("<body>");
        }
        if (id != null) 
            res.append("<a name=\"").append(id).append("\"> </a>");
        if (errorMessage != null) {
            res.append("\r\n<div style=\"border:2pt solid red\">");
            com.pullenti.util.MiscHelper.correctHtmlValue(res, errorMessage, false, false, false);
            res.append("</div>");
        }
        if (content != null) {
            content.getHtml(res, par);
            par._outFootnotes(res);
            par._outEndnotes(res);
            if (par != null && res.length() > par.maxHtmlSize) 
                res.append("\r\n<br/><div style=\"color:red\"><b>ВНИМАНИЕ!</b> Размер Html превышает установленные ").append(par.maxHtmlSize).append(" символов, часть информации не попало в Html.</div>");
        }
        if (par == null || par.useInnerDocuments) {
            for (UnitextDocument d : innerDocuments) {
                res.append("\r\n<HR/><H2>Внутренний документ ").append(((d.sourceFileName != null ? d.sourceFileName : ""))).append("</H1>");
                d.getHtml(res, par);
            }
        }
        par.callAfter(this, res);
        if (par.outHtmlAndBodyTags) 
            res.append("\r\n</body></html>");
    }

    /**
     * Сгенерировать HTML
     * @param par параметры генерации
     * @return результат
     */
    @Override
    public String getHtmlString(GetHtmlParam par) {
        StringBuilder res = new StringBuilder();
        this.getHtml(res, par);
        return res.toString();
    }

    /**
     * Сериализовать в XML. Потом можно восстановить фукнцией FromXml().
     * @param xml куда сериализовать
     * 
     */
    @Override
    public void getXml(com.pullenti.unisharp.XmlWriterWrapper xml) throws javax.xml.stream.XMLStreamException {
        xml.wr.writeStartElement("doc");
        if (sourceFormat != FileFormat.UNKNOWN) 
            xml.wr.writeAttribute("format", sourceFormat.toString().toLowerCase());
        if (sourceFileName != null) 
            xml.wr.writeAttribute("filename", com.pullenti.util.MiscHelper.correctXmlValue((new java.io.File(sourceFileName)).getName()));
        if (sourceFilePages != null) 
            xml.wr.writeAttribute("filepages", sourceFilePages);
        if (errorMessage != null) 
            xml.wr.writeAttribute("error", com.pullenti.util.MiscHelper.correctXmlValue(errorMessage));
        for (java.util.Map.Entry<String, String> a : attrs.entrySet()) {
            xml.wr.writeStartElement("attr");
            xml.wr.writeAttribute("name", a.getKey());
            xml.wr.writeAttribute("val", (String)com.pullenti.unisharp.Utils.notnull(com.pullenti.util.MiscHelper.correctXmlValue(a.getValue()), ""));
            xml.wr.writeEndElement();
        }
        if (sourcePlainText != null) 
            xml.writeElementString("sourcetext", new String(java.util.Base64.getEncoder().encode(com.pullenti.util.MiscHelper.encodeStringUtf8(sourcePlainText, false))));
        if (htmlStyles != null) 
            xml.writeElementString("htmlstyles", htmlStyles);
        if (styles.size() > 0) {
            xml.wr.writeStartElement("styles");
            for (UnitextStyle s : styles) {
                s.getXml(xml);
            }
            xml.wr.writeEndElement();
        }
        for (UnitextPagesection s : sections) {
            s.getXml(xml);
        }
        if (pages.size() > 0) {
            xml.wr.writeStartElement("pages");
            for (UnilayPage p : pages) {
                p.getXml(xml);
            }
            xml.wr.writeEndElement();
        }
        if (content != null) {
            xml.wr.writeStartElement("content");
            content.getXml(xml);
            xml.wr.writeEndElement();
            if (content.m_StyledFrag != null) 
                content.m_StyledFrag.getXml(xml, null, false);
        }
        for (UnitextDocument d : innerDocuments) {
            d.getXml(xml);
        }
        xml.wr.writeEndElement();
    }

    /**
     * Десериализовать из XML, полученный функцией GetXml().
     * @param xml корневой узел, куда сериализовали
     * 
     */
    @Override
    public void fromXml(org.w3c.dom.Node xml) throws NumberFormatException {
        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), "format")) {
                    try {
                        sourceFormat = (FileFormat)FileFormat.of(a.getNodeValue());
                    } catch (Exception ex593) {
                    }
                }
                else if (com.pullenti.unisharp.Utils.stringsEq(com.pullenti.unisharp.Utils.getXmlLocalName(a), "filename")) 
                    sourceFileName = a.getNodeValue();
                else if (com.pullenti.unisharp.Utils.stringsEq(com.pullenti.unisharp.Utils.getXmlLocalName(a), "filepages")) 
                    sourceFilePages = a.getNodeValue();
                else if (errorMessage != null) 
                    errorMessage = a.getNodeValue();
            }
        }
        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), "content")) {
                for (org.w3c.dom.Node xx : (new com.pullenti.unisharp.XmlNodeListWrapper(x.getChildNodes())).arr) {
                    content = com.pullenti.unitext.internal.uni.UnitextHelper.createItem(xx, this);
                    content.parent = this;
                    break;
                }
            }
            else if (com.pullenti.unisharp.Utils.stringsEq(com.pullenti.unisharp.Utils.getXmlLocalName(x), "sourcetext")) {
                try {
                    sourcePlainText = com.pullenti.util.MiscHelper.decodeStringUtf8(java.util.Base64.getDecoder().decode((x.getTextContent()).replace("\r", "").replace("\n", "")), 0, -1);
                } catch (Exception ex) {
                }
            }
            else if (com.pullenti.unisharp.Utils.stringsEq(com.pullenti.unisharp.Utils.getXmlLocalName(x), "section")) {
                UnitextPagesection s = new UnitextPagesection();
                s.fromXml(x);
                sections.add(s);
            }
            else if (com.pullenti.unisharp.Utils.stringsEq(com.pullenti.unisharp.Utils.getXmlLocalName(x), "doc")) {
                UnitextDocument d = new UnitextDocument();
                d.fromXml(x);
                innerDocuments.add(d);
            }
            else if (com.pullenti.unisharp.Utils.stringsEq(com.pullenti.unisharp.Utils.getXmlLocalName(x), "attr") && x.getAttributes() != null) {
                try {
                    attrs.put(com.pullenti.unisharp.Utils.getXmlAttrByName(x.getAttributes(), "name").getNodeValue(), com.pullenti.unisharp.Utils.getXmlAttrByName(x.getAttributes(), "val").getNodeValue());
                } catch (Exception ex594) {
                }
            }
            else if (com.pullenti.unisharp.Utils.stringsEq(com.pullenti.unisharp.Utils.getXmlLocalName(x), "styles")) {
                styles.clear();
                for (org.w3c.dom.Node xx : (new com.pullenti.unisharp.XmlNodeListWrapper(x.getChildNodes())).arr) {
                    UnitextStyle sty = new UnitextStyle();
                    sty.fromXml(xx);
                    styles.add(sty);
                }
            }
            else if (com.pullenti.unisharp.Utils.stringsEq(com.pullenti.unisharp.Utils.getXmlLocalName(x), "htmlstyles")) 
                htmlStyles = x.getTextContent();
            else if (com.pullenti.unisharp.Utils.stringsEq(com.pullenti.unisharp.Utils.getXmlLocalName(x), "pages")) {
                pages.clear();
                for (org.w3c.dom.Node xx : (new com.pullenti.unisharp.XmlNodeListWrapper(x.getChildNodes())).arr) {
                    UnilayPage page = new UnilayPage();
                    page.restore(xx);
                    pages.add(page);
                }
            }
            else if (com.pullenti.unisharp.Utils.stringsEq(com.pullenti.unisharp.Utils.getXmlLocalName(x), "stylefrag") && content != null) {
                content.m_StyledFrag = new UnitextStyledFragment();
                content.m_StyledFrag.setDoc(this);
                content.m_StyledFrag.fromXml(x);
            }
        }
        this.getAllItems(null, 0);
    }

    @Override
    public UnitextItem optimize(boolean isContent, CreateDocumentParam pars) {
        if (content != null) 
            content = content.optimize(true, pars);
        for (UnitextPagesection s : sections) {
            for (UnitextPagesectionItem it : s.items) {
                if (it.content != null) 
                    it.content = it.content.optimize(true, pars);
            }
        }
        for (UnitextDocument d : innerDocuments) {
            d.optimize(false, pars);
        }
        return this;
    }

    // Обновить ссылки на родительские элементы
    public void refreshParents() {
        this.getAllItems(null, 0);
    }

    /**
     * После OCR-распознавания обновить СТП (Content) на основе нового ТГП (Pages)
     */
    public void refreshContentByPages() {
        if (pages.size() == 0) 
            return;
        com.pullenti.unitext.internal.uni.UnilayoutHelper.createContentFromPages(this, true);
        com.pullenti.unitext.internal.uni.UnitextCorrHelper.removeFalseNewLines(this, true, null);
        this.refreshParents();
    }

    public java.util.ArrayList<UnitextItem> getContentItems() {
        java.util.ArrayList<UnitextItem> res = new java.util.ArrayList<UnitextItem>();
        this.getAllItems(res, 0);
        return res;
    }


    @Override
    public void getAllItems(java.util.ArrayList<UnitextItem> res, int lev) {
        if (res != null) 
            res.add(this);
        if (content != null) {
            content.parent = this;
            content.getAllItems(res, lev + 1);
        }
        for (UnitextDocument d : innerDocuments) {
            d.parent = this;
            d.getAllItems(res, lev + 1);
        }
        java.util.ArrayList<UnitextItem> tmp = null;
        if (res != null) 
            tmp = new java.util.ArrayList<UnitextItem>();
        for (UnitextPagesection s : sections) {
            s.parent = this;
            s.getAllItems(tmp, 0);
        }
        if (lev == 0 && res != null) {
            for (UnitextItem it : res) {
                if (it.parent != null && it.pageSectionId != null) {
                    if (it.getPageSection() == it.parent.getPageSection()) 
                        it.pageSectionId = null;
                }
            }
        }
        if (tmp != null) {
            for (UnitextItem it : tmp) {
                if (it.parent != null && it.pageSectionId != null) {
                    if (it.getPageSection() == it.getPageSection().getPageSection()) 
                        it.pageSectionId = null;
                }
            }
        }
    }

    // Откорректировать документ
    public boolean correct(CorrectDocumentParam corrPars) {
        if (corrPars == null) 
            corrPars = new CorrectDocumentParam();
        boolean ret = false;
        if (corrPars.restoreTables) {
            if (com.pullenti.unitext.internal.uni.UnitextCorrHelper.restoreTables(this)) 
                ret = true;
        }
        if (corrPars.removePageBreakNumeration) {
            FileFormatClass fty = com.pullenti.util.FileFormatsHelper.getFormatClass(sourceFormat);
            if (sourceFormat == FileFormat.TXT || fty == FileFormatClass.PAGELAYOUT || fty == FileFormatClass.IMAGE) 
                com.pullenti.unitext.internal.uni.UnitextCorrHelper.removePageBreakNumeration(this);
        }
        if (corrPars.removeFalseNewLines) 
            com.pullenti.unitext.internal.uni.UnitextCorrHelper.removeFalseNewLines(this, corrPars.replaceNbspBySpace, corrPars);
        if (corrPars.restoreTextFootnotes) 
            com.pullenti.unitext.internal.uni.UnitextCorrHelper.restoreTextFootnotes(this);
        if (corrPars.optimizeStructure && corrPars.removeEmptyTables) 
            this.optimize(false, CreateDocumentParam._new362(corrPars));
        return ret;
    }

    @Override
    public UnitextStyledFragment getStyledFragment(int textPos) {
        if (content != null) {
            if (content.m_StyledFrag == null) 
                return null;
            return content.getStyledFragment(textPos);
        }
        return null;
    }

    /**
     * Встроить контейнер в дерево элементов. 
     * ВНИМАНИЕ! Встраивание возможно только после вызова GetPlaintext(), 
     * когда значения BeginChar и EndChar установлены у всех элементов, и встраивание происходит относительно этих значений. 
     * Идентификатор у встраиваемого контейнера устанавливать самим, если нужно потом производить к нему навигацию в Html.
     * @param cnt встраиваемый контейнер (любой наследный от контейнера класс) с установленными значениями BeginChar и EndChar
     * @param plaintext сгенерированный плоский текст, относительно которого идёт позиционирование
     * @param _parent возможный контейнерный блок (если известен), может быть null
     * @return получилось ли встроить
     * 
     */
    public boolean implantate(UnitextContainer cnt, String plaintext, UnitextDocblock _parent) {
        if (content == null || cnt == null) 
            return false;
        if (((cnt.beginChar < 0) || (cnt.endChar < cnt.beginChar) || cnt.endChar >= plaintext.length()) || cnt.endChar <= 0) {
            UnitextContainer ppp = (UnitextContainer)com.pullenti.unisharp.Utils.cast(content, UnitextContainer.class);
            if (ppp == null) {
                ppp = UnitextContainer._new596(content.beginChar, content.endChar, this);
                ppp.children.add(content);
                content.parent = ppp;
            }
            cnt.beginChar = (cnt.endChar = 0);
            ppp.children.add(0, cnt);
            cnt.parent = ppp;
            return true;
        }
        if (_parent != null) {
            com.pullenti.unitext.internal.uni.UnitextImplantateHelper.implantate(_parent, cnt, plaintext, null);
            return cnt.parent != null;
        }
        UnitextItem res = com.pullenti.unitext.internal.uni.UnitextImplantateHelper.implantate(content, cnt, plaintext, null);
        if (res == null) 
            return false;
        content = res;
        return cnt.parent != null;
    }

    /**
     * Встроить гиперссылку в дерево элементов. 
     * ВНИМАНИЕ! Встраивание возможно только после вызова GetPlaintext(), 
     * когда значения BeginChar и EndChar установлены у всех элементов, и встраивание происходит относительно этих значений. 
     * Идентификатор у встраиваемого контейнера устанавливать самим, если нужно потом производить к нему навигацию в Html.
     * @param hl встраиваемая гиперссылка с установленными значениями BeginChar и EndChar
     * @param plaintext сгенерированный плоский текст, относительно которого идёт позиционирование
     * @param _parent возможный контейнерный блок (если известен), может быть null
     * @return получилось ли встроить
     */
    public boolean implantateHyperlink(UnitextHyperlink hl, String plaintext, UnitextDocblock _parent) {
        if (content == null) 
            return false;
        UnitextContainer cnt = new UnitextContainer();
        cnt.beginChar = hl.beginChar;
        cnt.endChar = hl.endChar;
        if (!this.implantate(cnt, plaintext, _parent)) 
            return false;
        if (cnt.parent == null) 
            return false;
        if (!cnt.parent.replaceChild(cnt, hl)) 
            return false;
        hl.content = cnt.optimize(true, null);
        if (hl.content != null) 
            hl.content.parent = hl;
        return true;
    }

    /**
     * Встроить в дерево структурирующий блок UnitextDocblock. 
     * Его идентификатор Id нужно устанавливать самим, если нужно.
     * @param beginHead начальная позиция заголовка блока
     * @param beginBody начальная позиция тела блока
     * @param beginTail начальная позиция подписи (если = beginBody, то отсутствует)
     * @param beginAppendix начальная позиция приложения (если = end, то отсутствует)
     * @param end конечная позиция
     * @param plaintext сгенерированный плоский текст, относительно которого идёт позиционирование
     * @param _parent возможный вышележащий блок
     * @return в случае успеха вернёт указатель встроенный блок, null - если не получилось
     */
    public UnitextDocblock implantateBlock(int beginHead, int beginBody, int beginTail, int beginAppendix, int end, String plaintext, UnitextDocblock _parent) {
        UnitextDocblock res = null;
        if ((_parent != null && _parent.appendix != null && beginHead >= _parent.appendix.beginChar) && end <= _parent.appendix.endChar) {
            com.pullenti.unisharp.Outargwrapper<UnitextDocblock> wrapres597 = new com.pullenti.unisharp.Outargwrapper<UnitextDocblock>(res);
            UnitextItem cnt = com.pullenti.unitext.internal.uni.UnitextImplantateHelper.implantateBlock(_parent.appendix, beginHead, beginBody, beginTail, beginAppendix, end, plaintext, null, wrapres597);
            res = wrapres597.value;
            if (cnt != null) 
                _parent.appendix = cnt;
        }
        else if ((_parent != null && _parent.body != null && beginHead >= _parent.beginChar) && end <= _parent.endChar) {
            com.pullenti.unisharp.Outargwrapper<UnitextDocblock> wrapres598 = new com.pullenti.unisharp.Outargwrapper<UnitextDocblock>(res);
            UnitextItem cnt = com.pullenti.unitext.internal.uni.UnitextImplantateHelper.implantateBlock(_parent.body, beginHead, beginBody, beginTail, beginAppendix, end, plaintext, null, wrapres598);
            res = wrapres598.value;
            if (cnt != null) 
                _parent.body = cnt;
        }
        else {
            com.pullenti.unisharp.Outargwrapper<UnitextDocblock> wrapres599 = new com.pullenti.unisharp.Outargwrapper<UnitextDocblock>(res);
            UnitextItem cnt = com.pullenti.unitext.internal.uni.UnitextImplantateHelper.implantateBlock(content, beginHead, beginBody, beginTail, beginAppendix, end, plaintext, null, wrapres599);
            res = wrapres599.value;
            if (cnt != null) 
                content = cnt;
        }
        return res;
    }

    /**
     * Удалить элементы определённого типа
     * @param typ тип элементов
     * @param cntTyp для контейнеров можно задать дополнительный тип
     * @return количество удалённых элементов
     */
    public int removeItems(Class<?> typ, UnitextContainerType cntTyp) {
        if (content == null) 
            return 0;
        int cou = 0;
        com.pullenti.unisharp.Outargwrapper<Integer> wrapcou600 = new com.pullenti.unisharp.Outargwrapper<Integer>(cou);
        content = com.pullenti.unitext.internal.uni.UnitextImplantateHelper.clear(content, null, typ, cntTyp, null, wrapcou600);
        cou = (wrapcou600.value != null ? wrapcou600.value : 0);
        if (cou > 0) 
            this.refreshParents();
        return cou;
    }

    /**
     * Удалить элемент по его идентификатору Id. 
     * Сейчас работает только для тех элементов, которые были встроены через Implantate
     * @param _id идентификатор удаляемого элемента
     * @return удалось ли удалить
     */
    public boolean removeItemById(String _id) {
        if (content == null) 
            return false;
        int cou = 0;
        com.pullenti.unisharp.Outargwrapper<Integer> wrapcou601 = new com.pullenti.unisharp.Outargwrapper<Integer>(cou);
        content = com.pullenti.unitext.internal.uni.UnitextImplantateHelper.clear(content, _id, null, UnitextContainerType.UNDEFINED, null, wrapcou601);
        cou = (wrapcou601.value != null ? wrapcou601.value : 0);
        return cou > 0;
    }

    /**
     * Удалить все гиперссылки, сделав их обычными текстами
     * @param subString если задан, то url должен содержать эту подстроку. Подстрок м.б. несколько, разделитель - точка с запятой.
     * @return количество удалённых гиперссылок
     */
    public int removeAllHyperlinks(String subString, CreateDocumentParam pars) {
        java.util.ArrayList<UnitextItem> its = new java.util.ArrayList<UnitextItem>();
        this.getAllItems(its, 0);
        int change = 0;
        java.util.ArrayList<String> substrs = new java.util.ArrayList<String>();
        if (subString != null) 
            com.pullenti.unisharp.Utils.addToArrayList(substrs, java.util.Arrays.asList(com.pullenti.unisharp.Utils.split(subString.toUpperCase(), String.valueOf(';'), false)));
        for (UnitextItem it : its) {
            UnitextHyperlink hl = (UnitextHyperlink)com.pullenti.unisharp.Utils.cast(it, UnitextHyperlink.class);
            if (hl == null) 
                continue;
            if (substrs.size() > 0) {
                if (hl.href == null) {
                    if (!substrs.contains("")) 
                        continue;
                }
                else {
                    int k;
                    for (k = 0; k < substrs.size(); k++) {
                        if (!com.pullenti.unisharp.Utils.isNullOrEmpty(substrs.get(k)) && (hl.href.toUpperCase().indexOf(substrs.get(k)) >= 0)) 
                            break;
                    }
                    if (k >= substrs.size()) {
                        if (((hl.href.indexOf(' ') < 0) && hl.href.indexOf('.') > 0) || hl.isInternal) 
                            continue;
                    }
                }
            }
            if (hl.parent != null && hl.content != null) {
                if (hl.ignorable) 
                    hl.content.ignorable = true;
                if (hl.parent.replaceChild(hl, hl.content)) 
                    change++;
            }
        }
        if (change > 0) {
            if (pars == null) 
                pars = new CreateDocumentParam();
            this.optimize(false, pars);
        }
        return change;
    }

    /**
     * Сгенерировать внутренние идентификаторы у элементов. 
     * Если у элемента Id установлен, то он не меняется. 
     * У колонтитулов Id не устанавливается. По умолчанию, Id генерируются при создании документа.
     */
    public void generateIds() {
        java.util.HashMap<String, Integer> ids = new java.util.HashMap<String, Integer>();
        java.util.ArrayList<UnitextItem> all = new java.util.ArrayList<UnitextItem>();
        this.getAllItems(all, 0);
        for (UnitextItem it : all) {
            if (it.getInnerTag() != null && it.id != null && it.id.startsWith(it.getInnerTag())) {
                int n;
                com.pullenti.unisharp.Outargwrapper<Integer> wrapn602 = new com.pullenti.unisharp.Outargwrapper<Integer>();
                boolean inoutres603 = com.pullenti.unisharp.Utils.parseInteger(it.id.substring(it.getInnerTag().length()), 0, null, wrapn602);
                n = (wrapn602.value != null ? wrapn602.value : 0);
                if (inoutres603) {
                    if (!ids.containsKey(it.getInnerTag())) 
                        ids.put(it.getInnerTag(), n);
                    else if (ids.get(it.getInnerTag()) < n) 
                        ids.put(it.getInnerTag(), n);
                }
            }
        }
        for (UnitextItem it : all) {
            if (it.getInnerTag() != null && it != this && it.id == null) {
                int _id;
                com.pullenti.unisharp.Outargwrapper<Integer> wrapid604 = new com.pullenti.unisharp.Outargwrapper<Integer>();
                boolean inoutres605 = com.pullenti.unisharp.Utils.tryGetValue(ids, it.getInnerTag(), wrapid604);
                _id = (wrapid604.value != null ? wrapid604.value : 0);
                if (!inoutres605) 
                    ids.put(it.getInnerTag(), (_id = 1));
                else 
                    ids.put(it.getInnerTag(), ++_id);
                it.id = (it.getInnerTag() + _id);
            }
        }
    }

    /**
     * Объединить содержимое с содержимым другого документа
     * @param doc другой документ
     */
    public void mergeWith(UnitextDocument doc) {
        UnitextContainer cnt = (UnitextContainer)com.pullenti.unisharp.Utils.cast(content, UnitextContainer.class);
        UnitextContainer cnt2 = (UnitextContainer)com.pullenti.unisharp.Utils.cast(doc.content, UnitextContainer.class);
        if (cnt == null) {
            cnt = new UnitextContainer();
            if (content != null) 
                cnt.children.add(content);
            content = cnt;
        }
        cnt.children.add(new UnitextPagebreak());
        if (cnt2 != null) 
            com.pullenti.unisharp.Utils.addToArrayList(cnt.children, cnt2.children);
        else if (doc.content != null) 
            cnt.children.add(doc.content);
        com.pullenti.unisharp.Utils.addToArrayList(sections, doc.sections);
    }

    /**
     * Преобразовать в байтовый поток (со сжатием). Восстанавливать потом функцией Deserialize().
     * @return результат
     */
    public byte[] serialize() throws Exception, javax.xml.stream.XMLStreamException, java.io.IOException {
        StringBuilder tmp = new StringBuilder();
        try (com.pullenti.unisharp.XmlWriterWrapper xml = new com.pullenti.unisharp.XmlWriterWrapper(tmp, _newXmlWriterSettings_606(java.nio.charset.Charset.forName("UTF-8"), false))) {
            this.getXml(xml);
        }
        String str = tmp.toString();
        byte[] dat = com.pullenti.util.MiscHelper.encodeStringUtf8(str, false);
        return com.pullenti.util.ArchiveHelper.compressGZip(dat);
    }

    /**
     * Восстановить документ из байтового потока, полученного функцией Serialize(). 
     * Если что не так, то выдаст Exception.
     * @param dat массив байт
     */
    public void deserialize(byte[] dat) throws Exception, javax.xml.stream.XMLStreamException, java.io.IOException, org.xml.sax.SAXException, NumberFormatException {
        if (dat == null || dat.length == 0) 
            return;
        dat = com.pullenti.util.ArchiveHelper.decompressGZip(dat);
        String head = com.pullenti.unisharp.Utils.decodeCharset(java.nio.charset.Charset.forName("ASCII"), dat, 0, (dat.length < 100 ? dat.length : 100));
        int ii = head.indexOf("utf-16");
        if (ii > 0) {
            dat[ii + 4] = (byte)'8';
            dat[ii + 5] = (byte)'"';
            dat[ii + 6] = (byte)' ';
        }
        try (com.pullenti.unisharp.MemoryStream mem = new com.pullenti.unisharp.MemoryStream(dat)) {
            com.pullenti.unisharp.XmlDocumentWrapper xml = new com.pullenti.unisharp.XmlDocumentWrapper();
            xml.load(mem);
            this.fromXml(xml.doc.getDocumentElement());
            return;
        }
    }

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


    /**
     * Найти элемент по его идентификатору
     * @param _id идентификатор элемента
     * @return результат или null
     */
    @Override
    public UnitextItem findById(String _id) {
        if (com.pullenti.unisharp.Utils.stringsEq(id, _id)) 
            return this;
        UnitextItem res;
        if (content != null) {
            if ((((res = content.findById(_id)))) != null) 
                return res;
        }
        for (UnitextDocument doc : innerDocuments) {
            if ((((res = doc.findById(_id)))) != null) 
                return res;
        }
        return null;
    }

    public static UnitextDocument _new47(FileFormat _arg1) {
        UnitextDocument res = new UnitextDocument();
        res.sourceFormat = _arg1;
        return res;
    }

    public static UnitextDocument _new69(String _arg1, FileFormat _arg2) {
        UnitextDocument res = new UnitextDocument();
        res.sourceFileName = _arg1;
        res.sourceFormat = _arg2;
        return res;
    }

    public static UnitextDocument _new380(FileFormat _arg1, String _arg2) {
        UnitextDocument res = new UnitextDocument();
        res.sourceFormat = _arg1;
        res.errorMessage = _arg2;
        return res;
    }

    public static UnitextDocument _new394(FileFormat _arg1, String _arg2) {
        UnitextDocument res = new UnitextDocument();
        res.sourceFormat = _arg1;
        res.sourceFileName = _arg2;
        return res;
    }

    public static UnitextDocument _new396(String _arg1) {
        UnitextDocument res = new UnitextDocument();
        res.sourcePlainText = _arg1;
        return res;
    }

    public static UnitextDocument _new494(FileFormat _arg1, java.util.HashMap<String, String> _arg2) {
        UnitextDocument res = new UnitextDocument();
        res.sourceFormat = _arg1;
        res.attrs = _arg2;
        return res;
    }

    public com.pullenti.unisharp.XmlWriterSettings _newXmlWriterSettings_606(java.nio.charset.Charset _arg1, boolean _arg2) {
        com.pullenti.unisharp.XmlWriterSettings res = new com.pullenti.unisharp.XmlWriterSettings();
        res.setEncoding(_arg1);
        res.setIndent(_arg2);
        return res;
    }
    public UnitextDocument() {
        super();
    }
}
