"""
Convert numbers from base 10 integers to base X strings and back again.

Original: http://www.djangosnippets.org/snippets/1431/

Sample usage:

>>> converter = the_converter
>>> converter.encode('1234')
'DvY'
>>> converter.decode('DvY')
'1234'

Tests:
>>> converter.decode(converter.encode('1234')) == '1234'
True
>>> converter.decode(converter.encode('1234A')) == '1234A'
True
>>> converter.decode(converter.encode('1234A-')) == '1234A-'
True
>>> converter.decode(converter.encode('1234A-')) == '1234A'
False
"""

import time
import string
import datetime


class BaseConverter(object):
    letter_set = set(string.letters)

    decimal_digits = "0123456789"
    base62_digits = "0123456789abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    base63_digits = "0123456789abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ-"
    decimal_char = "D"
    base62_char = "2"
    base63_char = "3"
    char_map = {
        decimal_char: decimal_digits,
        base62_char: base62_digits,
        base63_char: base63_digits,
    }

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

    def __get_base_digits(self, value):
        if "-" in value:
            return self.base63_digits, self.base63_char

        elif self.letter_set.intersection(value):
            return self.base62_digits, self.base62_char

        else:
            return self.decimal_digits, self.decimal_char

    def encode(self, i):
        decimal_digits, b_char = self.__get_base_digits(i)
        results = self.convert(i, decimal_digits, self.digits)
        return "%s%s" % (b_char, results)

    def one_way_encode(self, i):
        """
        One way encode, not possible to decode. using base62 digits no -
        """
        return self.convert(i, self.base62_digits, self.digits)

    def decode(self, s):
        # strip out the first base_char.
        return self.convert(s[1 : len(s)], self.digits, self.char_map[s[0]])

    def convert(number, fromdigits, todigits):
        # Based on http://code.activestate.com/recipes/111286/
        if str(number)[0] == "-":
            number = str(number)[1:]
            neg = 1
        else:
            neg = 0

        # make an integer out of the number
        x = 0
        for digit in str(number):
            x = x * len(fromdigits) + fromdigits.index(digit)

        # create the result in base 'len(todigits)'
        if x == 0:
            res = todigits[0]
        else:
            res = ""
            while x > 0:
                digit = x % len(todigits)
                res = todigits[digit] + res
                x = int(x / len(todigits))
            if neg:
                res = "-" + res
        return res

    convert = staticmethod(convert)


pbp_converter = BaseConverter(
    "012345abcdefghijklmnopqrstuvwxyz67" "ABCDEFGHIJKLMNOPQRSTUVWXYZ89"
)


def temp_code(now=None):
    """We need a unique temp code, so we get a timestamp to the
       microsecond and that should be good enough
    """
    if not now:
        now = datetime.datetime.now()
    return "%s%s" % (int(time.mktime(now.timetuple())), now.microsecond)
