import random as r
# encondings
R = [('a','0000'), ('b','001000'),('c','00101'),('d','10000'),('e','1100'),('f','111000'),('g','001001'),('h','10001'),('i','1001'),('j','1101000000'),('k','1010000'),('l','11101'),('m','110101'),('n','0001'),('o','1011'),('p','111001'),('q','110100001'),('r','11011'),('s','0011'),('t','1111'),('u','10101'),('v','11010001'),('w','1101001'),('x','1010001'),('y','101001'),('z','1101000001'),(' ','01')]

a2b = dict(R)
b2a = dict([ (k,v) for v, k in R])

#monogram frequencies
W = [('a',575),('b',128),('c',263),('d',285),('e',913),('f',173),('g',133),('h',313),('i',599),('j',6),('k',84),('l',335),('m',235),('n',596),('o',689),('p',192),('q',8),('r',508),('s',567),('t',706),('u',334),('v',69),('w',119),('x',73),('y',164),('z',7),(' ',1928)]


'''
returns the maximum lenght (in bits) of the encoding of a single character
'''
def max_enc_length():
	return max([len(x) for _, x in R])

'''
Checks if m is a string formed only by lowercase letters and whitespaces
'''
def correct_message(m):
	for e in m:
		if not ((e >= 'a' and e <= 'z') or e == ' '):
			return False
	return True

'''
Checks if m is a string formed only by 0 and 1
'''
def correct_cypher(m):
	for e in m:
		if not(e == '1' or e == '0'):
			return False
	return True


'''
Encodes the message M
'''
def E(M):
	if not correct_message(M): return 'Message contain ilegal characters'
	x = ''
	for l in M:
		x += a2b[l]
	return x

'''
Decodes the cyphermessage m
'''
def D(M):
	if not correct_cypher(M): return 'cypher contains ilegal characters'
	r = ''
	k = max_enc_length()
	while len(M):
		c = ''
		while not c in b2a:
			if len(c) > k:
				return 'Bad encoded Message!'
			c += M[0]
			M = M[1:]
		r += b2a[c]
	return r

'''
len(X) == len(W) > 1
W is transformed such that each elemnt is between 0.0 and 1.0
'''
def select(X,W):
	s = sum(W)
	W = [w / s for w in W]
	f = r.random() #random between 0 and 1
	acum = 0.0
	for i in range(0, len(X)):
		acum = acum + W[i]
		if f <= acum:
			return X[i]
	return 'Something went wrong'


'''
generates a random message of lenght l
if l=-1 lenght is random
'''
def rand_message(l=-1):
	m = ''
	lv = [x for x,_ in W]
	lw = [x for _,x in W]
	if l == -1:
		l = r.randint(1,500)
	for i in range(l):
		m += select(lv, lw)
	return m

## test
b = False
n = 500
for i in range(n):
	m = rand_message()
#	print (m)
	e = E(m)
	d = D(e)
	if m!=d: 
		print('Something pinch')
		b = True
if not b:
	print('everything ok in %d tests' % n)



