# coding=utf-8
"""Electrical connector in OpenDSS."""
from __future__ import division
from .._base import _GeometryBase
from .powerline import PowerLine
from ladybug_geometry.geometry2d.line import LineSegment2D
from ladybug_geometry.geometry2d.polyline import Polyline2D
from dragonfly.projection import polygon_to_lon_lat
[docs]
class ElectricalConnector(_GeometryBase):
    """Represents an electrical connector carrying wires in OpenDSS.
    Args:
        identifier: Text string for a unique electrical connector ID. Must contain only
            characters that are acceptable in OpenDSS. This will be used to
            identify the object across the exported geoJSON and OpenDSS files.
        geometry: A LineSegment2D or Polyline2D representing the geometry of the
            electrical connector.
        power_line: A PowerLine object representing the wires carried along the
            electrical connector and their arrangement.
    Properties:
        * identifier
        * display_name
        * geometry
        * power_line
        * phase_count
        * nominal_voltage
    """
    __slots__ = ('_power_line',)
    def __init__(self, identifier, geometry, power_line):
        """Initialize ElectricalConnector."""
        _GeometryBase.__init__(self, identifier)  # process the identifier
        assert isinstance(geometry, (LineSegment2D, Polyline2D)), 'Expected ' \
            
'ladybug_geometry LineSegment2D or Polyline2D. Got {}'.format(type(geometry))
        self._geometry = geometry
        self.power_line = power_line
[docs]
    @classmethod
    def from_dict(cls, data):
        """Initialize an ElectricalConnector from a dictionary.
        Args:
            data: A dictionary representation of an ElectricalConnector object.
        """
        # check the type of dictionary
        assert data['type'] == 'ElectricalConnector', 'Expected ElectricalConnector ' \
            
'dictionary. Got {}.'.format(data['type'])
        power_line = PowerLine.from_dict(data['power_line'])
        geo = LineSegment2D.from_dict(data['geometry']) \
            
if data['geometry']['type'] == 'LineSegment2D' \
            
else Polyline2D.from_dict(data['geometry'])
        con = cls(data['identifier'], geo, power_line)
        if 'display_name' in data and data['display_name'] is not None:
            con.display_name = data['display_name']
        return con 
[docs]
    @classmethod
    def from_dict_abridged(cls, data, power_lines):
        """Initialize an ElectricalConnector from an abridged dictionary.
        Args:
            data: A ElectricalConnectorAbridged dictionary.
            power_lines: A dictionary with identifiers of PowerLines as keys and Python
                PowerLine objects as values.
        """
        assert data['type'] == 'ElectricalConnectorAbridged', \
            
'Expected ElectricalConnectorAbridged. Got {}.'.format(data['type'])
        try:
            power_line = power_lines[data['power_line']]
        except KeyError as e:
            raise ValueError('Failed to find "{}" in power lines.'.format(e))
        geo = LineSegment2D.from_dict(data['geometry']) \
            
if data['geometry']['type'] == 'LineSegment2D' \
            
else Polyline2D.from_dict(data['geometry'])
        con = cls(data['identifier'], geo, power_line)
        if 'display_name' in data and data['display_name'] is not None:
            con.display_name = data['display_name']
        return con 
[docs]
    @classmethod
    def from_rnm_geojson_dict(
            cls, data, origin_lon_lat, conversion_factors, power_lines):
        """Get an ElectricalConnector from a dictionary as it appears in an RNM GeoJSON.
        Args:
            data: A GeoJSON dictionary representation of an ElectricalConnector feature.
            origin_lon_lat: An array of two numbers in degrees. The first value
                represents the longitude of the scene origin in degrees (between -180
                and +180). The second value represents latitude of the scene origin
                in degrees (between -90 and +90). Note that the "scene origin" is the
                (0, 0) coordinate in the 2D space of the input polygon.
            conversion_factors: A tuple with two values used to translate between
                meters and longitude, latitude.
            power_lines: A dictionary with identifiers of PowerLines as keys and Python
                PowerLine objects as values.
        """
        geo = cls._geojson_coordinates_to_line2d(
            data['geometry']['coordinates'], origin_lon_lat, conversion_factors)
        try:
            power_line = power_lines[data['properties']['Equip']]
        except KeyError as e:
            raise ValueError('Failed to find "{}" in power lines.'.format(e))
        return cls(data['properties']['Code'], geo, power_line) 
    @property
    def geometry(self):
        """Get a LineSegment2D or Polyline2D representing the electrical connector."""
        return self._geometry
    @property
    def power_line(self):
        """Get or set the PowerLine object carried along the electrical connector."""
        return self._power_line
    @power_line.setter
    def power_line(self, value):
        assert isinstance(value, PowerLine), 'Expected PowerLine object' \
            
' for electrical connector power_line. Got {}.'.format(type(value))
        value.lock()  # lock to avoid editing
        self._power_line = value
    @property
    def phase_count(self):
        """Get an integer for the number of phases this connector supports."""
        return self._power_line.phase_count
    @property
    def nominal_voltage(self):
        """Get an integer for the nominal voltage of this connector."""
        return self._power_line.nominal_voltage
[docs]
    def to_dict(self, abridged=False):
        """ElectricalConnector dictionary representation.
        Args:
            abridged: Boolean to note whether the full dictionary describing the
                object should be returned (False) or just an abridged version (True),
                which only specifies the identifier of the power line. (Default: False).
        """
        base = {'type': 'ElectricalConnector'} if not \
            
abridged else {'type': 'ElectricalConnectorAbridged'}
        base['identifier'] = self.identifier
        base['geometry'] = self.geometry.to_dict()
        base['power_line'] = self.power_line.identifier if abridged \
            
else self.power_line.to_dict()
        if self._display_name is not None:
            base['display_name'] = self.display_name
        return base 
[docs]
    def to_geojson_dict(self, start_id, end_id, origin_lon_lat, conversion_factors):
        """Get ElectricalConnector dictionary as it appears in an URBANopt geoJSON.
        Args:
            start_id: Identifier of the junction at the start of the wire.
            end_id: Identifier of the junction at the end of the wire.
            origin_lon_lat: An array of two numbers in degrees. The first value
                represents the longitude of the scene origin in degrees (between -180
                and +180). The second value represents latitude of the scene origin
                in degrees (between -90 and +90). Note that the "scene origin" is the
                (0, 0) coordinate in the 2D space of the input polygon.
            conversion_factors: A tuple with two values used to translate between
                meters and longitude, latitude.
        """
        if isinstance(self.geometry, LineSegment2D):
            pts = [(pt.x, pt.y) for pt in (self.geometry.p1, self.geometry.p2)]
        else:  # it's a polyline
            pts = [(pt.x, pt.y) for pt in self.geometry.vertices]
        coords = polygon_to_lon_lat(pts, origin_lon_lat, conversion_factors)
        return {
            'type': 'Feature',
            'properties': {
                'id': self.identifier,
                'type': 'ElectricalConnector',
                'startJunctionId': start_id,
                'endJunctionId': end_id,
                'total_length': round(self.geometry.length, 2),
                'connector_type': 'Wire',
                'electrical_catalog_name': self.power_line.identifier,
                'name': self.display_name
            },
            'geometry': {
                'type': 'LineString',
                'coordinates': coords
            }
        } 
    def __copy__(self):
        new_con = ElectricalConnector(self.identifier, self.geometry, self.power_line)
        new_con._display_name = self._display_name
        return new_con
    def __repr__(self):
        return 'ElectricalConnector: {}, [{} wires]'.format(
            self.display_name, self.power_line.wire_count)