from lib import (
    draw_template,
    drawing_save,
    EXTRA_HEIGHT,
    LANE_THICKNESS,
    LEGEND_TEXT_STYLE,
    sect_ths,
    TEXTURE_COLOR_1,
    TEXTURE_COLOR_2,
    TIME_THICKNESS,
    TIME_WIDTH,
    TIME_X,
    TOTAL_DUR,
    WIDTH,
    Y_PAD,
)
import svgwrite

FILENAME = "dist.svg"

LANE_HEIGHT = 100
TIME_Y = 5 * LANE_HEIGHT - LANE_THICKNESS
TIME_Y_TOP = TIME_Y - TIME_THICKNESS / 2
CONTOUR_0, CONTOUR_MAX = TIME_Y_TOP - Y_PAD, Y_PAD

HEIGHT = 5 * LANE_HEIGHT + EXTRA_HEIGHT

DISTS = [
    # end, dist_pitch, dynamic, gradual
    (14, 0 + 0 + 0, "pp", False),
    (15, 0 + 0 + 1, "mf", True),
    (20, 0 + 1 + 2, "mf", False),
    (21.5, 0 + 1 + 3, "f", True),
    (26.5, 0 + 1 + 2, "mf", False),
    (28, 0 + 1 + 3, "f", True),
    (32.5, 0 + 1 + 2, "mf", False),
    (34, 0 + 1 + 3, "f", True),
    (39.25, 0 + 1 + 2, "mf", False),
    (41, 0 + 1 + 3, "f", True),
    (46.25, 0 + 4 + 2, "ff", False),
    (48, 0 + 4 + 4, "ff", False),
    (53.25, 0 + 4 + 2, "ff", False),
    (55, 0 + 4 + 4, "ff", False),
    (1 * 60 + 10, 0 + 0 + 3, "p", False),
    (1 * 60 + 15, 0 + 1 + 2, "mp", False),
    (1 * 60 + 19.5, 0 + 0 + 2, "mf", False),
    (1 * 60 + 24, 0 + 0 + 3, "f", True),
    (1 * 60 + 32, 0 + 0 + 4, "f", False),
    (1 * 60 + 39, 0 + 0 + 3, "f", False),
    (1 * 60 + 45, 0 + 0 + 0, "p", False),
    (1 * 60 + 46, 0 + 3 + 2, "f", False),
    (1 * 60 + 48, 0 + 5 + 4, "ff", False),
    (1 * 60 + 49, 0 + 3 + 2, "f", False),
    (1 * 60 + 51, 0 + 5 + 4, "ff", False),
    (1 * 60 + 52, 0 + 3 + 2, "f", False),
    (1 * 60 + 54, 0 + 5 + 4, "ff", False),
    (1 * 60 + 55, 0 + 3 + 2, "f", False),
    (1 * 60 + 57, 0 + 5 + 4, "ff", False),
    (2 * 60 + 5, 0 + 5 + 3, "ff", False),
    (2 * 60 + 24, 2 + 5 + 2, "f", False),
    (2 * 60 + 27, 3 + 5 + 3, "ff", True),
    (2 * 60 + 36, 0 + 0 + 0, "p", False),
    (2 * 60 + 44, 0 + 3 + 3, "mf", False),
    (2 * 60 + 47, 0 + 3 + 0, "mf", False),
    (2 * 60 + 49.5, 0 + 5 + 2, "ff", False),
    (2 * 60 + 52, 0 + 1 + 2, "mf", False),
    (2 * 60 + 55, 2 + 6 + 3, "ff", False),
    (2 * 60 + 57.5, 0 + 5 + 2, "ff", False),
    (3 * 60 + 0, 0 + 1 + 2, "mf", False),
    (3 * 60 + 3, 2 + 6 + 3, "ff", False),
    (3 * 60 + 3.78, 0 + 5 + 4, "mf", False),
    (3 * 60 + 4.56, 0 + 3 + 3, "mf", False),
    (3 * 60 + 5.33, 0 + 5 + 4, "mf", False),
    (3 * 60 + 6.11, 0 + 3 + 3, "mf", False),
    (3 * 60 + 6.89, 0 + 5 + 4, "mf", False),
    (3 * 60 + 7.67, 0 + 3 + 3, "mf", False),
    (3 * 60 + 8.44, 0 + 5 + 4, "mf", False),
    (3 * 60 + 9.22, 0 + 3 + 3, "mf", False),
    (3 * 60 + 10, 0 + 5 + 4, "mf", False),
    (3 * 60 + 15, 0 + 0 + 0, "mp", False),
    (3 * 60 + 31, 0 + 0 + 3, "mp", False),
    (3 * 60 + 39, 0 + 1 + 4, "mf", False),
    (3 * 60 + 39.65, 0 + 5 + 4, "f", False),
    (3 * 60 + 41.6, 0 + 0 + 3, "f", False),
    (3 * 60 + 42.24, 0 + 5 + 4, "f", False),
    (3 * 60 + 44.19, 0 + 0 + 3, "f", False),
    (3 * 60 + 44.84, 0 + 5 + 4, "f", False),
    (3 * 60 + 45.49, 0 + 0 + 3, "f", False),
    (3 * 60 + 46.14, 0 + 5 + 4, "f", False),
    (3 * 60 + 46.78, 0 + 0 + 3, "f", False),
    (3 * 60 + 48.08, 0 + 5 + 4, "f", False),
    (4 * 60 + 15, 2 + 5 + 3, "f", False),
    (4 * 60 + 21, 0 + 5 + 3, "f", False),
    (4 * 60 + 23.5, 0 + 0 + 1, "mf", False),
    (4 * 60 + 31, 0 + 1 + 2, "mf", False),
    (4 * 60 + 33.5, 0 + 0 + 1, "mf", False),
    (4 * 60 + 41, 0 + 1 + 2, "mf", False),
    (4 * 60 + 44, 0 + 0 + 1, "mf", False),
]


def dyn_to_n(s):
    match s:
        case "pp":
            return 0
        case "p":
            return 1
        case "mp":
            return 2
        case "mf":
            return 4
        case "f":
            return 6
        case "ff":
            return 9
        case _:
            raise ValueError(f"Unrecognized dynamic: {s}")


def main():
    dwg = svgwrite.Drawing(filename=FILENAME, size=(WIDTH, HEIGHT), debug=True)

    draw_template(dwg, 5, LANE_HEIGHT)

    diag_hatch = dwg.add(
        dwg.pattern(
            id="diagHatch",
            width=10,
            height=10,
            patternTransform="rotate(45 0 0)",
            patternUnits="userSpaceOnUse",
        )
    )
    hatch_line = dwg.line(start=(0, 0), end=(0, 10))
    hatch_line.stroke(color=TEXTURE_COLOR_1, width=2)
    diag_hatch.add(hatch_line)

    legend_dist_box = dwg.add(dwg.rect(insert=(Y_PAD, Y_PAD), size=(128, 32)))
    legend_dist_box.stroke(
        color=TEXTURE_COLOR_1,
        width=2,
        opacity=0.75,
        linecap="round",
        linejoin="round",
    )
    legend_dist_box.fill(color="url(#diagHatch)", opacity=1.0)
    dwg.add(
        dwg.text(
            "dist\u2010pitch",
            insert=(Y_PAD + 15, Y_PAD + 24),
            style=LEGEND_TEXT_STYLE,
        )
    )
    legend_dyn_box = dwg.add(
        dwg.rect(insert=(Y_PAD, 2 * Y_PAD + 32), size=(128, 32))
    )
    legend_dyn_box.stroke(
        color=TEXTURE_COLOR_2,
        width=4,
        opacity=0.75,
        linecap="butt",
        linejoin="round",
    )
    legend_dyn_box.fill(color=TEXTURE_COLOR_2, opacity=0.0).dasharray([4, 4])
    dwg.add(
        dwg.text(
            "dynamic",
            insert=(Y_PAD + 20, 2 * Y_PAD + 32 + 24),
            style=LEGEND_TEXT_STYLE,
        )
    )

    dp_max, dyn_max = max(dp for _, dp, _, _ in DISTS), dyn_to_n("ff")

    start_t, prev_dyn_y = 0, TIME_Y_TOP
    dp_points = [(TIME_X, TIME_Y_TOP)]
    dyn_points = [(TIME_X, TIME_Y_TOP)]
    for end_t, dp, dyn, gradual in DISTS:
        x_start, x_end = TIME_X + TIME_WIDTH * (
            start_t / TOTAL_DUR
        ), TIME_X + TIME_WIDTH * (end_t / TOTAL_DUR)
        dp_y, dyn_y = (
            CONTOUR_0 - (CONTOUR_0 - CONTOUR_MAX) * dp / dp_max,
            CONTOUR_0 - (CONTOUR_0 - CONTOUR_MAX) * dyn_to_n(dyn) / dyn_max,
        )

        dp_points.append((x_start, dp_y))
        dp_points.append((x_end, dp_y))

        dyn_points.append((x_start, prev_dyn_y if gradual else dyn_y))
        dyn_points.append((x_end, dyn_y))

        start_t = end_t
        prev_dyn_y = dyn_y

    dp_points.append((TIME_X + TIME_WIDTH, TIME_Y_TOP))
    dyn_points.append((TIME_X + TIME_WIDTH, TIME_Y_TOP))

    dp_polyline = dwg.add(dwg.polyline(dp_points))
    dp_polyline.stroke(
        color=TEXTURE_COLOR_1,
        width=2,
        opacity=0.75,
        linecap="round",
        linejoin="round",
    )
    dp_polyline.fill(color="url(#diagHatch)", opacity=1.0)

    dyn_polyline = dwg.add(dwg.polyline(dyn_points))
    dyn_polyline.stroke(
        color=TEXTURE_COLOR_2,
        width=4,
        opacity=0.75,
        linecap="butt",
        linejoin="round",
    )
    dyn_polyline.fill(color=TEXTURE_COLOR_2, opacity=0.0).dasharray([4, 4])

    drawing_save(dwg)

    ts = [0] + [e for e, _, _, _ in DISTS]

    table = """<table>
  <thead>
    <tr>
      <td rowspan="2"></td>"""
    table += sect_ths(ts)

    dists, dyns = "", ""
    dp_prev = None
    dp_defer = 0
    dyn_prev = None, False
    dyn_defer = 0
    gradual_text = ""
    for _, dp, dyn, gradual in DISTS + [(TOTAL_DUR, None, None, None)]:
        if dp == dp_prev:
            dp_defer += 1
        elif dp_prev is not None:
            colspan = dp_defer + 1
            dp_defer = 0
            colspan_text = "" if colspan == 1 else f' colspan="{colspan}"'
            dists += f'\n      <td{colspan_text} class="center">{{% m "<{dp_prev},>", "c" %}}</td>'

        if (dyn, gradual) == dyn_prev:
            dyn_defer += 1
        elif dyn_prev[0] is not None:
            colspan = dyn_defer + 1
            dyn_defer = 0
            colspan_text = "" if colspan == 1 else f' colspan="{colspan}"'
            dyns += f'\n      <td{colspan_text} class="center">{gradual_text}{{% m "{dyn_prev[0]}" %}}</td>'

            if gradual:
                if dyn_to_n(dyn) > dyn_to_n(dyn_prev[0]):
                    gradual_text = "&#x1d192;&nbsp;"
                elif dyn_to_n(dyn) < dyn_to_n(dyn_prev[0]):
                    gradual_text = "&#x1d193;&nbsp;"
            else:
                gradual_text = ""

        dp_prev = dp
        dyn_prev = dyn, gradual

    table += f"""
    <tr>
      <th scope="row" class="no-wrap">{{% gloss "dist-pitch" %}}</th>{dists}
      <td rowspan="2"></td>
    </tr>
    <tr>
      <th scope="row">{{% gloss "dynamics", "dynamic" %}}</th>{dyns}
    </tr>
  </tbody>
</table>"""

    print(table)


if __name__ == "__main__":
    main()
