# 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 json
import os
import string
import subprocess
import sys


BASE_DIR = os.path.dirname(os.path.abspath(__file__))


def Run(*args):
  with open(os.devnull, 'w') as null:
    subprocess.check_call(args, stdout=null, stderr=null)


def FindNode(node, component):
  for child in node['children']:
    if child['name'] == component:
      return child
  return None


def InsertIntoTree(tree, source_name, size):
  components = source_name.replace(':', '').split('\\')
  node = tree
  for index, component in enumerate(components):
    data = FindNode(node, component)
    if not data:
      data = { 'name': component }
      if index == len(components) - 1:
        data['size'] = size
      else:
        data['children'] = []
      node['children'].append(data)
    node = data


def main():
  out_dir = os.path.join(BASE_DIR, '..', '..', '..', 'out', 'Release')
  jsons = []
  for dll in ('chrome.dll', 'chrome_child.dll'):
    dll_path = os.path.normpath(os.path.join(out_dir, dll))
    if os.path.exists(dll_path):
      print 'Tallying %s...' % dll_path
      json_path = dll_path + '.json'
      Run(os.path.join(BASE_DIR, 'code_tally.exe'),
          '--input-image=' + dll_path,
          '--input-pdb=' + dll_path + '.pdb',
          '--output-file=' + json_path)
      jsons.append(json_path)
  if not jsons:
    print 'Couldn\'t find binaries, looking in', out_dir
    return 1

  for json_name in jsons:
    with open(json_name, 'r') as jsonf:
      all_data = json.load(jsonf)
    html_path = os.path.splitext(json_name)[0] + '.html'
    print 'Generating %s...' % html_path
    by_source = {}
    for obj_name, obj_data in all_data['objects'].iteritems():
      for symbol, symbol_data in obj_data.iteritems():
        size = int(symbol_data['size'])
        # Sometimes there's symbols with no source file, we just ignore those.
        if 'contribs' in symbol_data:
          # There may be more than one file in the list, we just assign to the
          # first source file that contains the symbol, rather than try to
          # split or duplicate info.
          src_index = symbol_data['contribs'][0]
          source = all_data['sources'][int(src_index)]
          if source not in by_source:
            by_source[source] = []
          by_source[source].append(size)
    binary_name = all_data['executable']['name']
    data = {}
    data['name'] = binary_name
    data['children'] = []
    for source, sizes in by_source.iteritems():
      InsertIntoTree(data, source, sum(sizes))
    with open(html_path, 'w') as f:
      with open(os.path.join(BASE_DIR, 'template.html'), 'r') as templatef:
        template = templatef.read()
      f.write(string.Template(template).substitute(
          {'data': json.dumps(data, indent=2),
           'dllname': binary_name + ' ' + all_data['executable']['version']}))

  return 0


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