#!/usr/bin/python2

"""
(C) 2016 Jack Lloyd

Botan is released under the Simplified BSD License (see license.txt)
"""

import sys
import datetime
import re

def format_map(m, for_oid = False):
    s = ''
    for k in sorted(m.keys()):
        v = m[k]

        if len(s) > 0:
            s += '      '

        if for_oid:
            s += '{ "%s", OID("%s") },\n' % (k,v)
        else:
            s += '{ "%s", "%s" },\n' % (k,v)

    s = s[:-2] # chomp last two chars

    return s


def format_as_map(oid2str, str2oid):
   return """/*
* OID maps
*
* This file was automatically generated by %s on %s
*
* All manual edits to this file will be lost. Edit the script
* then regenerate this source file.
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/oids.h>
#include <unordered_map>

namespace Botan {

std::unordered_map<std::string, std::string> OIDS::load_oid2str_map()
   {
   return std::unordered_map<std::string,std::string>{
      %s
      };
   }

std::unordered_map<std::string, OID> OIDS::load_str2oid_map()
   {
   return std::unordered_map<std::string,OID>{
      %s
      };
   }

}
""" % (sys.argv[0], datetime.date.today().strftime("%Y-%m-%d"),
       format_map(oid2str), format_map(str2oid, True))


def format_if(m, nm,t=False):
    s = ''
    for k in sorted(m.keys()):
        v = m[k]

        if t:
            s += '   if(%s == "%s") return OID("%s");\n' % (nm,k, v)
        else:
            s += '   if(%s == "%s") return "%s";\n' % (nm,k, v)

    s = s[:-1]

    return s

def format_as_ifs(oid2str, str2oid):
   return """/*
* OID maps
*
* This file was automatically generated by %s on %s
*
* All manual edits to this file will be lost. Edit the script
* then regenerate this source file.
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/oids.h>

namespace Botan {

namespace OIDS {

std::string lookup(const OID& oid)
   {
   const std::string oid_str = oid.as_string();
%s

#if defined(BOTAN_HOUSE_ECC_CURVE_NAME)
   if(oid_str == BOTAN_HOUSE_ECC_CURVE_OID) return BOTAN_HOUSE_ECC_CURVE_NAME;
#endif

   return std::string();
   }

OID lookup(const std::string& name)
   {
%s

#if defined(BOTAN_HOUSE_ECC_CURVE_NAME)
   if(name == BOTAN_HOUSE_ECC_CURVE_NAME) return OID(BOTAN_HOUSE_ECC_CURVE_OID);
#endif

   return OID();
   }

}

}
""" % (sys.argv[0], datetime.date.today().strftime("%Y-%m-%d"),
       format_if(oid2str,"oid_str"), format_if(str2oid, "name", True))

def main(args = None):
    if args is None:
        args = sys.argv

    oid_lines = open('src/build-data/oids.txt').readlines()

    oid_re = re.compile("^([1-9][0-9.]+) = ([A-Za-z0-9_\./\(\), -]+)$")
    hdr_re = re.compile("^\[([a-z0-9_]+)\]$")

    oid2str = {}
    str2oid = {}
    cur_hdr = None

    for line in oid_lines:
        line = line.strip()
        if len(line) == 0:
            continue

        if line[0] == '#':
            continue

        match = hdr_re.match(line)
        if match is not None:
            cur_hdr = match.group(1)
            continue

        match = oid_re.match(line)
        if match is None:
            raise Exception(line)

        oid = match.group(1)
        nam = match.group(2)

        if oid in str2oid:
            print "Duplicated OID", oid, name, oid2str[oid]
            sys.exit() # hard error
        else:
            oid2str[oid] = nam

        if nam in str2oid:
            #print "Duplicated name", nam, oid, str2oid[nam]
            #str2oid[nam] = oid
            pass
        else:
            str2oid[nam] = oid

    print format_as_ifs(oid2str, str2oid)


if __name__ == '__main__':
    sys.exit(main())
