#!/usr/bin/python
# Copyright 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import sys
import string
import json

template_h = string.Template("""\
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_PROTOCOL_CONSTANTS_H_
#define CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_PROTOCOL_CONSTANTS_H_

// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
// Generated by
//  content/browser/devtools/devtools_protocol_constants_generator.py from
//  third_party/WebKit/Source/devtools/protocol.json and
//  content/browser/devtools/browser_protocol.json).

namespace content {
namespace devtools {

extern const char kResult[];
$contents

}  // devtools
}  // content

#endif  // CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_PROTOCOL_CONSTANTS_H_
""")

template_cc = string.Template("""\
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
// Generated by
//  content/browser/devtools/devtools_protocol_constants_generator.py from
//  third_party/WebKit/Source/devtools/protocol.json and
//  content/browser/devtools/browser_protocol.json).

#include "content/browser/devtools/devtools_protocol_constants.h"

namespace content {
namespace devtools {

const char kResult[] = "result";
$contents

}  // devtools
}  // content
""")

def Capitalize(s):
  return s[:1].capitalize() + s[1:]

references = []

def CreateNamespace(domain_name, data, keys, prefixes, name = None):
  result = {}
  if name:
    result["kName"] = name
  for i, key in enumerate(keys):
    if key in data:
      for parameter in data[key]:
        parameter_name = parameter["name"];
        result[prefixes[i] + Capitalize(parameter_name)] = parameter_name
        if "enum" in parameter:
          enum_name = Capitalize(parameter_name)
          result[enum_name] = {}
          for enum in parameter["enum"]:
            result[enum_name]["kEnum" + Capitalize(enum)] = enum
        reference = ""
        if "$ref" in parameter:
          reference = parameter["$ref"]
        if "items" in parameter and "$ref" in parameter["items"]:
          reference = parameter["items"]["$ref"]
        if reference:
          if not "." in reference:
            reference = domain_name + "." + reference
          references.append(reference)
  return result

def IsHandledInBrowser(item):
  return "handlers" in item and "browser" in item["handlers"]

def FormatContents(tree, indent, format_string):
  outer = dict((key, value) for key, value in tree.iteritems()
                if not isinstance(value, dict))
  inner = dict((key, value) for key, value in tree.iteritems()
              if isinstance(value, dict))
  body = ""
  body += "".join(indent + format_string.format(key, value)
                 for (key, value) in sorted(outer.items()))
  body += "".join(FormatNamespace(key, value, indent, format_string)
                 for (key, value) in sorted(inner.items()))
  return body

def FormatNamespace(title, tree, indent, format_string):
  if (not tree):
    return ""
  body = '\n' + indent + "namespace " + title + " {\n"
  body += FormatContents(tree, indent + "  ", format_string)
  body += indent + "} // " + title + "\n"
  return body

def CreateHeader(tree, output_file):
  contents = FormatContents(tree, "", "extern const char {0}[];\n")
  output_file.write(template_h.substitute({"contents": contents}))

def CreateBody(tree, output_file):
  contents = FormatContents(tree, "", "const char {0}[] = \"{1}\";\n")
  output_file.write(template_cc.substitute({"contents": contents}))

blink_protocol_data = open(sys.argv[1]).read()
browser_protocol_data = open(sys.argv[2]).read()

blink_protocol = json.loads(blink_protocol_data)
browser_protocol = json.loads(browser_protocol_data)

domains = blink_protocol["domains"] + browser_protocol["domains"]

namespace_tree = {}

for domain in domains:
  domain_value = {}
  domain_namespace_name = Capitalize(domain["domain"])
  if "commands" in domain:
    for command in domain["commands"]:
      if (IsHandledInBrowser(command)):
        domain_value[command["name"]] = CreateNamespace(domain["domain"],
            command, ["parameters", "returns"], ["kParam", "kResponse"],
            domain_namespace_name + "." + command["name"])

  if "events" in domain:
    for event in domain["events"]:
      if IsHandledInBrowser(event):
        domain_value[event["name"]] = CreateNamespace(domain["domain"],
            event, ["parameters"], ["kParam"],
            domain_namespace_name + "." + event["name"])
  if domain_value:
    namespace_tree[domain_namespace_name] = domain_value

while (references):
  reference = references.pop();
  path = reference.split(".");
  parent_namespace = namespace_tree;
  for path_segment in path[0:-1]:
    if path_segment not in parent_namespace:
      parent_namespace[path_segment] = {}
    parent_namespace = parent_namespace[path_segment]
  if (path[-1] not in parent_namespace):
    try:
      domain = [d for d in domains if d["domain"] == path[0]][0]
      ref_type = [t for t in domain["types"] if t["id"] == path[1]][0]
      parent_namespace[ref_type["id"]] = CreateNamespace(path[0],
          ref_type, ["properties"], ["kParam"])
    except IndexError:
      sys.stderr.write("Failed to resolve type [{0}].\n".format(reference))
      sys.exit(1)

for (namespace_name, namespace) in namespace_tree.items():
  namespace["kName"] = namespace_name

with open(sys.argv[3], "w") as f:
  CreateBody(namespace_tree, f)

with open(sys.argv[4], "w") as f:
  CreateHeader(namespace_tree, f)
