"""
Hellfire Chain
"""
#############################PyNN Initialisation############################################
from pyNN.utility import get_script_args
from pyNN.hardware.stage1 import *                 #Uncomment this line for Spiky Chip
import numpy
#from pyNN.nest import *                             #Uncomment this line for Nest

#This line sets up the simulation, and also resets hardware if it is used, and turns off
#the scope
setup(timestep=0.1,min_delay=0.1,max_delay=4.0,useScope=False,assertSilence=True, calibVthresh=False)

#Length of Simulation in milliseconds (ms)
Duration = 10000. # 1s

##############################INFORMATION###################################################
#Excitatory weights range from 0.0003 to 0.005                                             # 
#Inhibitory weights range from 0.001 to 0.015                                              # 
#delay is ignored by hardware, but 0.1 is a good reference for next                        #
############################################################################################

##############################Topography Control Variables##################################
#Currently 12 layers deep, 12 wide excitatory, 4 wide inhibitory
#Each inhibitory inhibits 1/4 of the chain
ChainLength = 5
ExciteWidthE = 7
InhibiWidthE = 7
ExciteWidthI = 7
InhibiWidthI = 7

##############################Configure Neurons#############################################
NeuronParams =   {  'v_thresh'      : -55.2, #-55 to -80
                    'v_rest'        : -60.0, #-55 to -80
                    'tau_syn_E'     :   5.0,
                    'tau_syn_I'     :   5.0,
                    'v_reset'       : -65.0, #-55 to -80
                    'g_leak'        :  20.0,
                    'e_rev_I'       : -80.0}


##############################Instantiation#################################################
#Create Cells
Chain_ExciteE      = create(IF_facets_hardware1, NeuronParams, n = ExciteWidthE*ChainLength )
Chain_InhibiE      = create(IF_facets_hardware1, NeuronParams, n = InhibiWidthE*ChainLength )
Chain_ExciteI      = create(IF_facets_hardware1, NeuronParams, n = ExciteWidthI*ChainLength )
Chain_InhibiI      = create(IF_facets_hardware1, NeuronParams, n = InhibiWidthI*ChainLength )

#Noise sources
ExciteSynapticInput = create(SpikeSourceArray, {'spike_times': numpy.arange(50., 53.1, 0.6)}, ExciteWidthE)
InhibSynapticInput =  create(SpikeSourceArray, {'spike_times': numpy.arange(0.,200., 5.3)}, ExciteWidthI)

#############################Excitatory Connections#########################################
#Connect the excitatory layers to the next layer and to the inhibitory layer
for n in range(0,ChainLength,1):
    # E: e-e
    for p in range((n*ExciteWidthE),((n+1)*ExciteWidthE),1):
        for q in range((n*ExciteWidthE),((n+1)*ExciteWidthE),1):
            if p!=q: # avoid self-connections
                connect(Chain_ExciteE[p], Chain_ExciteE[q], weight = 0.003333, synapse_type='excitatory')
    # E: e-i
    for p in range((n*ExciteWidthE),((n+1)*ExciteWidthE),1):
        for q in range((n*InhibiWidthE),((n+1)*InhibiWidthE),1):
            connect(Chain_ExciteE[p], Chain_InhibiE[q], weight = 0.001, synapse_type='excitatory')

    # E: i-e
    for p in range((n*InhibiWidthE),((n+1)*InhibiWidthE),1):
        for q in range((n*ExciteWidthE),((n+1)*ExciteWidthE),1):
            connect(Chain_InhibiE[p], Chain_ExciteE[q], weight = 0.001, synapse_type='inhibitory')

    # I: e-e
    for p in range((n*ExciteWidthI),((n+1)*ExciteWidthI),1):
        for q in range((n*ExciteWidthI),((n+1)*ExciteWidthI),1):
            if p!=q: # avoid self-connections
                connect(Chain_ExciteI[p], Chain_ExciteI[q], weight = 0.002, synapse_type='excitatory')
    # I: e-i
    for p in range((n*ExciteWidthI),((n+1)*ExciteWidthI),1):
        for q in range((n*InhibiWidthI),((n+1)*InhibiWidthI),1):
            connect(Chain_ExciteI[p], Chain_InhibiI[q], weight = 0.005, synapse_type='excitatory')

    # I: i-e
    for p in range((n*InhibiWidthI),((n+1)*InhibiWidthI),1):
        for q in range((n*ExciteWidthI),((n+1)*ExciteWidthI),1):
            connect(Chain_InhibiI[p], Chain_ExciteI[q], weight = 0.000333, synapse_type='inhibitory')

    # forward excitation
    k = (n+1)%ChainLength
    if True:#k!=0: 
        #print "connecting",n,k
        connect(Chain_ExciteE[(n*ExciteWidthE):((n+1)*ExciteWidthE)], Chain_ExciteE[(k*ExciteWidthE):((k+1)*ExciteWidthE)], weight = 0.001, synapse_type='excitatory')
        #connect(Chain_ExciteE[(n*ExciteWidthE):((n+1)*ExciteWidthE)], Chain_InhibiE[(k*InhibiWidthE):((k+1)*InhibiWidthE)], weight = 0.000666, synapse_type='excitatory')

    # inhibitory neighbor
    connect(Chain_ExciteE[(n*ExciteWidthE):((n+1)*ExciteWidthE)], Chain_ExciteI[(n*ExciteWidthI):((n+1)*ExciteWidthI)], weight = 0.001, synapse_type='excitatory')
    connect(Chain_ExciteE[(n*ExciteWidthE):((n+1)*ExciteWidthE)], Chain_InhibiI[(n*InhibiWidthI):((n+1)*InhibiWidthI)], weight = 0.001, synapse_type='excitatory')

############################# Blocking Inhibitory Connections #########################################
for n in range(0,ChainLength,1):
    for m in range(0,ChainLength,1):
        k = (n+1)%ChainLength
        x = (n-1)%ChainLength
        y = (n+2)%ChainLength
        if m==x: # backwards
            connect(Chain_InhibiI[n*InhibiWidthI:(n+1)*InhibiWidthI], Chain_ExciteE[m*ExciteWidthE:(m+1)*ExciteWidthE], weight = 0.015, synapse_type='inhibitory')
            connect(Chain_ExciteI[n*ExciteWidthI:(n+1)*ExciteWidthI], Chain_InhibiE[m*InhibiWidthE:(m+1)*InhibiWidthE], weight = 0.005, synapse_type='excitatory')

        if m==y: # 2 forward
            connect(Chain_InhibiI[n*InhibiWidthI:(n+1)*InhibiWidthI], Chain_ExciteE[m*ExciteWidthE:(m+1)*ExciteWidthE], weight = 0.015, synapse_type='inhibitory')
            connect(Chain_ExciteI[n*ExciteWidthI:(n+1)*ExciteWidthI], Chain_InhibiE[m*InhibiWidthE:(m+1)*InhibiWidthE], weight = 0.005, synapse_type='excitatory')

        k = (m-2)%ChainLength
        if n==k:
            #print "connecting",n,m
            connect(Chain_InhibiI[n*InhibiWidthI:(n+1)*InhibiWidthI], Chain_ExciteI[k*ExciteWidthI:(k+1)*ExciteWidthI], weight = 0.015, synapse_type='inhibitory')
            connect(Chain_ExciteI[n*ExciteWidthI:(n+1)*ExciteWidthI], Chain_InhibiI[k*InhibiWidthI:(k+1)*InhibiWidthI], weight = 0.005, synapse_type='excitatory')

############################# Input Synaptic Noise ###########################################
#Connect the excitatory noise too the first excitatory cell layer
SynToExciteCell = connect(ExciteSynapticInput, Chain_ExciteE[0:ExciteWidthE], weight = 0.005, synapse_type='excitatory')
SynToInhibCell1  = connect(InhibSynapticInput, Chain_ExciteI[(ChainLength-1)*InhibiWidthI:ChainLength*InhibiWidthI], weight = 0.005, synapse_type='excitatory'); 
SynToInhibCell2  = connect(InhibSynapticInput, Chain_InhibiI[(ChainLength-1)*InhibiWidthI:ChainLength*InhibiWidthI], weight = 0.005, synapse_type='excitatory'); 


############################# Setup Output Recording #########################################
#record_v(Chain_InhibiI[1*InhibiWidthI], "") 
#record_v(Chain_ExciteE[5*ExciteWidthE], "membraneE.dat")
#record(Chain_ExciteE[ExciteWidthE*0:ExciteWidthE*1], "Spikes_E0.data")
#record(Chain_ExciteE[ExciteWidthE*1:ExciteWidthE*2], "Spikes_E1.data")
#record(Chain_ExciteE[ExciteWidthE*2:ExciteWidthE*3], "Spikes_E2.data")
#record(Chain_ExciteE[ExciteWidthE*3:ExciteWidthE*4], "Spikes_E3.data")
#record(Chain_ExciteE[ExciteWidthE*4:ExciteWidthE*5], "Spikes_E4.data")
#record(Chain_ExciteE[ExciteWidthE*5:ExciteWidthE*6], "Spikes_E5.data")
#record(Chain_InhibiI[InhibiWidthI*0:InhibiWidthI*1], "Spikes_I0.data")
#record(Chain_InhibiI[InhibiWidthI*1:InhibiWidthI*2], "Spikes_I1.data")
#record(Chain_InhibiI[InhibiWidthI*2:InhibiWidthI*3], "Spikes_I2.data")
#record(Chain_InhibiI[InhibiWidthI*3:InhibiWidthI*4], "Spikes_I3.data")
#record(Chain_InhibiI[InhibiWidthI*3:InhibiWidthI*5], "Spikes_I4.data")
#record(Chain_InhibiI[InhibiWidthI*3:InhibiWidthI*6], "Spikes_I5.data")
record(Chain_ExciteE, "spikesExE.dat")
record(Chain_InhibiE, "spikesInE.dat")
record(Chain_InhibiI, "spikesInI.dat")
record(Chain_ExciteI, "spikesExI.dat")

#run it for a duration
run(Duration)

end()

