# -*- coding: utf-8 -*-
"""
Created on Tue Apr  2 18:31:47 2013

@author: pietro
"""

from __future__ import print_function
import re


from read import GETTYPE, element2dict, DOC


class Parameter(object):

    def __init__(self, xparameter=None, diz=None):
        self._value = None
        diz = element2dict(xparameter) if xparameter is not None else diz
        if diz is None:
            raise TypeError('Xparameter or diz are required')
        self.name = diz['name']
        self.required = True if diz['required'] == 'yes' else False
        self.multiple = True if diz['multiple'] == 'yes' else False
        # check the type
        if diz['type'] in GETTYPE:
            self.type = GETTYPE[diz['type']]
            self.typedesc = diz['type']
            self._type = GETTYPE[diz['type']]
        else:
            raise TypeError('New type: %s, ignored' % diz['type'])

        self.description = diz.get('description', None)
        self.keydesc, self.keydescvalues = diz.get('keydesc', (None, None))

        #
        # values
        #
        if 'values' in diz:
            try:
                # chek if it's a range string: "3-30"
                isrange = re.match("(?P<min>\d+)-(?P<max>\d+)",
                                   diz['values'][0])
                if isrange:
                    range_min, range_max = isrange.groups()
                    self.values = range(int(range_min), int(range_max) + 1)
                    self.isrange = diz['values'][0]
                else:
                    self.values = [self._type(i) for i in diz['values']]
                    self.isrange = False
            except TypeError:
                self.values = [self._type(i) for i in diz['values']]
                self.isrange = False

        #
        # default
        #
        self.default = self._type(
            diz['default']) if 'default' in diz else None
        if self.default is not None:
            self._value = self.default

        self.guisection = diz.get('guisection', None)

        #
        # gisprompt
        #
        if 'gisprompt' in diz:
            self.type = diz['gisprompt']['prompt']
            self.input = False if diz['gisprompt']['age'] == 'new' else True
        else:
            self.input = True

    def _get_value(self):
        return self._value

    def _set_value(self, value):
        if isinstance(value, list) or isinstance(value, tuple):
            if self.multiple or self.keydescvalues:
                # check each value
                self._value = [self._type(val) for val in value]
            else:
                str_err = 'The Parameter <%s> does not accept multiple inputs'
                raise TypeError(str_err % self.name)
        elif self.typedesc == 'all':
            self._value = value
        elif isinstance(value, self._type):
            if hasattr(self, 'values'):
                if value in self.values:
                    self._value = value
                else:
                    raise ValueError('The Parameter <%s>, must be one of: %r' %
                                     (self.name, self.values))
            else:
                self._value = value
        else:
            str_err = 'The Parameter <%s>, require: %s, get: %s instead'
            raise TypeError(str_err % (self.name, self.typedesc, type(value)))

    # here the property function is used to transform value in an attribute
    # in this case we define which function must be use to get/set the value
    value = property(fget=_get_value, fset=_set_value)

    def get_bash(self):
        if isinstance(self._value, list) or isinstance(self._value, tuple):
            value = ','.join([str(v) for v in self._value])
        else:
            value = str(self._value)
        return """%s=%s""" % (self.name, value)

    def get_python(self):
        if not self.value:
            return ''
        return """%s=%r""" % (self.name, self._value)

    def __str__(self):
        return self.get_bash()

    def __repr__(self):
        str_repr = "Parameter <%s> (required:%s, type:%s, multiple:%s)"
        return str_repr % (self.name,
                           "yes" if self.required else "no",
                           self.type if self.type in (
                           'raster', 'vector') else self.typedesc,
                           "yes" if self.multiple else "no")

    # here we use property with a decorator, in this way we mask a method as
    # a class attribute
    @property
    def __doc__(self):
        """Return the docstring of the parameter

        {name}: {default}{required}{multi}{ptype}
            {description}{values}"","""
        if hasattr(self, 'values'):
            if self.isrange:
                vals = self.isrange
            else:
                vals = ', '.join([repr(val) for val in self.values])
        else:
            vals = False
        keydescvals = "\n    (%s)" % ', '.join(self.keydescvalues)
        return DOC['param'].format(name=self.name,
                default=repr(self.default) + ', ' if self.default else '',
                required='required, ' if self.required else 'optional, ',
                multi='multi' if self.multiple else '',
                ptype=self.typedesc, description=self.description,
                values='\n    Values: {0}'.format(vals)  if vals else '',
                keydescvalues= keydescvals if self.keydescvalues else '')
