# This collection of classes just let me call something like compass.east to get 90 degrees.

from collections import namedtuple


class CompassSimple:
    """A class to use one of the 32 compass points inplace of degrees.  This was made so I could just call
    compass.east to get 90 degrees.
    """

    north = N = 0
    north_by_east = NbE = 11.25
    north_northeast = NNE = 22.5
    northeast_by_north = NEbN = 33.75
    northeast = NE = 45
    northeast_by_east = NEbE = 56.25
    east_northeast = ENE = 67.5
    east_by_north = EbN = 78.75
    east = E = 90
    east_by_south = EbS = 101.25
    east_southeast = ESE = 112.5
    southeast_by_east = SEbE = 123.75
    southeast = SE = 135
    southeast_by_south = SEbS = 146.25
    south_southeast = SSE = 157.5
    south_by_east = SbE = 168.75
    south = S = 180
    south_by_west = SbW = 191.25
    south_southwest = SSW = 202.5
    southwest_by_south = SWbS = 213.75
    southwest = SW = 225
    southwest_by_west = SWbW = 236.25
    west_southwest = WSW = 247.5
    west_by_south = WbS = 258.75
    west = W = 270
    west_by_north = WbN = 281.25
    west_northwest = WNW = 292.5
    northwest_by_west = NWbW = 303.75
    northwest = NW = 315
    northwest_by_north = NWbN = 326.25
    north_northwest = NNW = 337.5
    north_by_west = NbW = 348.75


class CompassComplex:
    """This class contains more information then the CompassSimple class.
    Recommended to use import CompassComplex as compass.
    """

    CompassPoint = namedtuple(
        "CompassPoint",
        ["Point", "Abbr", "WindPoint", "Minimum", "Direction", "Maximum"],
    )
    compass = dict()
    compass["north"] = compass["N"] = north = N = CompassPoint(
        "north", "N", "Tramontana", 354.375, 0.000, 5.625
    )
    compass["north by east"] = compass["NbE"] = north_by_east = NbE = CompassPoint(
        "north by east",
        "NbE",
        "Quarto di Tramontana verso Greco",
        5.625,
        11.250,
        16.875,
    )
    compass["north-northeast"] = compass["NNE"] = north_northeast = NNE = CompassPoint(
        "north-northeast", "NNE", "Greco-Tramontana", 16.875, 22.500, 28.125
    )
    compass["northeast by north"] = compass["NEbN"] = northeast_by_north = NEbN = (
        CompassPoint(
            "northeast by north",
            "NEbN",
            "Quarto di Greco verso Tramontana",
            28.125,
            33.750,
            39.375,
        )
    )
    compass["northeast"] = compass["NE"] = northeast = NE = CompassPoint(
        "northeast", "NE", "Greco", 39.375, 45.000, 50.625
    )
    compass["northeast by east"] = compass["NEbE"] = northeast_by_east = NEbE = (
        CompassPoint(
            "northeast by east",
            "NEbE",
            "Quarto di Greco verso Levante",
            50.625,
            56.250,
            61.875,
        )
    )
    compass["east-northeast"] = compass["ENE"] = east_northeast = ENE = CompassPoint(
        "east-northeast", "ENE", "Greco-Levante", 61.875, 67.500, 73.125
    )
    compass["east by north"] = compass["EbN"] = east_by_north = EbN = CompassPoint(
        "east by north", "EbN", "Quarto di Levante verso Greco", 73.125, 78.750, 84.375
    )
    compass["east"] = compass["E"] = east = E = CompassPoint(
        "east", "E", "Levante", 84.375, 90.000, 95.625
    )
    compass["east by south"] = compass["EbS"] = east_by_south = EbS = CompassPoint(
        "east by south",
        "EbS",
        "Quarto di Levante verso Scirocco",
        95.625,
        101.250,
        106.875,
    )
    compass["east-southeast"] = compass["ESE"] = east_southeast = ESE = CompassPoint(
        "east-southeast", "ESE", "Levante-Scirocco", 106.875, 112.500, 118.125
    )
    compass["southeast by east"] = compass["SEbE"] = southeast_by_east = SEbE = (
        CompassPoint(
            "southeast by east",
            "SEbE",
            "Quarto di Scirocco verso Levante",
            118.125,
            123.750,
            129.375,
        )
    )
    compass["southeast"] = compass["SE"] = southeast = SE = CompassPoint(
        "southeast", "SE", "Scirocco", 129.375, 135.000, 140.625
    )
    compass["southeast by south"] = compass["SEbS"] = southeast_by_south = SEbS = (
        CompassPoint(
            "southeast by south",
            "SEbS",
            "Quarto di Scirocco verso Ostro",
            140.625,
            146.250,
            151.875,
        )
    )
    compass["south-southeast"] = compass["SSE"] = south_southeast = SSE = CompassPoint(
        "south-southeast", "SSE", "Ostro-Scirocco", 151.875, 157.500, 163.125
    )
    compass["south by east"] = compass["SbE"] = south_by_east = SbE = CompassPoint(
        "south by east",
        "SbE",
        "Quarto di Ostro verso Scirocco",
        163.125,
        168.750,
        174.375,
    )
    compass["south"] = compass["S"] = south = S = CompassPoint(
        "south", "S", "Ostro", 174.375, 180.000, 185.625
    )
    compass["south by west"] = compass["SbW"] = south_by_west = SbW = CompassPoint(
        "south by west",
        "SbW",
        "Quarto di Ostro verso Libeccio",
        185.625,
        191.250,
        196.875,
    )
    compass["south-southwest"] = compass["SSW"] = south_southwest = SSW = CompassPoint(
        "south-southwest", "SSW", "Ostro-Libeccio", 196.875, 202.500, 208.125
    )
    compass["southwest by south"] = compass["SWbS"] = southwest_by_south = SWbS = (
        CompassPoint(
            "southwest by south",
            "SWbS",
            "Quarto di Libeccio verso Ostro",
            208.125,
            213.750,
            219.375,
        )
    )
    compass["southwest"] = compass["SW"] = southwest = SW = CompassPoint(
        "southwest", "SW", "Libeccio", 219.375, 225.000, 230.625
    )
    compass["southwest by west"] = compass["SWbW"] = southwest_by_west = SWbW = (
        CompassPoint(
            "southwest by west",
            "SWbW",
            "Quarto di Libeccio verso Ponente",
            230.625,
            236.250,
            241.875,
        )
    )
    compass["west-southwest"] = compass["WSW"] = west_southwest = WSW = CompassPoint(
        "west-southwest", "WSW", "Ponente-Libeccio", 241.875, 247.500, 253.125
    )
    compass["west by south"] = compass["WbS"] = west_by_south = WbS = CompassPoint(
        "west by south",
        "WbS",
        "Quarto di Ponente verso Libeccio",
        253.125,
        258.750,
        264.375,
    )
    compass["west"] = compass["W"] = west = W = CompassPoint(
        "west", "W", "Ponente", 264.375, 270.000, 275.625
    )
    compass["west by north"] = compass["WbN"] = west_by_north = WbN = CompassPoint(
        "west by north",
        "WbN",
        "Quarto di Ponente verso Maestro",
        275.625,
        281.250,
        286.875,
    )
    compass["west-northwest"] = compass["WNW"] = west_northwest = WNW = CompassPoint(
        "west-northwest", "WNW", "Maestro-Ponente", 286.875, 292.500, 298.125
    )
    compass["northwest by west"] = compass["NWbW"] = northwest_by_west = NWbW = (
        CompassPoint(
            "northwest by west",
            "NWbW",
            "Quarto di Maestro verso Ponente",
            298.125,
            303.750,
            309.375,
        )
    )
    compass["northwest"] = compass["NW"] = northwest = NW = CompassPoint(
        "northwest", "NW", "Maestro", 309.375, 315.000, 320.625
    )
    compass["northwest by north"] = compass["NWbN"] = northwest_by_north = NWbN = (
        CompassPoint(
            "northwest by north",
            "NWbN",
            "Quarto di Maestro verso Tramontana",
            320.625,
            326.250,
            331.875,
        )
    )
    compass["north-northwest"] = compass["NNW"] = north_northwest = NNW = CompassPoint(
        "north-northwest", "NNW", "Maestro-Tramontana", 331.875, 337.500, 343.125
    )
    compass["north by west"] = compass["NbW"] = north_by_west = NbW = CompassPoint(
        "north by west",
        "NbW",
        "Quarto di Tramontana verso Maestro",
        343.125,
        348.750,
        354.375,
    )

    full_name = [
        "north",
        "north by east",
        "north-northeast",
        "northeast by north",
        "northeast",
        "northeast by east",
        "east-northeast",
        "east by north",
        "east",
        "east by south",
        "east-southeast",
        "southeast by east",
        "southeast",
        "southeast by south",
        "south-southeast",
        "south by east",
        "south",
        "south by west",
        "south-southwest",
        "southwest by south",
        "southwest",
        "southwest by west",
        "west-southwest",
        "west by south",
        "west",
        "west by north",
        "west-northwest",
        "northwest by west",
        "northwest",
        "northwest by north",
        "north-northwest",
        "north by west",
    ]
    abbr = [
        "N",
        "NbE",
        "NNE",
        "NEbN",
        "NE",
        "NEbE",
        "ENE",
        "EbN",
        "E",
        "EbS",
        "ESE",
        "SEbE",
        "SE",
        "SEbS",
        "SSE",
        "SbE",
        "S",
        "SbW",
        "SSW",
        "SWbS",
        "SW",
        "SWbW",
        "WSW",
        "WbS",
        "W",
        "WbN",
        "WNW",
        "NWbW",
        "NW",
        "NWbN",
        "NNW",
        "NbW",
    ]

    def __init__(self):
        """
        Initializer for the Compass Class
        """
        pass

    def get_point(self, heading):
        return self._get_dir_name(heading, self.full_name)

    def get_abbr(self, heading):
        return self._get_dir_name(heading, self.abbr)

    def _get_dir_name(self, heading, type):
        """
        General case for finding the direction
        :param heading:
        :param type:
        :return:
        """
        heading = heading % 360
        for point in type:
            if self.compass[point].Direction == 0:
                if (
                    self.compass[point].Minimum <= heading <= 360.0
                    or 0.0 <= heading < self.compass[point].Maximum
                ):
                    return point
            elif self.compass[point].Minimum <= heading < self.compass[point].Maximum:
                return point


if __name__ == "__main__":
    import math

    print(CompassComplex.get_point(CompassComplex(), 200))
    print(CompassComplex.get_point(0))
    print(CompassComplex.get_point(360))
    print(CompassComplex.get_point(100))
    print(CompassComplex.get_point(2 * math.pi))
    print(CompassComplex.get_point(-15))
    print(CompassComplex.get_point(-360))
    print(CompassComplex.get_point(400))
    print(CompassComplex.get_point(-600))
    print(CompassComplex.N)
    print(CompassComplex.E.Direction)
