```"""Generate a point-in-time climate-based sky."""
from __future__ import division
import honeybee.typing as typing

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.

Args:
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 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 \
# write wea file first
wea_file = self.write_wea(folder, hoys=hoys)
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)
```