import numpy as np
import numpy.fft as npft

# TODO: license
# TODO: normalize function call names
# TODO: document functions

def create_basis_IPSP(neye,ncos,kpeaks,ks,DTsim,t0,I_stim,nkt,flag_exp,npcut):
    
    kbasprs = {}
    kbasprs['neye'] = neye #No of 'identity' basis vectors near time of spike
    kbasprs['ncos'] = ncos #No of raised-cosines to use
    kbasprs['kpeaks'] = kpeaks  #Position of first and last bump
    kbasprs['b'] = 0.1 #Offset for non-linear scaling
    kbasprs['ks'] = ks
        
    gg0 = makeFitStruct_GLM(DTsim,kbasprs,nkt,flag_exp)
    
    #Create spike-stim with which to convolve post spike filter
    spike_stim = np.zeros(np.shape(I_stim))
    for kk in range(len(t0)):
        spind = int(t0[kk])
        #print int(t0[kk]), spind-190000
        spike_stim[spind]=1.0
    
    ##Convolve temporal basis functions with spike-stim
    c = np.zeros((len(spike_stim),ncos))
    for jj in range(ncos):
        basisfilt = gg0['ktbas'][:,jj]
        bconv = np.convolve(spike_stim,np.flipud(basisfilt),'full')
        c[:,jj] = bconv[range(len(spike_stim))]        
    
    basis_IPSP = c;
    
    return basis_IPSP, gg0

def makeFitStruct_GLM(dtsim,kbasprs,nkt,flag_exp):
    
    gg = {}
    gg['k'] = []
    gg['dc'] = 0
    gg['kt'] = np.zeros((nkt,1))
    gg['ktbas'] = []
    gg['kbasprs'] = kbasprs
    gg['dt'] = dtsim
    
    nkt = nkt
    if flag_exp==0:    
        ktbas = makeBasis_StimKernel(kbasprs,nkt)
    else:
        ktbas = makeBasis_StimKernel_exp(kbasprs,nkt)
    
    gg['ktbas'] = ktbas
    gg['k'] = gg['ktbas']*gg['kt']
    
    return gg

def makeBasis_StimKernel(kbasprs,nkt):
    
    neye = kbasprs['neye']
    ncos = kbasprs['ncos']
    kpeaks = kbasprs['kpeaks']
    kdt = 1
    b = kbasprs['b']
    
    yrnge = nlin(kpeaks + b*np.ones(np.shape(kpeaks)))
    #db = np.diff(yrnge)/(ncos-1)
    db = (yrnge[-1]-yrnge[0])/(ncos-1)
    ctrs = yrnge
    mxt = invnl(yrnge[ncos-1]+2*db)-b
    print mxt
    kt0 = np.arange(0,mxt,kdt)    
    nt = len(kt0)
    e1 = np.tile(nlin(kt0+b*np.ones(np.shape(kt0))),(ncos,1))
    e2 = np.transpose(e1)    
    e3 = np.tile(ctrs,(nt,1))
    kbasis0 = []
    for kk in range(ncos):    
        kbasis0.append(ff(e2[:,kk],e3[:,kk],db))
         
    
    #Concatenate identity vectors
    nkt0 = np.size(kt0,0)
    a1 = np.concatenate((np.eye(neye), np.zeros((nkt0,neye))),axis=0)
    a2 = np.concatenate((np.zeros((neye,ncos)),np.array(kbasis0).T),axis=0)
    kbasis = np.concatenate((a1,a2),axis=1)
    kbasis = np.flipud(kbasis)
    nkt0 = np.size(kbasis,0)
    
    if nkt0 < nkt:
        kbasis = np.concatenate((np.zeros((nkt-nkt0,ncos+neye)),kbasis),axis=0)
    elif nkt0 > nkt:
        kbasis = kbasis[-1-nkt:-1,:] 

    kbasis = normalizecols(kbasis)

    return kbasis    


def makeBasis_StimKernel_exp(kbasprs,nkt):
    ks = kbasprs['ks']
    b = kbasprs['b']
    x0 = np.arange(0,nkt)
    kbasis = np.zeros((nkt,len(ks)))
    for ii in range(len(ks)):
        kbasis[:,ii] = invnl(-ks[ii]*x0) #(1.0/ks[ii])*
    
    kbasis = np.flipud(kbasis)     
    return kbasis  
    
def nlin(x):
    eps = 1e-20
    return np.log(x+eps)
    
def invnl(x):
    eps = 1e-20
    return np.exp(x)-eps
    
def ff(x,c,dc):
    rowsize = np.size(x,0)
    m = []
    for i in range(rowsize): 
        xi = x[i]
        ci = c[i]
        val=(np.cos(np.max([-pi,np.min([pi,(xi-ci)*pi/dc/2])]))+1)/2    
        m.append(val)
        
    return np.array(m)
    
def normalizecols(A):
    
    B = A/np.tile(np.sqrt(sum(A**2,0)),(np.size(A,0),1))
    
    return B
    
def sameconv(A,B):
    
    am = np.size(A)
    bm = np.size(B)
    nn = am+bm-1
    
    q = npft.fft(A,nn)*npft.fft(np.flipud(B),nn)
    p = q
    G = npft.ifft(p)
    G = G[range(am)]
    
    return G

