# -*- coding: utf-8 -*-
from __future__ import unicode_literals

import re
import collections
import voluptuous as vs


def _validate(validator, value):
    """ Try use validator to validate given value """
    if callable(validator):
        return validator(value)
    elif not validator == value:
        raise vs.Invalid('has unexpected value (%s)' % value)
    return value


def _match(match_re, data):
    """
    Check string content with given for math given regexp.
    Helper for preventing mistakes like checking only part of string
    """
    match = re.match(r'^%s$' % match_re, data)
    if match is None:
        raise vs.Invalid('does not match %s' % match_re)
    return True


def ArgSet(validator):
    """ Data can be represented as set of given types """

    def is_set_of(data):
        if isinstance(data, (str, unicode)) or not isinstance(data, collections.Iterable):
            data = [data]
        return frozenset(_validate(validator, d) for d in data)
    return is_set_of


def ArgList(validator):
    """ Data can be represented as list of given types """

    def is_list_of(data):
        if isinstance(data, (str, unicode)) or not isinstance(data, collections.Iterable):
            data = [data]
        return [_validate(validator, d) for d in data]
    return is_list_of


def EmptyList(data):
    """ Just empty list. Can be representented as empty string or any other empty iterable """
    if len(data) != 0:
        raise vs.Invalid('not an empty list')
    return []


def EmptySet(data):
    """ Just empty set. Can be representented as empty string or any other empty iterable """
    if len(data) != 0:
        raise vs.Invalid('not an empty set')
    return frozenset()


def Any(*args):
    str_args = [a for a in args if isinstance(a, (str, unicode))]
    if str_args:
        msg = 'not a valid value (expected one of: %s)' % ', '.join(str_args)
    else:
        msg = 'not a valid value'
    return vs.Any(*args, msg=msg)


Optional = vs.Optional


def SimpleString(data):
    """ String with only [A-Za-z0-9_] symbols """
    if not data:
        raise vs.Invalid('is empty')
    _match('[A-Za-z0-9_\-]+', data)
    return data


def Int(data):
    """ Interger """
    try:
        return int(data)
    except Exception:
        raise vs.Invalid('not an integer')


def YandexLogin(data):
    """ String with Yandex login """
    if not data:
        raise vs.Invalid('is empty')
    _match('[A-Za-z0-9_\-.]+', data)
    return data


Partner = SimpleString
