# Copyright 2015 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.

from string import Template

import optparse
import os
import sys

try:
  grit_module_path = os.path.join(
      os.path.dirname(__file__),  '..', '..', '..', 'tools', 'grit')
  sys.path.insert(0, grit_module_path)
  from grit.format import data_pack as DataPack
except ImportError, e:
  print 'ImportError: ', e
  sys.exit(-1)

def is_ascii(s):
  return all(ord(c) < 128 for c in s)

header_template = \
"""// Copyright 2015 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 MOJO_SERVICES_HTML_VIEWER_BLINK_RESOURCE_MAP_H_
#define MOJO_SERVICES_HTML_VIEWER_BLINK_RESOURCE_MAP_H_

#include <map>

namespace html_viewer {

class BlinkResourceMap {
 public:
  BlinkResourceMap();
  const char* GetResource(int id, int* length);

 private:
  struct ResourceEntry {
    const char* data;
    int length;

    ResourceEntry()
      : data(nullptr)
      , length(0) {
    }

    ResourceEntry(const char* data, int length)
      : data(data)
      , length(length) {
    }
  };
  typedef std::map<int, ResourceEntry> ResourceMap;
  ResourceMap resources_;
};

} // namespace html_viewer
#endif // MOJO_SERVICES_HTML_VIEWER_BLINK_RESOURCE_MAP_H_"""

cpp_template = \
"""// Copyright 2015 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.

#include "$header_file_name"

#include "base/macros.h"

namespace html_viewer {

$definitions

BlinkResourceMap::BlinkResourceMap()
{
  $map_initializer
}

const char* BlinkResourceMap::GetResource(int id, int* length)
{
  ResourceMap::iterator it = resources_.find(id);
  if (it == resources_.end()) {
    *length = 0;
    return nullptr;
  }
  *length = it->second.length;
  return it->second.data;
}

} // namespace html_viewer"""

def main():
  parser = optparse.OptionParser(
    usage='Usage: %prog --pak-file PAK_FILE --header HEADER --cpp CPP\n')
  parser.add_option('-i', '--pak-file', action='store', dest='pak_file',
                    help='The .pak file to be extracted.')
  parser.add_option('', '--header', action='store', dest='header_file',
                    help='Header file to be generated.')
  parser.add_option('', '--cpp', action='store', dest='cpp_file',
                    help='C++ file to be generated.')

  (options, _) = parser.parse_args()
  if (not options.pak_file or not options.header_file or not options.cpp_file):
    parser.print_help()
    sys.exit(-1)

  header_file = open(options.header_file, 'w+')
  cpp_file = open(options.cpp_file, 'w+')

  pak_contents = DataPack.ReadDataPack(options.pak_file)
  resourceIds = []

  header_contents = dict()
  cpp_contents = dict()

  definitions = []

  for (resId, data) in pak_contents.resources.iteritems():
    if not is_ascii(data):
      continue
    resourceIds.append(resId)
    hex_values = ['0x{0:02x}'.format(ord(char)) for char in data]
    f = lambda A, n=12: [A[i:i+n] for i in range(0, len(A), n)]
    hex_values_string = ',\n    '.join(', '.join(x) for x in f(hex_values))
    cpp_definition = \
        'const char kResource%s[%d] = {\n    %s \n};' % \
        (str(resId), len(hex_values), hex_values_string)
    definitions.append(cpp_definition)

  header_file_contents = Template(header_template).substitute(header_contents)
  header_file.write(header_file_contents)
  header_file.close()

  map_initializer = []
  for resId in resourceIds:
    insert_statement = \
        'resources_.insert(std::pair<int, ResourceEntry>(\n' \
        '      %s, ResourceEntry(kResource%s, arraysize(kResource%s))));'
    map_initializer.append( \
        insert_statement % (str(resId), str(resId), str(resId)))

  cpp_contents['definitions']= '\n'.join(definitions)
  cpp_contents['header_file_name'] = os.path.basename(options.header_file)
  cpp_contents['map_initializer'] = '\n  '.join(map_initializer)
  cpp_file_contents = Template(cpp_template).substitute(cpp_contents)
  cpp_file.write(cpp_file_contents)
  cpp_file.close()

if __name__ == '__main__':
  main()
