# This file is part of lyx2lyx
# Copyright (C) 2002-2004 José Matos <jamatos@lyx.org>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

"""Convert files to the file format generated by lyx 1.1.6, until fix2"""

import re

from parser_tools import check_token, find_re, find_token, find_tokens

lyxtable_re = re.compile(r".*\\LyXTable$")


def update_tabular(document):
    "Update tabular to version 1 (xml like syntax)."
    lines = document.body
    i = 0
    while True:
        i = find_re(lines, lyxtable_re, i)
        if i == -1:
            break
        prop_dict = {
            "family": "default",
            "series": "default",
            "shape": "default",
            "size": "default",
            "emph": "default",
            "bar": "default",
            "noun": "default",
            "latex": "default",
            "color": "default",
        }

        # remove \LyXTable
        lines[i] = lines[i][:-9]
        i = i + 1
        lines.insert(i, "")
        i = i + 1
        lines[i] = "\\begin_inset  Tabular"
        i = i + 1
        head = lines[i].split()
        rows = int(head[0])
        columns = int(head[1])

        tabular_line = i
        i = i + 1
        lines.insert(
            i,
            f'<Features rotate="{head[2]}" islongtable="{head[3]}" endhead="{head[4]}" endfirsthead="{head[5]}" endfoot="{head[6]}" endlastfoot="{head[7]}">',
        )

        i = i + 1

        row_info = []
        cont_row = []
        for j in range(rows):
            row_info.append(lines[i].split())
            if lines[i].split()[2] == "1":
                cont_row.append(j)
            del lines[i]

        column_info = []
        col_info_re = re.compile(r'(\d) (\d) (\d) (".*") (".*")')
        for j in range(columns):
            column_info.append(col_info_re.match(lines[i]).groups())
            del lines[i]

        cell_info = []
        cell_col = []
        ncells = 0
        cell_re = re.compile(r'(\d) (\d) (\d) (\d) (\d) (\d) (\d) (".*") (".*")')
        for j in range(rows):
            for k in range(columns):
                # add column location to read properties
                cell_info.append(cell_re.match(lines[i]).groups())
                cell_col.append(k)
                if lines[i][0] != "2":
                    ncells = ncells + 1
                del lines[i]

        lines[tabular_line] = (
            f'<LyXTabular version="1" rows="{rows-len(cont_row)}" columns="{columns}">'
        )
        del lines[i]
        if not lines[i]:
            del lines[i]

        # Read cells
        l = 0
        cell_content = []
        for j in range(rows):
            cell_content.append([])

        for j in range(rows):
            for k in range(columns):
                cell_content[j].append([])

        for j in range(rows):
            for k in range(columns):
                m = j * columns + k
                if cell_info[m][0] == "2":
                    continue

                if l == ncells - 1:
                    # the end variable refers to cell end, not to document end.
                    end = find_tokens(
                        lines,
                        ["\\layout", "\\the_end", "\\end_deeper", "\\end_float"],
                        i,
                    )
                else:
                    end = find_token(lines, "\\newline", i)

                if end == -1:
                    document.error("Malformed LyX file.")

                end = end - i
                while end > 0:
                    cell_content[j][k].append(lines[i])
                    del lines[i]
                    end = end - 1

                if lines[i].find("\\newline") != -1:
                    del lines[i]
                l = l + 1

        tmp = []
        tmp.append("")

        for j in range(rows):
            if j in cont_row:
                continue
            tmp.append(
                f'<Row topline="{row_info[j][0]}" bottomline="{row_info[j][1]}" newpage="{row_info[j][3]}">'
            )

            for k in range(columns):
                if j:
                    tmp.append("<Column>")
                else:
                    tmp.append(
                        f'<Column alignment="{column_info[k][0]}" valignment="0" leftline="{column_info[k][1]}" rightline="{column_info[k][2]}" width={column_info[k][3]} special={column_info[k][4]}>'
                    )
                m = j * columns + k

                leftline = int(column_info[k][1])
                if cell_info[m][0] == "1":
                    n = m + 1
                    while n < rows * columns - 1 and cell_info[n][0] == "2":
                        n = n + 1
                    rightline = int(column_info[cell_col[n - 1]][2])
                else:
                    # not a multicolumn main cell
                    rightline = int(column_info[k][2])

                tmp.append(
                    '<Cell multicolumn="%s" alignment="%s" valignment="0" topline="%s" bottomline="%s" leftline="%d" rightline="%d" rotate="%s" usebox="%s" width=%s special=%s>'
                    % (
                        cell_info[m][0],
                        cell_info[m][1],
                        cell_info[m][2],
                        cell_info[m][3],
                        leftline,
                        rightline,
                        cell_info[m][5],
                        cell_info[m][6],
                        cell_info[m][7],
                        cell_info[m][8],
                    )
                )
                tmp.append("\\begin_inset Text")
                tmp.append("")
                tmp.append("\\layout %s" % document.default_layout)
                tmp.append("")

                if cell_info[m][0] != "2":
                    paragraph = []
                    if cell_info[m][4] == "1":
                        l = j
                        paragraph = paragraph + cell_content[j][k]
                        while cell_info[m][4] == "1":
                            m = m + columns
                            l = l + 1
                            if l >= rows:
                                break
                            paragraph = paragraph + cell_content[l][k]
                    else:
                        paragraph = cell_content[j][k]
                    tmp = tmp + set_paragraph_properties(paragraph, prop_dict)

                tmp.append("\\end_inset ")
                tmp.append("</Cell>")
                tmp.append("</Column>")
            tmp.append("</Row>")

        tmp.append("</LyXTabular>")
        tmp.append("")
        tmp.append("\\end_inset ")
        tmp.append("")
        tmp.append("")
        lines[i:i] = tmp

        i = i + len(tmp)


prop_exp = re.compile(r"\\(\S*)\s*(\S*)")


def set_paragraph_properties(lines, prop_dict):
    "Set paragraph properties."
    # we need to preserve the order of options
    properties = [
        "family",
        "series",
        "shape",
        "size",
        "emph",
        "bar",
        "noun",
        "latex",
        "color",
    ]
    prop_value = {
        "family": "default",
        "series": "medium",
        "shape": "up",
        "size": "normal",
        "emph": "off",
        "bar": "no",
        "noun": "off",
        "latex": "no_latex",
        "color": "none",
    }

    start = 0
    end = 0
    i = 0
    n = len(lines)

    # skip empty lines
    while i < n and lines[i] == "":
        i = i + 1
    start = i

    # catch open char properties
    while i < n and lines[i][:1] == "\\":
        result = prop_exp.match(lines[i])
        # sys.stderr.write(lines[i]+"\n")
        prop = result.group(1)
        if prop not in properties:
            break
        else:
            prop_dict[prop] = result.group(2)
        i = i + 1
    end = i

    aux = []
    insert = 0
    for prop in properties:
        if prop_dict[prop] != "default":
            insert = 1
            if prop == "color":
                aux.append(f"\\{prop} {prop_dict[prop]}")
            elif prop != "family" or prop_dict[prop] != "roman":
                aux.append(f"\\{prop} {prop_dict[prop]} ")

    # remove final char properties
    n = len(lines)
    changed_prop = []

    while n:
        n = n - 1
        if not lines[n]:
            del lines[n]
            continue

        if lines[n][:1] == "\\":
            result = prop_exp.match(lines[n])
            prop = result.group(1)
            if prop in properties:
                changed_prop.append(prop)
                prop_dict[prop] = result.group(2)
                del lines[n]
                continue

            if check_token(lines[n], "\\end_inset"):
                # ensure proper newlines after inset end
                lines.append("")
                lines.append("")
        break

    for line in lines[end:]:
        if line[:1] == "\\":
            result = prop_exp.match(line)
            prop = result.group(1)
            if prop in properties and prop not in changed_prop:
                prop_dict[prop] = result.group(2)

    if not lines[start:] and not lines[end:]:
        return []

    result = lines[:start] + aux[:] + lines[end:]
    if insert and result[0] != "":
        return [""] + result[:]

    return result[:]


def update_language(document):
    """Update document language, if language is default convert it to
    english."""
    header = document.header
    i = find_token(header, "\\language", 0)
    if i == -1:
        # no language, should emit a warning
        header.append("\\language english")
        return
    # This is the lyx behaviour: defaults to english
    if header[i].split()[1] == "default":
        header[i] = "\\language english"
    return


supported_versions = ["1.1.6", "1.1.6fix1", "1.1.6fix2", "1.1"]
convert = [[217, [update_tabular, update_language]]]
revert = []


if __name__ == "__main__":
    pass
