"""Generate a point-in-time climate-based sky."""
from __future__ import division
import honeybee.typing as typing
import ladybug.futil as futil
from ladybug.wea import Wea
from ladybug_geometry.geometry2d.pointvector import Vector2D
import os
import math
[docs]
class SunMatrix(object):
    """Annual Climate-based Sun matrix.
    The output of SkyMatrix is similar to using command Radiance's gendaymtx command with
    ``-n -D`` options. The options are available in Radiance 5.3 and after that. For more
    information see gendaymtx documentation.
    https://www.radiance-online.org/learning/documentation/manual-pages/pdfs/gendaymtx.pdf
    Args:
        wea: A Ladybug wea object.
        north: A number between -360 and 360 for the counterclockwise difference between
            the North and the positive Y-axis in degrees. 90 is West and 270 is East
            (Default: 0)
    Properties:
        * wea
        * location
        * north
        * is_point_in_time
        * is_climate_based
    """
    __slots__ = ('_wea', '_north')
    def __init__(self, wea, north=0):
        """Create a climate-based sun matrix."""
        self.wea = wea
        self.north = north
    @property
    def wea(self):
        """Get and set wea."""
        return self._wea
    @wea.setter
    def wea(self, value):
        assert isinstance(value, Wea), \
            
'wea must be from type Wea not {}'.format(type(value))
        self._wea = value
    @property
    def north(self):
        """Get and set north direction.
        A number between -360 and 360 for the counterclockwise difference between
        the North and the positive Y-axis in degrees. 90 is West and 270 is East.
        """
        return self._north
    @north.setter
    def north(self, value):
        value = typing.float_in_range(value, -360, +360, 'Skymatrix north')
        self._north = value
    @property
    def is_climate_based(self):
        """Return True if the sky is created based on values from weather data."""
        return True
    @property
    def is_point_in_time(self):
        """Return True if the sky is generated for a single point in time."""
        return False
    @property
    def location(self):
        """Location information for sky matrix."""
        return self.wea.location
[docs]
    def north_from_vector(self, north_vector):
        """Automatically set the north property using a Vector2D.
        Args:
            north_vector: A ladybug_geometry Vector2D for the north direction
        """
        self._north = math.degrees(north_vector.angle_clockwise(Vector2D(0, 1))) 
[docs]
    @classmethod
    def from_dict(cls, input_dict):
        """Create the sky from a dictionary.
        Args:
            input_dict: A python dictionary in the following format
        .. code-block:: python
            {
                'type': 'SunMatrix',
                'wea': {},
                'north': 0.0  # optional
            }
        """
        if 'type' not in input_dict or input_dict['type'] != 'SunMatrix':
            raise ValueError('Input dict "type" must be "SunMatrix".')
        if 'north' in input_dict:
            sky = cls(Wea.from_dict(input_dict['wea']), input_dict['north'])
        else:
            sky = cls(input_dict['wea'])
        return sky 
    # TODO: add support for additional parameters
    # TODO: add gendaymtx to radiance-command and use it for validating inputs
[docs]
    def to_radiance(self, output_type=1, wea_file=None, output_name=None):
        """Return Radiance command to generate the sky.
        Note that you need to write the wea to a file (in.wea) before running this
        command.
        Alternatively you can use write method which will write the wea data to a file.
        Args:
            output_type: An integer between 0 to 1 for output type.
                * 0 = output in W/m2/sr visible
                * 1 = output in W/m2/sr solar (default)
            wea_file: Path to wea file (default: in.wea).
            output_name: A name for output files (default: suns).
        """
        output_type = typing.int_in_range(output_type, 0, 1, 'SunMatrix output type')
        wea_file = wea_file or 'in.wea'
        output_name = output_name or 'suns'
        if self.north == 0:
            command = 'gendaymtx -n -D {0}.mtx -M {0}.mod -O{1} {2}'.format(
                output_name, output_type, wea_file
            )
        else:
            command = 'gendaymtx -n -D {0}.mtx -M {0}.mod -O{1} -r {3} {2}'.format(
                output_name, output_type, wea_file, self.north
            )
        return command 
[docs]
    def to_dict(self):
        """Translate this matrix to a dictionary."""
        return {
            'type': 'SunMatrix',
            'wea': self.wea.to_dict(),
            'north': self.north
        } 
[docs]
    def write_wea(self, folder='.', name=None, hoys=None):
        """Write wea to a file.
        Args:
            folder: Path to target folder (Default: '.').
            name: Optional name for the wea file (Default: in.wea)
            hoys: Optional list of hoys to filter the hours of the wea. If None,
                this object's wea will be used as-is. Note that you may not want
                to use this input if this object's wea is not annual since an
                exception will be raised if a given hoy is not found in the
                wea. (Default: None).
        Returns:
            Path to wea file.
        """
        name = name or 'in.wea'
        file_path = os.path.join(folder, name)
        wea_obj = self.wea if hoys is None else self.wea.filter_by_hoys(hoys)
        return wea_obj.write(file_path=file_path) 
[docs]
    def to_file(self, folder, name=None, hoys=None, mkdir=False):
        """Write matrix to a Radiance file.
        This method also writes the wea information to a .wea file.
        Args:
            folder: Target folder.
            name: File name.
            hoys: Optional list of hoys to filter the hours of the wea. If None,
                this object's wea will be used as-is. Note that you may not want
                to use this input if this object's wea is not annual since an
                exception will be raised if a given hoy is not found in the
                wea. (Default: None).
            mkdir: A boolean to note if the directory should be created if doesn't
                exist (default: False).
        Returns:
            Full path to the newly created file.
        """
        name = typing.valid_string(name) if name \
            
else '%s.rad' % self.__class__.__name__.lower()
        # write wea file first
        wea_file = self.write_wea(folder, hoys=hoys)
        content = self.to_radiance(wea_file=os.path.split(wea_file)[-1])
        return futil.write_to_file_by_name(folder, name, '!' + content, mkdir) 
    def __eq__(self, value):
        if not isinstance(value, self.__class__) \
            
or value.wea != self.wea \
                
or value.north != self.north:
            return False
        return True
    def __ne__(self, value):
        return not self.__eq__(value)
    def __repr__(self):
        """Matrix representation."""
        return '%s: %s' % (self.__class__.__name__, self.wea.location.city)