# -*- coding: utf-8 -*-
"""
Created on Fri May 21 12:42:11 2021

@author: sansin
"""

from Encoder import Encoder
from FDecoder import FDecoder
from BDecoder import BDecoder
from Decoder import Decoder
from SymbolMapper import SymbolMapper
import random
import math
from Stati import Stati
# some constants:
import numpy as np
import pylab as pl
import scipy.stats as st
from Rate import Rate

Mi=4723
Ma=7229
k = 8
c = 10

precision = 10
B = 16
b = 2
d = 2

Ta=1
Ti=1
F= 28

#SNR=range(2,20,3)
SNR=range(1,12)
# Message to be encoded:
print SNR
message = "hello world!Univ"


if __name__ == '__main__':
    cpl=[]
    cplf=[]
    
    rate=[]
    ratef=[]
    rateb=[]
    sino=[]

    for snr in SNR :
        f=0
        M= Mi
        T = Ti
        snrr=10**(float(snr)/float(10))
        sino.append(0.5*np.log2(snrr+1))
        spinal_complex=0.0#decoder.get_sum()
        ls=0
        for p in range(1,10):
            #
            mapper = SymbolMapper(c, precision)
            map_func = lambda value: mapper.map(value)
            
            #Instantiate an encoder
            #print '\tMessage: "%s"' % message
           # print 'Message hex:', message.encode("hex")
            encoder = Encoder(k, map_func, message)
            
            # spine length
            n = 8 * len(message) 
            
            spine_length = (n + (k - 1)) / k
            
            # encode a short message, making 3 passes
            #print "Producing  passes." 
            symbols = [encoder.get_symbol(i) for i in range(spine_length)*p]
            #print "symbols: ", symbols
            
            # make sure we got the expected result
         #   assert(expected_encoder_output == symbols)
            
            # get average signal power
            signal_power = mapper.get_signal_average_power()
            
            # what is the noise power and standard deviation when SNR is 10dB?
            noise_power = signal_power / snr
            noise_std_dev = math.sqrt(noise_power)
            
            # initialize random number generator. this seed is fixed constant in order
            # to get deterministic results in this example.
            random.seed(314159265359)
            
            # add white gaussian noise at 10dB to signal
            #print "Adding white gaussian noise at 10dB."
            noisy_symbols = [sym + random.gauss(0, noise_std_dev) for sym in symbols]
            # round to closest integer
            noisy_symbols = [int(x + 0.5) for x in noisy_symbols]
            #print "noisy symbols:", noisy_symbols
            
            # instantiate decoder
            decoder = Decoder(k, B, d,b,T,M,p,map_func,spine_length)
            
            # update decoder with gathered points
            
            
            decoder.advance(noisy_symbols)
            de_m=decoder.get_most_likely()
            spinal_complex+=decoder.get_sum()
            ls+=p
            #print '\tdecoded: "%s"'%de_m#.encode("hex")
            #print '\tdecode_complex: "%s"'%spinal_complex#.encode("hex")
            # make sure we got the message we started with
            if de_m == message:
                print "SNR=",snr
                print '\tMessage: "%s"' % message
                print '\tdecoded: "%s"'%de_m#.encode("hex")
                
               
                print '\tBBD_complex: "%s"'%spinal_complex#.encode("hex")
                cpl.append(spinal_complex)
                #rate.append(float(k)/float(p))                
                #cpl.append(spinal_complex)
                #print "\t\tSuccess!\n\t\tl=",p,
                print "\trate=",float(k)/float(ls)
                print "\t\tSuccess!"
                f=1                
                break
            else:
                if F==(F+spine_length-1)/spine_length:
                    if decoder.para>=0:
                        T=Ti
                        M=Mi
                    else:
                        T=Ta
                        M=Ma
#        if f==0:
#            if len(cpl)>0:
#                cpl.append(cpl[-1])
#            else:
#                cpl.append(p)
    for snr in SNR :
        f=0
        M =Ma
        ls=0
        spinal_complex=0.0#decoder.get_sum()
        for p in range(1,10):
            #print "SNR=",snr
            mapper = SymbolMapper(c, precision)
            map_func = lambda value: mapper.map(value)
            
            #Instantiate an encoder
          
           # print 'Message hex:', message.encode("hex")
            encoder = Encoder(k, map_func, message)
            
            # spine length
            n = 8 * len(message) 
            
            spine_length = (n + (k - 1)) / k
            
            # encode a short message, making 3 passes
            #print "Producing  passes." 
            symbols = [encoder.get_symbol(i) for i in range(spine_length)*p]
            #print "symbols: ", symbols
            
            # make sure we got the expected result
         #   assert(expected_encoder_output == symbols)
            
            # get average signal power
            signal_power = mapper.get_signal_average_power()
            
            # what is the noise power and standard deviation when SNR is 10dB?
            noise_power = signal_power / snr
            noise_std_dev = math.sqrt(noise_power)
            
            # initialize random number generator. this seed is fixed constant in order
            # to get deterministic results in this example.
            random.seed(314159265359)
            
            # add white gaussian noise at 10dB to signal
            #print "Adding white gaussian noise at 10dB."
            noisy_symbols = [sym + random.gauss(0, noise_std_dev) for sym in symbols]
            # round to closest integer
            noisy_symbols = [int(x + 0.5) for x in noisy_symbols]
            #print "noisy symbols:", noisy_symbols
            
            # instantiate decoder
            decoder = FDecoder(k, B, d,b ,M,p,map_func,spine_length)
            
            # update decoder with gathered points
            
            
            decoder.advance(noisy_symbols)
            de_m=decoder.get_most_likely()
            spinal_complex+=decoder.get_sum()
            ls+=p
            # make sure we got the message we started with
            if de_m == message:
                spinal_complex=decoder.get_sum()
                cplf.append(spinal_complex)
                print "SNR=",snr
                print '\tMessage: "%s"' % message
                print '\tdecoded: "%s"'%de_m#.encode("hex")
                print '\tFSD_complex: "%s"'%spinal_complex#.encode("hex")
                print "\trate=",float(k)/float(ls)
                print "\t\tSuccess!"
                f=1
                break
#        if f==0:
#            if len(cplf)>0:
#                cplf.append(cplf[-1])
#            else:
#                cplf.append(p)
          
    print SNR
    #print cpl
#    cpl.pop(0)
#    cplf.pop(0)
    cplc=Stati(SNR,cpl,cplf)
    
    #sinoc=Rate(SNR,sino)
    cplc.simula()
   
    #sinoc.rates()
