# Copyright (c) 2012 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 itertools
import optparse
import re

VENDOR_PATTERN = re.compile("^(?P<id>[0-9a-fA-F]{4})\s+(?P<name>.+)$")
PRODUCT_PATTERN = re.compile("^\t(?P<id>[0-9a-fA-F]{4})\s+(?P<name>.+)$")

def EscapeName(name):
  name = name.replace("\\", "\\\\")
  name = name.replace("\"", "\\\"")
  name = name.replace("?", "\?")
  return name

def ParseTable(input_path):
  input_file = open(input_path, "r")
  input = input_file.read().split("\n")
  input_file.close()

  table = {}
  vendor = None

  for line in input:
    vendor_match = VENDOR_PATTERN.match(line)
    if vendor_match:
      if vendor:
        table[vendor["id"]] = vendor
      vendor = {}
      vendor["id"] = int(vendor_match.group("id"), 16)
      vendor["name"] = vendor_match.group("name")
      vendor["products"] = []
      continue

    product_match = PRODUCT_PATTERN.match(line)
    if product_match:
      if not vendor:
        raise Exception("Product seems to appear before vendor.")
      product = {}
      product["id"] = int(product_match.group("id"), 16)
      product["name"] = product_match.group("name")
      vendor["products"].append(product)

  return table

def GenerateDeviceDefinitions(table):
  output = ""

  for vendor_id in sorted(table.keys()):
    vendor = table[vendor_id]
    if len(vendor["products"]) == 0:
      continue

    output += "static const UsbProduct vendor_%.4x_products[] = {\n" % \
        vendor["id"]
    for product in vendor["products"]:
      output += "  {0x%.4x, \"%s\"},\n" % (product["id"],
                                           EscapeName(product["name"]))
    output += "};\n"

  return output

def GenerateVendorDefinitions(table):
  output = "const size_t UsbIds::vendor_size_ = %d;\n" % len(table.keys())
  output += "const UsbVendor UsbIds::vendors_[] = {\n"

  for vendor_id in sorted(table.keys()):
    vendor = table[vendor_id]

    product_table = "NULL"
    if len(vendor["products"]) != 0:
      product_table = "vendor_%.4x_products" % (vendor["id"])
    output += "  {0x%.4x, \"%s\", %d, %s},\n" % (vendor["id"],
        EscapeName(vendor["name"]), len(vendor["products"]), product_table)

  output += "};\n"
  return output

if __name__ == "__main__":
  parser = optparse.OptionParser(
      description="Generates a C++ USB ID lookup table.")
  parser.add_option("-i", "--input", help="Path to usb.ids")
  parser.add_option("-o", "--output", help="Output file path")

  (opts, args) = parser.parse_args()
  table = ParseTable(opts.input)

  output = """// Generated from %s
#ifndef GENERATED_USB_IDS_H_
#define GENERATED_USB_IDS_H_

#include "device/usb/usb_ids.h"

namespace device {

""" % (opts.input)
  output += GenerateDeviceDefinitions(table)
  output += GenerateVendorDefinitions(table)
  output += """

}  // namespace device

#endif  // GENERATED_USB_IDS_H_
"""

  output_file = open(opts.output, "w+")
  output_file.write(output)
  output_file.close()
