# -*- coding: utf-8 -*-

"""
Модуль содержит дополнительные функции для работы с датой и временем.
"""

import os
import re
import time
from datetime import datetime
from datetime import timedelta
__author__ = "Zasimov Alexey"
__email__ = "zasimov-a@yandex-team.ru"

# Регулярное выражение для разбора строки с timedelta.
timedelta_re = re.compile(r'((?P<hours>\d+?)h)?((?P<minutes>\d+?)m)?((?P<seconds>\d+?)s)?')


def tzset(tz):
    """
    Устанавливает временную зону tz.

    @param tz: Человеческое имя зона (например, Europe/Moscow).
    """
    os.environ["TZ"] = tz
    time.tzset()


def with_tz(tz, func, *args):
    """
    Запускает функцию func в окружении с установленной временной зоной tz.

    >>> with_tz("Asia/Nicosia", lambda x: time.timezone, None)
    -7200

    @param tz: Человеческое имя зоны (например, Europe/Moscow).
    @param func: Функция для запуска.
    @param args: Аргументы для функции func.
    """
    tz_from_env = os.environ.get('TZ', None)
    try:
        tzset(tz)
        return func(*args)
    finally:
        # Восстанавливаем предыдущую зону
        if not tz_from_env:
            del os.environ['TZ']
        else:
            os.environ['TZ'] = tz_from_env
        time.tzset()


def delta_to_str(td, format="%H:%M:%S"):
    """
    Принимает на вход дельту td и конвертирует её в строку.

    Формат берется из переменной format, в которой допускается использовать:
        - %H - часы;
        - %M - минуты;
        - %S - секунды;
        - %% - %;
    Эти параметры выбраны для совместимости с L{time.strftime}.

    Пример работы:

    >>> t1 = datetime.today()
    >>> t2 = datetime.today() + timedelta(hours=2, minutes=12, seconds=13)
    >>> d = t2 - t1
    >>> delta_to_str(d)
    '2:12:13'
    >>> delta_to_str(d, "%S:%M:%H")
    '13:12:2'
    >>> delta_to_str(d, "%H%Z%%")
    '2%Z%'
    >>> delta_to_str(d, "%S%")
    '13%'

    @type td: timedelta из модуля datetime
    @param td: Делта.
    @type format: строка формата
    @param format: Формат результата.
    """
    s = "" #: переменная с результатом
    expect = True

    hours = td.seconds // 3600
    minutes = (td.seconds % 3600) // 60
    seconds = (td.seconds % 3600) % 60

    for c in str(format):
        if expect:
            if c == "%":
                expect = False
            else:
                s += c
        else:
            expect = True
            if c == "H":
                s += str(hours)
            elif c == "M":
                s += str(minutes)
            elif c == "S":
                s += str(seconds)
            elif c == "%":
                s += "%"
            else:
                s += "%" + c

    # Не забываем последний %
    if not expect:
        s += "%"

    return s


def _to_unixtime(dt):
    return time.mktime(dt.timetuple())


def to_unixtime(dt, tz=None):
    """
    Преобразует дату dt в U{unixtime <http://ru.wikipedia.org/wiki/UNIX-время>}.

    Пример работы:

    >>> tzset("Europe/Moscow")
    >>> dt = datetime.strptime("07.07.2011 17:53:12", "%d.%m.%Y %H:%M:%S")
    >>> to_unixtime(dt)
    1310046792.0
    >>> to_unixtime(dt, "Europe/London")
    1310057592.0

    @type dt: datetime
    @param dt: Дата и время.
    @type tz: человеческое имя временной зоны
    @param tz: Временная зона, в которой задано время dt. Если время считается
               заданным в системной временной зоне.
    """
    assert isinstance(dt, datetime), "Expected datetime, but received %s" % dt.__class__
    if tz:
        return with_tz(tz, _to_unixtime, dt)
    else:
        return _to_unixtime(dt)


def str_to_timedelta(time_str):
    """
    Преобразует строчку вида XXhXXmXXs в timedelta.

    Пример:

    >>> dt = datetime.strptime("07.07.2011 17:53:12", "%d.%m.%Y %H:%M:%S")
    >>> n = dt - str_to_timedelta("24h2m1s")
    >>> n.strftime("%d.%m.%Y %H:%M:%S")
    '06.07.2011 17:51:11'

    @param time_str: Строчка с timedelta.
    """
    global timedelta_re
    parts = timedelta_re.match(time_str)
    if not parts:
        raise ValueError("Invalid timedelta format: %s" % s)
    parts = parts.groupdict()
    time_params = {}
    for (name, param) in parts.items():
        if param:
            time_params[name] = int(param)
    return timedelta(**time_params)


