######################### Transformer.py ####################
from lark import Transformer
import re

def dms_to_dd(dms):
    m = re.match(r"(\d+)([NSEW])", dms)
    val, hemi = m.groups()

    deg = int(val[:-4])
    minutes = int(val[-4:-2])
    seconds = int(val[-2:])

    dd = deg + minutes/60 + seconds/3600
    if hemi in ("S", "W"):
        dd *= -1
    return dd


def parse_coord_token(token):
    lat, lon = token.split()
    return Coord(dms_to_dd(lon), dms_to_dd(lat))


class NotamTransformer(Transformer):

    def COORD(self, token):
        return parse_coord_token(str(token))

    def NUMBER(self, token):
        return float(token)

    def coord_clause(self, items):
        return ("coords", items)

    def arc_clause(self, items):
        clockwise = True
        idx = 0

        if isinstance(items[0], str):
            clockwise = items[0] == "CLOCKWISE"
            idx += 1

        radius = items[idx]; idx += 1
        center = items[idx]; idx += 1

        end = items[idx] if idx < len(items) else None

        return ("arc", {
            "radius": radius,
            "center": center,
            "end": end,
            "clockwise": clockwise
        })

    def circle_clause(self, items):
        return ("circle", {
            "radius": items[0],
            "center": items[1]
        })

    def bearing_clause(self, items):
        return ("bearing", {
            "start": items[0],
            "end": items[1]
        })

    def area(self, items):
        segments = []
        coords = []

        for item in items:
            t, v = item

            if t == "coords":
                coords.extend(v)

            elif t == "arc":
                start = coords[-1]
                end = v["end"] or start

                segments.append(ArcSeg(
                    start=start,
                    end=end,
                    center=v["center"],
                    radius_nm=v["radius"],
                    clockwise=v["clockwise"]
                ))

                coords.append(end)

            elif t == "circle":
                segments.append(CircleSeg(
                    center=v["center"],
                    radius_nm=v["radius"]
                ))

            elif t == "bearing":
                segments.append(BearingArcSeg(
                    center=coords[-1],
                    radius_nm=5,
                    start_bearing=v["start"],
                    end_bearing=v["end"]
                ))

        # implicit lines
        for i in range(len(coords)-1):
            segments.append(LineSeg(coords[i], coords[i+1]))

        return AreaAST(segments)

    def start(self, items):
        return NotamAST(items)







