/*
 * 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.internal.uni;

public class UnilayoutHelper {

    public static void correctPdfSpacings(java.util.ArrayList<com.pullenti.unitext.UnilayPage> pages) {
        int sp0 = 0;
        int sp1 = 0;
        for (com.pullenti.unitext.UnilayPage p : pages) {
            for (com.pullenti.unitext.UnilayRectangle r : p.rects) {
                if (r.text != null) {
                    for (int i = 0; i < (r.text.length() - 1); i++) {
                        char ch1 = r.text.charAt(i);
                        char ch2 = r.text.charAt(i + 1);
                        if (!com.pullenti.unisharp.Utils.isWhitespace(ch1)) {
                            if (!com.pullenti.unisharp.Utils.isWhitespace(ch2)) 
                                sp0++;
                            else if (((i + 2) < r.text.length()) && !com.pullenti.unisharp.Utils.isWhitespace(r.text.charAt(i + 2))) 
                                sp1++;
                        }
                    }
                }
            }
        }
        if (sp0 > (sp1 / 100)) 
            return;
        StringBuilder tmp = new StringBuilder();
        for (com.pullenti.unitext.UnilayPage p : pages) {
            for (com.pullenti.unitext.UnilayRectangle r : p.rects) {
                if (r.text != null) {
                    tmp.setLength(0);
                    for (int i = 0; i < r.text.length(); i++) {
                        char ch1 = r.text.charAt(i);
                        if (com.pullenti.unisharp.Utils.isWhitespace(ch1)) 
                            continue;
                        tmp.append(ch1);
                        int j;
                        int k = 0;
                        for (j = i + 1; j < r.text.length(); j++) {
                            if (!com.pullenti.unisharp.Utils.isWhitespace(r.text.charAt(j))) 
                                break;
                            else 
                                k++;
                        }
                        k /= 2;
                        for (; k > 0; k--) {
                            tmp.append(' ');
                        }
                    }
                    r.text = tmp.toString();
                }
            }
        }
    }

    public static void correctPdfEncoding(java.util.ArrayList<com.pullenti.unitext.UnilayPage> pages) {
        int tot = 0;
        int err = 0;
        int lat = 0;
        int rus = 0;
        for (com.pullenti.unitext.UnilayPage p : pages) {
            for (com.pullenti.unitext.UnilayRectangle r : p.rects) {
                if (r.text != null) {
                    for (char ch : r.text.toCharArray()) {
                        if (Character.isLetter(ch)) {
                            tot++;
                            int cod = (int)ch;
                            if (cod < 0x80) 
                                lat++;
                            else if (cod < 0x100) 
                                err++;
                            else if (cod >= 0x400 && (cod < 0x500)) 
                                rus++;
                        }
                    }
                }
            }
        }
        if (err > 10 && err > (tot / 2) && (rus < (err / 2))) {
        }
        else 
            return;
        StringBuilder tmp = new StringBuilder();
        byte[] b1 = new byte[1];
        for (com.pullenti.unitext.UnilayPage p : pages) {
            for (com.pullenti.unitext.UnilayRectangle r : p.rects) {
                if (r.text != null) {
                    tmp.setLength(0);
                    for (char ch : r.text.toCharArray()) {
                        int cod = (int)ch;
                        char resCh = ch;
                        if (cod > 0x80 && (cod < 0x100)) {
                            b1[0] = (byte)cod;
                            String s = com.pullenti.util.MiscHelper.decodeString1251(b1, 0, -1);
                            if ((s != null && s.length() == 1 && ((int)s.charAt(0)) >= 0x400) && (((int)s.charAt(0)) < 0x500)) {
                                resCh = s.charAt(0);
                                if (((resCh >= 'А' && resCh <= 'Я')) || ((resCh >= 'а' && resCh <= 'я'))) {
                                }
                                else if (resCh == 'њ') 
                                    resCh = 'Ё';
                                else if (cod == 188) 
                                    resCh = 'ё';
                                else if (cod == 190) 
                                    resCh = '«';
                                else if (cod == 191) 
                                    resCh = '»';
                                else {
                                }
                            }
                            else {
                            }
                        }
                        tmp.append(resCh);
                    }
                    r.text = tmp.toString();
                }
            }
        }
    }

    private static double _cmFromPt(int pt) {
        double v = (double)pt;
        v = (v * 2.54) / (72.0);
        return com.pullenti.unisharp.Utils.mathRound(v, 1);
    }

    public static void createContentFromPages(com.pullenti.unitext.UnitextDocument doc, boolean afterOcr) {
        if (doc.pages.size() == 0) 
            return;
        if (doc.sourceFormat == com.pullenti.unitext.FileFormat.PDF && !afterOcr) 
            correctPdfEncoding(doc.pages);
        com.pullenti.unitext.UnitextContainer cnt = new com.pullenti.unitext.UnitextContainer();
        doc.content = cnt;
        java.util.ArrayList<java.util.ArrayList<LayLine>> plines = new java.util.ArrayList<java.util.ArrayList<LayLine>>();
        for (com.pullenti.unitext.UnilayPage p : doc.pages) {
            plines.add(correctPageLines(p));
        }
        java.util.ArrayList<LayLine> headTitle = new java.util.ArrayList<LayLine>();
        com.pullenti.unitext.UnitextItem header = null;
        com.pullenti.unitext.UnitextItem footer = null;
        if (doc.pages.size() > 1) {
            while (plines.get(0).size() > 0) {
                if (headTitle.size() > 0) {
                    if (plines.get(0).get(0).getY() > (headTitle.get(0).getY() + headTitle.get(0).getHeight())) 
                        break;
                }
                int pn;
                int eq = 0;
                for (pn = 1; pn < plines.size(); pn++) {
                    if (plines.get(pn).size() > 0) {
                        if (plines.get(pn).get(0).canBeEqualsExceptPageNumber(plines.get(0).get(0))) 
                            eq++;
                        else 
                            break;
                    }
                }
                if (eq > 0 && pn >= plines.size()) {
                    headTitle.add(plines.get(0).get(0));
                    for (java.util.ArrayList<LayLine> pp : plines) {
                        if (pp.size() > 0) 
                            pp.remove(0);
                    }
                    continue;
                }
                break;
            }
            if (headTitle.size() > 0) {
                com.pullenti.unitext.UnitextContainer fcnt = new com.pullenti.unitext.UnitextContainer();
                for (LayLine ht : headTitle) {
                    for (com.pullenti.unitext.UnilayRectangle b : ht.boxes) {
                        b.ignored = true;
                        if (b.text != null) 
                            fcnt.children.add(com.pullenti.unitext.UnitextPlaintext._new57(b.text));
                        else if (b.imageContent != null) 
                            fcnt.children.add(com.pullenti.unitext.UnitextImage._new278(b.imageContent));
                    }
                }
                String ttt = fcnt.getPlaintextString(null);
                if (ttt != null && ttt.length() > 5) 
                    header = fcnt;
            }
        }
        com.pullenti.unitext.UnitextPagesection cur = new com.pullenti.unitext.UnitextPagesection();
        cur.width = _cmFromPt(doc.pages.get(0).width);
        cur.height = _cmFromPt(doc.pages.get(0).height);
        doc.sections.add(cur);
        for (int pn = 0; pn < doc.pages.size(); pn++) {
            com.pullenti.unitext.UnilayPage p = doc.pages.get(pn);
            if (pn > 0) 
                cnt.children.add(com.pullenti.unitext.UnitextPagebreak._new351(cur.id, pn));
            double pw = _cmFromPt(p.width);
            double ph = _cmFromPt(p.height);
            if (Math.abs(pw - cur.width) > 1 || Math.abs(ph - cur.height) > 1) {
                cur = new com.pullenti.unitext.UnitextPagesection();
                doc.sections.add(cur);
                cur.id = ("ps" + doc.sections.size());
                cur.width = pw;
                cur.height = ph;
            }
            java.util.ArrayList<LayLine> lines = plines.get(pn);
            if (lines == null) 
                continue;
            double charWidth = 0.0;
            int cou = 0;
            for (LayLine l : lines) {
                for (com.pullenti.unitext.UnilayRectangle r : l.boxes) {
                    if (r.text != null) {
                        cou += r.text.length();
                        charWidth += (r.right - r.left);
                    }
                }
            }
            if (cou > 0) 
                charWidth /= ((double)cou);
            for (int i = 0; i < lines.size(); i++) {
                if (i > 0) {
                    cou = 1;
                    double h1 = lines.get(i - 1).getHeight();
                    double h2 = lines.get(i).getHeight();
                    double y1 = lines.get(i - 1).getY();
                    double y2 = lines.get(i).getY();
                    if (((h1 < (h2 * ((double)0.75F)))) || ((h1 * ((double)0.75F)) >= h2)) 
                        cou = 2;
                    else if ((y1 + h1) <= y2 && h1 > 0) {
                        cou = (int)((((y2 - y1)) / h1));
                        if (cou < 1) 
                            cou = 1;
                        else if (cou > 5) 
                            cou = 5;
                    }
                    else if (y1 > y2) 
                        cou = 3;
                    cnt.children.add(com.pullenti.unitext.UnitextNewline._new352(cou, cur.id));
                }
                LayLine l = lines.get(i);
                for (com.pullenti.unitext.UnilayRectangle b : l.boxes) {
                    b.tag = null;
                }
                if (i == 13) {
                }
                for (int j = 0; j < l.boxes.size(); j++) {
                    com.pullenti.unitext.UnilayRectangle r = l.boxes.get(j);
                    r.lineNumber = j + 1;
                    if (j > 0) {
                        double d = r.left - l.boxes.get(j - 1).right;
                        if (d > (charWidth / (3.0))) {
                            int sps = (charWidth > 0 ? (int)((d / charWidth)) : 1);
                            if (sps < 1) 
                                sps = 1;
                            String str = com.pullenti.unisharp.Utils.createString(' ', sps);
                            cnt.children.add(com.pullenti.unitext.UnitextPlaintext._new353(str, cur.id));
                        }
                    }
                    if (r.text != null) {
                        com.pullenti.unitext.UnitextPlaintext txt = com.pullenti.unitext.UnitextPlaintext._new353(r.text, cur.id);
                        txt.layout = new com.pullenti.unitext.UnilayRectangle[r.text.length()];
                        for (int k = 0; k < txt.layout.length; k++) {
                            txt.layout[k] = r;
                        }
                        cnt.children.add(txt);
                        if (j > 0 && _hasLetterOrDigit(txt.text)) {
                            com.pullenti.unitext.UnilayRectangle r0 = l.boxes.get(j - 1);
                            if (r0.tag == null && (r0.right + (3.0)) >= r.left) {
                                com.pullenti.unitext.UnitextPlaintext prev = (cnt.children.size() > 1 ? (com.pullenti.unitext.UnitextPlaintext)com.pullenti.unisharp.Utils.cast(cnt.children.get(cnt.children.size() - 2), com.pullenti.unitext.UnitextPlaintext.class) : null);
                                if (prev != null && _hasLetterOrDigit(prev.text)) {
                                    if (r.bottom > ((((r0.bottom + r0.top)) / (2.0))) && r.bottom > r0.top && (r.top < r0.top)) {
                                        if ((prev.text.length() < 3) && txt.text.length() > 4) 
                                            prev.typ = com.pullenti.unitext.UnitextPlaintextType.SUB;
                                        else if (txt.text.length() < 5) {
                                            r.tag = txt;
                                            txt.typ = com.pullenti.unitext.UnitextPlaintextType.SUP;
                                        }
                                    }
                                    else if ((r.top < ((((r0.bottom + r0.top)) / (2.0)))) && (r.top < r0.bottom)) {
                                        if (r.bottom > ((r0.bottom + (((r.bottom - r0.top)) / (6.0))))) {
                                            if (prev != null && (prev.text.length() < 3) && txt.text.length() > 4) 
                                                prev.typ = com.pullenti.unitext.UnitextPlaintextType.SUP;
                                            else if (txt.text.length() < 5) {
                                                r.tag = txt;
                                                txt.typ = com.pullenti.unitext.UnitextPlaintextType.SUB;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                    else if (r.imageContent != null) {
                        com.pullenti.unitext.UnitextImage img = com.pullenti.unitext.UnitextImage._new355(r.imageContent, r, cur.id);
                        img.width = ((((Integer)((int)((r.right - r.left)))).toString()) + "pt");
                        img.height = ((((Integer)((int)((r.bottom - r.top)))).toString()) + "pt");
                        cnt.children.add(img);
                    }
                }
            }
            if (p.imageContent != null) {
                com.pullenti.unitext.UnitextImage img = com.pullenti.unitext.UnitextImage._new356(cur.id);
                img.content = p.imageContent;
                if (p.width > 0) 
                    img.width = ((((Integer)(p.width)).toString()) + "pt");
                if (p.height > 0) 
                    img.height = ((((Integer)(p.height)).toString()) + "pt");
                cnt.children.add(img);
            }
        }
    }

    private static boolean _hasLetterOrDigit(String txt) {
        if (txt != null) {
            for (char ch : txt.toCharArray()) {
                if ((Character.isLetterOrDigit(ch) || ch == '*' || ch == '<') || ch == '>') 
                    return true;
            }
        }
        return false;
    }

    private static java.util.ArrayList<LayLine> correctPageLines(com.pullenti.unitext.UnilayPage p) {
        java.util.ArrayList<LayLine> lines = new java.util.ArrayList<LayLine>();
        for (com.pullenti.unitext.UnilayRectangle r : p.rects) {
            if (lines.size() > 0 && lines.get(lines.size() - 1).tryAppend(r)) {
            }
            else {
                LayLine l = new LayLine();
                l.boxes.add(r);
                lines.add(l);
                if (lines.size() == 14) {
                }
            }
        }
        if (lines.size() < 1) 
            return lines;
        double height = 0.0;
        double x = 10000000.0;
        for (LayLine l : lines) {
            height += l.getHeight();
            if (l.getX() < x) 
                x = l.getX();
        }
        height /= ((double)lines.size());
        int errs = 0;
        int max = (lines.size() * ((lines.size() - 1))) / 2;
        for (int i = 0; i < (lines.size() - 1); i++) {
            for (int j = i + 1; j < lines.size(); j++) {
                if (lines.get(i).getY() > (lines.get(j).getY() + height)) 
                    errs++;
            }
        }
        if (errs > (max / 2)) {
            for (int ii = 0; ii < lines.size(); ii++) {
                boolean ch = false;
                for (int jj = 0; jj < (lines.size() - 1); jj++) {
                    if (lines.get(jj).compareTo(lines.get(jj + 1)) > 0) {
                        LayLine v = lines.get(jj);
                        com.pullenti.unisharp.Utils.putArrayValue(lines, jj, lines.get(jj + 1));
                        com.pullenti.unisharp.Utils.putArrayValue(lines, jj + 1, v);
                        ch = true;
                    }
                }
                if (!ch) 
                    break;
            }
        }
        return lines;
    }

    public static class LayLine implements Comparable {
    
        public java.util.ArrayList<com.pullenti.unitext.UnilayRectangle> boxes = new java.util.ArrayList<com.pullenti.unitext.UnilayRectangle>();
    
        public boolean canBeEqualsExceptPageNumber(LayLine ll) {
            if (ll.boxes.size() != boxes.size()) 
                return false;
            for (int i = 0; i < ll.boxes.size(); i++) {
                com.pullenti.unitext.UnilayRectangle b0 = boxes.get(i);
                com.pullenti.unitext.UnilayRectangle b1 = ll.boxes.get(i);
                if (b0.text == null && b1.text == null) {
                    if (b0.imageContent != null && b1.imageContent != null) {
                        if (b0.imageContent.length != b1.imageContent.length) 
                            return false;
                        for (int j = 0; j < b0.imageContent.length; j++) {
                            if (b0.imageContent[j] != b1.imageContent[j]) 
                                return false;
                        }
                    }
                    else 
                        return false;
                    continue;
                }
                if (b0.text == null || b1.text == null) 
                    return false;
                if (com.pullenti.unisharp.Utils.stringsEq(b0.text, b1.text)) 
                    continue;
                int i0 = 0;
                int i1 = 0;
                while ((i0 < b0.text.length()) && (i1 < b1.text.length())) {
                    char ch0 = b0.text.charAt(i0);
                    char ch1 = b1.text.charAt(i1);
                    if (ch0 == ch1) {
                        i0++;
                        i1++;
                        continue;
                    }
                    boolean oo = false;
                    while ((i0 < b0.text.length()) && Character.isDigit(b0.text.charAt(i0))) {
                        i0++;
                        oo = true;
                    }
                    while ((i1 < b1.text.length()) && Character.isDigit(b1.text.charAt(i1))) {
                        i1++;
                        oo = true;
                    }
                    if (!oo) 
                        return false;
                }
                if ((i0 < b0.text.length()) || (i1 < b1.text.length())) 
                    return false;
            }
            return true;
        }
    
        @Override
        public String toString() {
            StringBuilder txt = new StringBuilder();
            for (com.pullenti.unitext.UnilayRectangle b : boxes) {
                if (b.text != null) {
                    if (txt.length() > 0) 
                        txt.append(' ');
                    txt.append(b.text);
                }
            }
            return (txt.toString() + " X=" + this.getX() + " X1=" + (this.getX() + this.getWidth()) + " Y=" + this.getY() + " Y2=" + (this.getY() + this.getHeight()));
        }
    
        public double getX() {
            return (double)(boxes.size() == 0 ? 0 : (int)boxes.get(0).left);
        }
    
    
        public double getWidth() {
            if (boxes.size() == 0) 
                return 0.0;
            return (boxes.get(boxes.size() - 1).right - boxes.get(0).left);
        }
    
    
        public double getY() {
            double y = 0.0;
            for (com.pullenti.unitext.UnilayRectangle w : boxes) {
                y += w.top;
            }
            if (boxes.size() > 0) 
                y /= ((double)boxes.size());
            return y;
        }
    
    
        public double getHeight() {
            double y = 0.0;
            double h = 0.0;
            for (com.pullenti.unitext.UnilayRectangle w : boxes) {
                y += w.top;
                h += w.bottom;
            }
            if (boxes.size() > 0) {
                y /= ((double)boxes.size());
                h /= ((double)boxes.size());
                h -= y;
            }
            return h;
        }
    
    
        public boolean tryAppend(com.pullenti.unitext.UnilayRectangle r) {
            if (boxes.size() == 0) {
                boxes.add(r);
                return true;
            }
            if ((((r.top + r.bottom)) / (2.0)) < getY()) 
                return false;
            if (r.top > ((this.getY() + ((this.getHeight() / (2.0)))))) 
                return false;
            if (r.left >= ((getX() + getWidth()) - (2.0))) {
                boxes.add(r);
                return true;
            }
            for (int i = 0; i < boxes.size(); i++) {
                if (r.right <= boxes.get(i).left) {
                    boxes.add(i, r);
                    return true;
                }
            }
            return false;
        }
    
        @Override
        public int compareTo(Object obj) {
            LayLine l = (LayLine)com.pullenti.unisharp.Utils.cast(obj, LayLine.class);
            if (getY() < l.getY()) 
                return -1;
            if (getY() > l.getY()) 
                return 1;
            if (getX() < l.getX()) 
                return -1;
            if (getX() > l.getX()) 
                return 1;
            return 0;
        }
        public LayLine() {
        }
    }

    public UnilayoutHelper() {
    }
    public static UnilayoutHelper _globalInstance;
    
    static {
        try { _globalInstance = new UnilayoutHelper(); } 
        catch(Exception e) { }
    }
}
