"""Module for the v0 version of the `SPTrans API <http://www.sptrans.com.br/desenvolvedores/APIOlhoVivo/Documentacao.aspx?1>`_.

The first thing you have to do, in order to use it, is to instantiate a client and authenticate to the API:
::

    from sptrans.v0 import Client


    client = Client()
    client.authenticate('this is my token')

Then you can use the other methods to grab data from the API.
"""

from collections import namedtuple
from datetime import date, datetime, time
import json
try:
    from urllib import urlencode
except ImportError:  # pragma: no cover
    from urllib.parse import urlencode

import requests


BASE_URL = 'http://api.olhovivo.sptrans.com.br/v0'


class RequestError(Exception):
    """Raised when the request failes to be accomplished.

    Normally this is due to the client not being authenticated anymore.
    In this case, just authenticate again, and it should be back at work.
    """


class AuthenticationError(Exception):
    """Raised when the authentication fails - for example, with a wrong token -."""


class TupleMapMixin(object):
    MAPPING = {}

    @classmethod
    def from_dict(cls, result_dict):
        kwargs = {}
        for key, value in cls.MAPPING.items():
            if isinstance(value, str):
                kwargs[key] = result_dict[value]
            else:
                kwargs[key] = value.resolve(result_dict)
        return cls(**kwargs)


def build_tuple_class(name, mapping):
    base_classes = (namedtuple(name, mapping.keys()), TupleMapMixin)
    return type(name, base_classes, {'MAPPING': mapping})


def time_string_to_datetime(time_string):
    hour_parts = time_string.split(':')
    hour, minute = [int(part) for part in hour_parts]
    return datetime.combine(date.today(), time(hour=hour, minute=minute))


class TimeField(object):

    def __init__(self, field):
        self.field = field

    def resolve(self, result_dict):