from Crypto.Cipher import AES
import binascii
import re
from urllib import urlencode
import struct

from core import settings
import random,string
    
def _pad(string):
    padding = ""
    padlength = 16 - (len(string) % 16)
    for i in range(1, padlength+1):
        padding += chr(padlength)
    return string + padding
    
def encrypt(send_string, encryption_key):
    
    iv = ''.join(random.sample(('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'),  16))
    aes = AES.new(encryption_key, 2, encryption_key)
    send_string = _pad(send_string)
    enc = aes.encrypt(send_string)
    enc = "@" + binascii.hexlify(enc)
        
    return enc
        
def format_money_value(num):
    return u'{0:.2f}'.format(num)

def encode_basket(basket):
    fields = []
    fields.append(unicode(len(basket)))
    for item in basket:
        fields.extend([
            INVALID_CHARS.sub(' ', unicode(item.get(f, ''))) for f in [
                'description', 'quantity', 'unit_value_net', 'unit_tax',
                'unit_value', 'line_total'
        ]])
    output = u':'.join(fields)
    return output

def encode_transaction_request(data):
    # We're going to mutate this dict so make a copy
    data = data.copy()
    #data['Amount'] = format_money_value(data['Amount'])
    basket = data.pop('Basket', None)
    if basket:
        data['Basket'] = encode_basket(basket)
    for key in data:
        if not isinstance(data[key], basestring):
            data[key] = unicode(data[key])
        data[key] = data[key].encode('utf8')

    return data
    

def get_encrypted_crypt(crypt_contents):

    crypt_contents = encode_transaction_request(crypt_contents)    
    crypt_string = ''
    for key in crypt_contents:
        crypt_string = "%s%s=%s&" % (crypt_string,key,crypt_contents[key])
    crypt_string = crypt_string[:-1]

    encrypted_crypt_string = encrypt(crypt_string,settings.CRYPT_PASSWORD)

    return encrypted_crypt_string

    
def decode_transaction_response(body):

    return dict(line.split('=', 1) for line in body.strip().strip('\x0e').strip('\x03').split("&"))

    
def decrypt(send_string,encryption_key):

    send_string = send_string[1:]
    send_string = binascii.unhexlify(send_string)    
    aes = AES.new(encryption_key,2,encryption_key)
    decoded = aes.decrypt(send_string)

    return decoded
    
def decode_response(response_data):
    
    data = decrypt(response_data,settings.CRYPT_PASSWORD)    
    data = decode_transaction_response(data)

    return data
    