#script to generate a small-world graph, where the graph is implemented by a dict()

import numpy
import os
import shutil
import time

#generate social graph of acquaintances

print "enter size for the graph"
size=input()

#make a new directory to place all the generated files
dirname = "Network"+str(size) 
if (not(os.path.exists(dirname))):
    os.mkdir(dirname)

#copy all necessary files (unchanged) to the target directory
#complicated way to scan a directory... lists all file names in 'filelist'
(r,dirs,filelist)=os.walk('.\\network_files').next()
for item in filelist:
	fname = '.\\network_files\\'+item
	shutil.copy(fname, '.\\'+ dirname+'\\')

#generate social graph
G= dict()

G[0] = []
for i in range(1,size):
    #random decision for the parameters of the new nodes : how many existing nodes it contacts
    rrr = numpy.random.random()
    rr1=1 #1 primary contact
    if (rrr<0.05) and (len(G.keys()) >1): rr1 = 2 #or 2
    rr2 = numpy.random.poisson(1.6) #some secondary contacts
    available = list(G.keys())
    contact1 = numpy.random.randint(0,len(available)) #available is integers from 0 to i-1
    available.remove(contact1)
    G[i] = [contact1] #insert node i, connect to contact1
    G[contact1].append(i) #connect contact1 to i
    if (rr1==2):
        contact2 = available[numpy.random.randint(0,len(available))]
        G[i].append(contact2) #connect
        G[contact2].append(i)
    #print rr1," primary contact(s) added"
    #secondary contacts
    available = list(G[contact1]) #re-define available
    if (rr1==2): available = available.extend(G[contact2])
    if (available != None):
        setav = list(set(available)) #remove duplicates
        if(i in setav) : setav.remove(i)
        if(contact1 in setav) : setav.remove(contact1)
        if (rr1==2):
            if (contact2 in setav) : setav.remove(contact2)
        #print "available for secondary contacts :", setav
        num=0
        for j in range(1, rr2): # the number of secondary contacts
            #we now have only available nodes for secondary contact: maybe there are none left
            if (len(setav)==0): break
            contactj = numpy.random.randint(0,len(setav))
            G[i].append(setav[contactj]) #connect
            G[setav[contactj]].append(i)
            setav.remove(setav[contactj])
            num=j
        #print num," secondary contacts added"

    
print "Social acquaintances graph for the P2P network; acquaintances of each peer:"
for k in range(size):
    print k, ": ",G[k]
    
#output an adjacency matrix to a file
fifi = open(dirname+"/socialgraph"+str(size)+".txt", "w")
fifi.write(str(size))

for i in range(size):
    fifi.write("\n")
    for j in range(size):
        if j in G[i]:
            fifi.write("1 "),
        else:
            fifi.write("0 "),
        
fifi.close()

#===============================================
#generating demux.h :
demux = open(dirname+"/demux.h", "w")
ftop = open("demux_h_1.txt", "r")
fbottom = open("demux_h_2.txt", "r")
"// output ports to the different peers -- generated by script"
for line in ftop:
    demux.write(line)
for k in range(size): #size is the number of nodes-1 (they go 0 to size)
    demux.write("\tPort &out_"+str(k)+" ;\n")
    demux.write("\tPort &out_c"+str(k)+" ;\n")
for line in fbottom:
    demux.write(line)
demux.close()
ftop.close()
fbottom.close()

#generating demux.cpp :

demux = open(dirname+"/demux.cpp", "w")
f1 = open("demux_cpp_1.txt", "r")
f2 = open("demux_cpp_2.txt", "r")
f3 = open("demux_cpp_3.txt", "r")
f4 = open("demux_cpp_4.txt", "r")

"// output ports to the different peers -- generated by script"
for line in f1:
    demux.write(line)
    
for k in range(size): #size is the number of nodes (they go 0 to size-1)
    demux.write(", out_"+str(k)+"( addOutputPort( \"out_"+str(k)+"\" ) )\n")
    demux.write(", out_c"+str(k)+"( addOutputPort( \"out_c"+str(k)+"\" ) )\n")

for line in f2:
    demux.write(line)

for k in range(size): 
    demux.write("\t\t\tcase "+str(k)+":\n\t\t\t\t sendOutput( msg.time(), out_"+str(k)+", nextOutput);\n\t\t\t\tbreak;\n")

for line in f3:
    demux.write(line)

for k in range(size):
    demux.write("\t\t\tcase "+str(k)+":\n\t\t\t\t sendOutput( msg.time(), out_c"+str(k)+", nextOutput);\n\t\t\t\tbreak;\n")

for line in f4:
    demux.write(line)

demux.close()
f1.close()
f2.close()
f3.close()
f4.close()

#generating friends/k/.dat
for k in range(size):
    friendsfile = open(dirname+"/friends"+str(k)+".dat", "w")
    friendsfile.write( str(len(G[k]))+"\n")
    for j in G[k]:
        friendsfile.write(str(j))
        friendsfile.write(" ")
    friendsfile.close()

#generating qs/k/.dat
#a random sequence of queries, number of queries follows poisson distribution of mean 6, queries uniformly taken from [0,9]
#note that queries may be repeated.
#update 23.10.2010 : the sequence of queries by each peer is repeated. This will give more chances for publishes to occur and for files to actually propagate
for k in range(size):
    qfile = open(dirname+"/qs"+str(k)+".dat", "w")
    rrr = b= numpy.random.randint(0,10,numpy.random.poisson(6)) 
    queries = list(rrr) # to list 
    qfile.write( str(len(queries)*2)+"\n")
    for j in queries:
        qfile.write(str(j))
        qfile.write(" ")
    for j in queries:
        qfile.write(str(j))
        qfile.write(" ")

    qfile.close()

#generating docs/k/.dat
#docs will be initially distributed between the peers
#so that each document is only stored by 1 or 2 peers.
DocDistrib = dict()
for d in range(10,20): #there are 10 docs numbered 10 to 19
    #they are stored by one or two of the peers (num of peers = size)
    nodes = list(numpy.random.randint(0,size,numpy.random.randint(1,3)))
    for nn in nodes:
        if (not (DocDistrib.has_key(nn))):
            DocDistrib[nn] = [d]
        else:
            DocDistrib[nn].append(d) #for each node storing the document, add the doc to its list of stored docs

#output the distribution to docs/k/.dat files.
for k in range(size):
    docfile = open(dirname+"/docs"+str(k)+".dat", "w")
    if DocDistrib.has_key(k):
        docfile.write( str(len(DocDistrib[k]))+"\n")
        for j in DocDistrib[k]:
            docfile.write(str(j))
            docfile.write(" ")
    else :
        docfile.write( "0\n") #no docs for you!
    docfile.close()

#generating P2Pnet_size_.MA
MAFile = open(dirname+"/P2PNet_"+str(size)+".MA", "w")
#load a piece of the MA file from a separate file
partfile = open("EachPeer_script.txt", "r")
eachpeerspec = ""
for line in partfile:
    eachpeerspec=eachpeerspec+line
partfile.close()
#load another piece
netspec =""
partfile = open("NetworkSpec_script.txt","r")
for line in partfile:
    netspec=netspec+line
partfile.close()

#list of parts making up the final MA file, with number of times each is repeated
parts = [(1,"[top]\ncomponents : Network"),
         (size," Peer{num}") ,
         (1,"\n"),
         (size, "Link : online@Peer{num} peer_online@Network\n"),
         (size, "Link : offline@Peer{num} peer_offline@Network\n"),
         (size, "Link : out_connect@Peer{num} peer_connect@Network\n"),
         (size, "Link : out_disconnect@Peer{num} peer_disconnect@Network\n"),
         (size, "Link : query@Peer{num} query@Network\n"),
         (size, "Link : publish@Peer{num} publish@Network\n"),
         (size, "Link : remove@Peer{num} remove@Network\n"),
         (size, "Link : out_{num}@Network queryhit@Peer{num}\n"),
         (size, "Link : out_c{num}@Network in_connect@Peer{num}\n"),
         (size, eachpeerspec), #read from file because this part is big
         (1, "\n[Network]\n components : db@Database demux@Demux disp@Dispatcher gnut@Gnutella netwk@LTSNetwork\n"),
         (size, "out : out_{num}\n"),
         (size, "out : out_c{num}\n"),
         (1, netspec),
         (1, "\n"),
         (size, "Link : out_{num}@demux out_{num}\n"),
         (size, "Link : out_c{num}@demux out_c{num}\n"),
         (1, "\n[db]\ndatafile : querydoc.dat \n")]

for part in parts:
    for j in range(part[0]): #the first element is a number indicating how many times the second is repeated
        MAFile.write(part[1].format(num=str(j))) #write other element replacing the {num} with the appropriate integer

MAFile.close()

#===============================================
#generating the testing file :
testingfile = open(dirname+"/P2PTest.bat", "w")

line1 = "cd \\eclipse\\workspace\\p2p\\coupled\\Network"+str(size)+"\\\n"
line2 = 'simu.exe -m"P2PNet_'+str(size)+'.MA" -l"P2P'+str(size)+'LOG.log" -w9-9 \n'

testingfile.write(line1)
testingfile.write(line2)
testingfile.write("rem\n pause\n")
testingfile.close()

print "All files generated for a network size =", size
time.sleep(5)
