#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2014 Kungliga Tekniska Högskolan
# (KTH Royal Institute of Technology, Stockholm, Sweden).
# See LICENSE for licensing information.

import json
import base64
import urllib
import urllib2
import sys

frontendnodes = ["https://127.0.0.1:8080/"]
storagenodes = ["https://127.0.0.1:8081/"]

chainsdir = "../rel/mergedb/chains"
logorderfile = "../rel/mergedb/logorder"

def parselogrow(row):
    return base64.b16decode(row)

def get_logorder():
    f = open(logorderfile, "r")
    return [parselogrow(row.rstrip()) for row in f]

def write_chain(key, value):
    f = open(chainsdir + "/" + base64.b16encode(key), "w")
    f.write(value)
    f.close()

def read_chain(key):
    f = open(chainsdir + "/" + base64.b16encode(key), "r")
    value = f.read()
    f.close()
    return value

def add_to_logorder(key):
    f = open(logorderfile, "a")
    f.write(base64.b16encode(key) + "\n")
    f.close()

def get_new_entries(baseurl):
    try:
        result = urllib2.urlopen(baseurl + "ct/storage/fetchnewentries").read()
        parsed_result = json.loads(result)
        if parsed_result.get(u"result") == u"ok":
            return parsed_result[u"entries"]
        print "ERROR: fetchnewentries", parsed_result
        sys.exit(1)
    except urllib2.HTTPError, e:
        print "ERROR: fetchnewentries", e.read()
        sys.exit(1)

def get_curpos(baseurl):
    try:
        result = urllib2.urlopen(baseurl + "ct/frontend/currentposition").read()
        parsed_result = json.loads(result)
        if parsed_result.get(u"result") == u"ok":
            return parsed_result[u"position"]
        print "ERROR: currentposition", parsed_result
        sys.exit(1)
    except urllib2.HTTPError, e:
        print "ERROR: currentposition", e.read()
        sys.exit(1)

def sendlog(baseurl, submission):
    try:
        result = urllib2.urlopen(baseurl + "ct/frontend/sendlog",
            json.dumps(submission)).read()
        return json.loads(result)
    except urllib2.HTTPError, e:
        print "ERROR: sendlog", e.read()
        sys.exit(1)
    except ValueError, e:
        print "==== FAILED REQUEST ===="
        print submission
        print "======= RESPONSE ======="
        print result
        print "========================"
        raise e

def sendsth(baseurl, submission):
    try:
        result = urllib2.urlopen(baseurl + "ct/frontend/sendsth",
            json.dumps(submission)).read()
        return json.loads(result)
    except urllib2.HTTPError, e:
        print "ERROR: sendsth", e.read()
        sys.exit(1)
    except ValueError, e:
        print "==== FAILED REQUEST ===="
        print submission
        print "======= RESPONSE ======="
        print result
        print "========================"
        raise e

def get_missingentries(baseurl):
    try:
        result = urllib2.urlopen(baseurl + "ct/frontend/missingentries").read()
        parsed_result = json.loads(result)
        if parsed_result.get(u"result") == u"ok":
            return parsed_result[u"entries"]
        print "ERROR: missingentries", parsed_result
        sys.exit(1)
    except urllib2.HTTPError, e:
        print "ERROR: missingentries", e.read()
        sys.exit(1)


logorder = get_logorder()
certsinlog = set(logorder)

new_entries = [entry for storagenode in storagenodes for entry in get_new_entries(storagenode)]

for new_entry in new_entries:
    hash = base64.b64decode(new_entry["hash"])
    entry = base64.b64decode(new_entry["entry"])
    if hash not in certsinlog:
        write_chain(hash, entry)
        add_to_logorder(hash)
        logorder.append(hash)
        certsinlog.add(hash)
        print "added", base64.b16encode(hash)

for frontendnode in frontendnodes:
    curpos = get_curpos(frontendnode)
    entries = [base64.b64encode(entry) for entry in logorder[curpos:]]
    sendlog(frontendnode, {"start": curpos, "hashes": entries})
    missingentries = get_missingentries(frontendnode)
    print "missing entries:", missingentries
    # XXX: no test case for missing entries yet, waiting to implement
    sendsth(frontendnode, {"tree_size": len(logorder)})