from bs4 import BeautifulSoup


def check_if_true(value: str):
    if value == '1' or value == 'True' or value == 'true':
        return True
    return False


def change_paragraph_properties(old_properties: "BaseProperties",
                                tree: BeautifulSoup):
    """
    changes old properties indent, size, jc, spacing_before, spacing_after if they were found in tree
    :param old_properties: Paragraph
    :param tree: BeautifulSoup tree with properties
    """
    change_indent(old_properties, tree)
    change_size(old_properties, tree)
    change_jc(old_properties, tree)
    change_spacing(old_properties, tree)


def change_run_properties(old_properties: "BaseProperties",
                          tree: BeautifulSoup):
    """
    changes old properties: bold, italic, underlined, size if they were found in tree
    :param old_properties: Run
    :param tree: BeautifulSoup tree with properties
    """
    change_size(old_properties, tree)
    change_caps(old_properties, tree)
    # bold
    if tree.b:
        b_tag = tree.b.get("w:val", True)
        old_properties.bold = check_if_true(b_tag) if isinstance(b_tag, str) else b_tag

    # italic
    if tree.i:
        i_tag = tree.i.get("w:val", True)
        old_properties.italic = check_if_true(i_tag) if isinstance(i_tag, str) else i_tag

    # underlined
    if tree.u:
        u_tag = tree.u.get("w:val", False)
        if u_tag == 'none':
            old_properties.underlined = False
        elif isinstance(u_tag, str):
            old_properties.underlined = True


def change_indent(old_properties: "BaseProperties",
                  tree: BeautifulSoup):
    """
    changes old properties: indent if it was found in tree
    :param old_properties: Paragraph
    :param tree: BeautifulSoup tree with properties
    """
    # firstLine describes additional indentation to current indentation, if hanging is present firstLine is ignored
    # firstLineChars differs from firstLine only in measurement (one hundredths of a character unit)
    # hanging removes indentation from current indentation (analogous hangingChars)
    # start describes classical indentation (startChars)
    # left isn't specified in the documentation, F
    # main measurement 1/1440 of an inch
    # 1 inch is 12 char units, 1/100 char unit = 1/1200 inch = 1.2 * (1/1440 of an inch)

    attributes = {"firstLine": 0, "firstLineChars": 0, "hanging": 0, "hangingChars": 0,
                  "start": 0, "startChars": 0, "left": 0}
    if tree.ind:
        for attribute in attributes:
            attributes[attribute] = int(tree.ind.get("w:{}".format(attribute), 0))
    else:
        return
    indentation = 0
    if attributes["left"] != 0:
        indentation = attributes["left"]
    elif attributes["start"] != 0:
        indentation = attributes["start"]
    elif attributes["startChars"] != 0:
        indentation = attributes["startChars"] / 1.2

    if attributes["firstLine"] != 0 and attributes["hanging"] == 0:
        indentation += attributes["firstLine"]

    if attributes["firstLineChars"] != 0 and attributes["hangingChars"] == 0:
        indentation += attributes["firstLineChars"] / 1.2

    if attributes["hanging"] != 0:
        indentation -= attributes["hanging"]
    elif attributes["hangingChars"] != 0:
        indentation -= attributes["hangingChars"] / 1.2

    old_properties.indentation = indentation


def change_size(old_properties: "BaseProperties",
                tree: BeautifulSoup):
    """
    changes old properties: size if it was found in tree
    :param old_properties: Paragraph or Run
    :param tree: BeautifulSoup tree with properties
    """
    if tree.sz:
        old_properties.size = int(tree.sz.get('w:val', old_properties.size))


def change_jc(old_properties: "BaseProperties",
              tree: BeautifulSoup):
    """
    changes old_properties: jc (alignment) if tag jc was found in tree
    :param old_properties: Paragraph
    :param tree: BeautifulSoup tree with properties
    """
    # alignment values: left, right, center, both
    # left is default value
    if not tree.jc:
        return
    if tree.bidi:
        bidi_tag = tree.bidi.get('w:val', True)
        right_to_left = check_if_true(bidi_tag) if isinstance(bidi_tag, str) else bidi_tag
    else:
        right_to_left = False

    jc_tag = tree.jc.get('w:val', old_properties.jc)

    if jc_tag == 'both':
        old_properties.jc = 'both'
    elif jc_tag == 'center':
        old_properties.jc = 'center'
    elif jc_tag == 'right':
        old_properties.jc = 'right'
    elif jc_tag == 'end' and not right_to_left:
        old_properties.jc = 'right'
    elif jc_tag == 'start' and right_to_left:
        old_properties.jc = 'right'


def change_caps(old_properties: "BaseProperties",
                tree: BeautifulSoup):
    """
    changes old_properties: caps if tag caps was found in tree
    :param old_properties: Paragraph or Run
    :param tree: BeautifulSoup tree with properties
    """
    if not tree.caps:
        return

    caps_tag = tree.caps.get('w:val', True)
    old_properties.caps = check_if_true(caps_tag) if isinstance(caps_tag, str) else caps_tag


def change_spacing(old_properties: "BaseProperties",
                   tree: BeautifulSoup):
    """
    changes old_properties: spacing_before, spacing_after if tag spacing was found in tree
    :param old_properties: Paragraph
    :param tree: BeautifulSoup tree with properties
    """
    # tag <spacing> may have the following attributes for spacing between paragraphs:
    # after / before (measured in twentieths of a point), ignored if afterLines or afterAutospacing are specified
    # afterAutospacing / beforeAutospacing (we set 0 if specified) if is specified, other attributes are ignored
    # afterLines / beforeLines (measured in one hundredths of a line)

    # if we have spacing after value for the previous paragraph and spacing before value for the next paragraph
    # we choose maximum between these two values
    if not tree.spacing:
        return

    before, after = 0, 0
    before_autospacing = tree.spacing.get("w:beforeAutospacing", False)
    before_autospacing = check_if_true(before_autospacing) if before_autospacing else before_autospacing

    after_autospacing = tree.spacing.get("w:afterAutospacing", False)
    after_autospacing = check_if_true(after_autospacing) if after_autospacing else after_autospacing

    if not before_autospacing:
        before_lines = tree.spacing.get("w:beforeLines", False)
        before_lines = int(before_lines) if before_lines else before_lines
        if not before_lines:
            before_tag = tree.spacing.get("w:before", False)
            before = int(before_tag) if before_tag else before
        else:
            before = before_lines

    if not after_autospacing:
        after_lines = tree.spacing.get("w:afterLines", False)
        after_lines = int(after_lines) if after_lines else after_lines
        if not after_lines:
            after_tag = tree.spacing.get("w:after", False)
            after = int(after_tag) if after_tag else after
        else:
            after = after_lines

    old_properties.spacing_before = before
    old_properties.spacing_after = after
