import json
import os
import paho.mqtt.client as mqtt
import sqlite3
import subprocess
import time

# db initial
DbPath = "/tmp/.db"
conn = sqlite3.connect(DbPath+"/chain.db")
c = conn.cursor()
c.execute("create table if not exists keystore(peerID text, Kname text,Khash text, PRIMARY KEY(peerID,Kname))")
conn.commit()

# Load Node set of chain
def GetChainNodeSet():
    Jobject = ""
    ChainNodeSet = set()
    f = open("/tmp/Ohash","r")
    while True:
        line = f.readline()
        if not line:
            break
        cmd = "timeout 10 ipfs object get "+line
        Jobject = json.loads(subprocess.check_output(cmd, shell=True))
        for x in Jobject['Links']:
            if "node-" in x['Name']:
                ChainNodeSet.add(x['Name'].split("###")[1])
        return ChainNodeSet
    return "ERROR"

def Publish(target, channel, message):
	client = mqtt.Client()
	client.max_inflight_messages_set(200000)
        client.connect(target, 1883)
        client.loop_start()
        msg_info = client.publish(channel, message, qos=1)
        if msg_info.is_published() == False:
        	msg_info.wait_for_publish()
	client.disconnect()

def LoadDescription():
    Ddict = dict()
    f = open('/tmp/description.conf','r')
    while True:
        line = f.readline()
        if not line:
                break
        tmp = line.split("=")
        try:
                for i in range(len(tmp)):
                        if tmp[0] == "description":
                                tmp[i] = tmp[i].replace("\n","")
                                continue
                        tmp[i] = tmp[i].replace(" ","")
                        tmp[i] = tmp[i].replace("\n","")
                        tmp[i] = tmp[i].replace("\t","")
                tmp[0] = tmp[0].lower()
                Ddict[tmp[0]] = tmp[1]
        except:
                continue
    return Ddict

def GetKhash():
        Ddict = LoadDescription()
        cmd = "timeout 300 ipfs add -r createChain/"+Ddict['chainname']+"/keystore"
        Klist = subprocess.check_output(cmd, shell=True).split("\n")
	for x in Klist:
		try:
			tmp = x.split(" ")
			if tmp[2] == "keystore":
				return tmp[1]
		except:
			pass
	return "ERROR"

def GetDbHash():
	cmd = "timeout 300 ipfs add -r "+DbPath
	DbDict = dict()
        while True:
                try:
                        Dblist = subprocess.check_output(cmd, shell=True).split("\n")
                        break
                except:
                        pass
	for x in Dblist:
		try:
			tmp = x.split(" ")
			if tmp[2].split("/")[1][:8] == "chain.db": # need not to backup
				continue
			DbDict[tmp[2].split("/")[1]] = tmp[1]	# Dbname, Dbhash
		except:
			pass
	return DbDict

def GetPeerID():
	cmd = "timeout 10 ipfs id -f='<id>'"
	peerID = subprocess.check_output(cmd, shell=True)
	return peerID

def CheckKhash(peerID):
	global c
	Khash = c.execute("select Khash from keystore where peerID = '"+peerID+"' and Kname = 'keystore'")
	for x in Khash:
		return x[0]
	return "ERROR"

# Check createChain
while True:
    Flist = os.listdir("/tmp")
    if "createChain" in Flist:
        break
    else:
        print "waiting for createChain"
    time.sleep(1)

peerID = GetPeerID()
OldKhash = "TaiwanNumberOne"
OldDbDict = dict()

c.execute("delete from keystore")
conn.commit()

while True:
	# Update Keystore hash
	NewKhash = GetKhash()
	if OldKhash != NewKhash:
		c.execute("INSERT OR REPLACE INTO keystore values('"+peerID+"','keystore','"+NewKhash+"')")
		conn.commit()
                CNset = GetChainNodeSet()
                for x in CNset:
                    Publish(x,"KeyStore",peerID+"###keystore###"+NewKhash)
		OldKhash = NewKhash

	# Update Db hash
	NewDbDict = GetDbHash()
	for x in NewDbDict:
		if x not in OldDbDict:	# insert new db hash
			c.execute("INSERT OR REPLACE INTO keystore values('"+peerID+"','"+x+"','"+NewDbDict[x]+"')")
			conn.commit()
			CNset = GetChainNodeSet()
			for y in CNset:
				Publish(y,"KeyStore",peerID+"###"+x+"###"+NewDbDict[x])
		elif NewDbDict[x] != OldDbDict[x]:	# update db hash
			c.execute("INSERT OR REPLACE INTO keystore values('"+peerID+"','"+x+"','"+NewDbDict[x]+"')")
			conn.commit()
			CNset = GetChainNodeSet()
			for y in CNset:
				Publish(y,"KeyStore",peerID+"###"+x+"###"+NewDbDict[x])
	for x in OldDbDict: # delete old db hash
		if x not in NewDbDict:
			c.execute("INSERT OR REPLACE INTO keystore values('"+peerID+"','"+x+"','NoUse')")
			conn.commit()
			CNset = GetChainNodeSet()
			for y in CNset:
				Publish(y,"KeyStore",peerID+"###"+x+"###NoUse")
	OldDbDict = NewDbDict

	# delete nouse db
        if int(time.time()) % 60 == 0:
	    c.execute("delete from keystore where khash = 'NoUse'")
	    conn.commit()

	time.sleep(1)