from enum import Enum
import json
from helix.constants.panel_type import PanelType
from helix.functions import fequal
from helix.models.coordinate import Coordinate


class PanelData(Enum):
    Handle = 'HANDLE'
    Blockname = 'BLOCKNAME'
    Subarray = 'SUBARRAY'
    PanelType = 'POS'
    WindZone = 'WIND'
    Ballast = 'BAL'
    LinkTray = 'LT_CALCULATED'
    CrossTray = 'XTRAY'
    WindAnchor = 'ANC'
    SeismicAnchor = 'SEISMIC'
    Coordinate = 'COORDINATE'
    Pressure = 'PSF'
    Id = 'ID'
    PresentedLinkTray = 'LTRAY'
    Xcoord = 'XCOORD'
    Ycoord = 'YCOORD'
    Rotation = 'ANGLE'
    FuzzyWindZone = 'FUZZYWINDZONE'


class PanelWarnings(Enum):
    MaxPsf = 'The values highlighted are panels that exceed our UL listed load limit. Please do not place panels in these areas to avoid exceeding the listed limit.'

class Panel(object):
    def __init__(self, handle=None, blockname=None, subarray=None, panel_type=None, wind_zone=None, ballast=None,
                 link_tray=None, cross_tray=None, wind_anchors=None, seismic_anchors=None, coordinate=None,
                 pressure=None, id=None, presented_link_tray=None, original_coordinate=None, fuzzy_wind_zone=False,
                 warnings=None):
        self.handle = handle
        self.blockname = blockname
        self.subarray = subarray
        self.panel_type = panel_type
        self.wind_zone = wind_zone
        self.ballast = ballast
        self.link_tray = link_tray
        self.cross_tray = cross_tray
        self.wind_anchors = wind_anchors
        self.seismic_anchors = seismic_anchors
        # this field after DXF parsing and before serialization into CSV contains translated coordinates (all positive)
        # and after deserialization from CSV contains original coordinates - same as original_coordinate field
        self.coordinate = coordinate
        self.original_coordinate = original_coordinate
        self.pressure = pressure
        self.id = id
        self.presented_link_tray = presented_link_tray
        self.fuzzy_wind_zone = fuzzy_wind_zone
        self.warnings = warnings or []

    def merge(self, other):
        if not isinstance(other, self.__class__):
            return self

        d = {}
        for key, data in self.__dict__.items():
            if data is not None:
                d[key] = data
            else:
                d[key] = other.__dict__.get(key)
        panel = Panel()
        panel.__dict__.update(d)
        return panel

    def is_subset(self, other):
        if not isinstance(other, self.__class__):
            return False
        for key, value in self.__dict__.items():
            if value is None:
                continue
            if other.__dict__[key] != value:
                return False
        return True

    def almost_equal(self, other, decimal=6):
        if not isinstance(other, self.__class__):
            return False
        if self.pressure is not None and other.pressure is not None:
            if not fequal(self.pressure, other.pressure, delta=(10 ** (-decimal))):
                print("Pressures are not equal to within %d decimal places, got %f, expected %f" % (decimal, self.pressure, other.pressure))
                return False
        elif self.pressure != other.pressure:
            return False
        for key, value in self.__dict__.items():
            if key == 'pressure':
                continue
            elif other.__dict__.get(key) != value:
                print("Expected %s to be equal, got %s, expected %s" % (key, str(value), str(other.__dict__.get(key))))
                return False
        return True

    def __deepcopy__(self, _):
        return Panel(handle=self.handle,
                     blockname=self.blockname,
                     subarray=self.subarray,
                     panel_type=self.panel_type,
                     wind_zone=self.wind_zone,
                     ballast=self.ballast,
                     link_tray=self.link_tray,
                     cross_tray=self.cross_tray,
                     wind_anchors=self.wind_anchors,
                     seismic_anchors=self.seismic_anchors,
                     coordinate=self.coordinate,
                     original_coordinate=self.original_coordinate,
                     pressure=self.pressure,
                     id=self.id,
                     presented_link_tray=self.presented_link_tray,
                     fuzzy_wind_zone=self.fuzzy_wind_zone)

    def __eq__(self, other):
        if self is other:
            return True
        return self.almost_equal(other, decimal=3)

    def __repr__(self):
        def json_forcer(x):
            if isinstance(x, PanelType):
                return x.value
            if isinstance(x, Coordinate):
                return x.dictionary
            return x.__dict__

        d = {key: value for (key, value) in self.__dict__.items() if value is not None}
        return json.dumps(d, sort_keys=True, default=json_forcer)
