// Filename: interrogateDatabase.cxx
// Created by:  drose (01Aug00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University.  All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license.  You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////

#include "interrogateDatabase.h"
#include "config_interrogatedb.h"
#include "indexRemapper.h"
#include "interrogate_datafile.h"

InterrogateDatabase *InterrogateDatabase::_global_ptr = NULL;
int InterrogateDatabase::_file_major_version = 0;
int InterrogateDatabase::_file_minor_version = 0;
int InterrogateDatabase::_current_major_version = 2;
int InterrogateDatabase::_current_minor_version = 2;

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::Constructor
//       Access: Private
//  Description:
////////////////////////////////////////////////////////////////////
InterrogateDatabase::
InterrogateDatabase() {
  _error_flag = false;
  _next_index = 1;
  _lookups_fresh = 0;
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::get_ptr
//       Access: Private
//  Description: Returns the global pointer to the one
//               InterrogateDatabase.
////////////////////////////////////////////////////////////////////
InterrogateDatabase *InterrogateDatabase::
get_ptr() {
  if (_global_ptr == (InterrogateDatabase *)NULL) {
    if (interrogatedb_cat->is_debug()) {
      interrogatedb_cat->debug()
        << "Creating interrogate database\n";
    }
    _global_ptr = new InterrogateDatabase;
  }
  return _global_ptr;
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::request_module
//       Access: Public
//  Description: Requests that the interrogate data for the given
//               module be made available.  The function pointers will
//               be made available immediately, while the database
//               file will be read later, the next time someone asks
//               for interrogate data that requires it.
////////////////////////////////////////////////////////////////////
void InterrogateDatabase::
request_module(InterrogateModuleDef *def) {
  if (interrogatedb_cat->is_debug()) {
    if (def->library_name == (const char *)NULL) {
      interrogatedb_cat->debug()
        << "Got interrogate data for anonymous module\n";
    } else {
      interrogatedb_cat->debug()
        << "Got interrogate data for module " << def->library_name << "\n";
    }
  }

  int num_indices = def->next_index - def->first_index;
  if (num_indices > 0) {
    // If the module def has any definitions--any index numbers
    // used--assign it to its own unique range of index numbers.
    def->first_index = _next_index;
    _next_index += num_indices;
    def->next_index = _next_index;

    // Assign a reference to the module def by index number.  When we
    // need to look up a function by its index number, we'll be able
    // to use this.
    _modules.push_back(def);
  }

  if (def->num_unique_names > 0 && def->library_name != (const char *)NULL) {
    // Define a lookup by hash for this module, mainly so we can look
    // up functions by their unique names.
    _modules_by_hash[def->library_hash_name] = def;
  }

  if (def->database_filename != (const char *)NULL) {
    _requests.push_back(def);
  }
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::get_error_flag
//       Access: Public
//  Description: Returns the global error flag.  This will be set true
//               if there was some problem importing the database
//               (e.g. cannot find an .in file), or false if
//               everything is ok.
////////////////////////////////////////////////////////////////////
bool InterrogateDatabase::
get_error_flag() {
  return _error_flag;
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::get_num_global_types
//       Access: Public
//  Description: Returns the total number of "global" types known to
//               the interrogate database.  These are types defined at
//               the global level that should be considered for
//               exporting, but not the incidental types (like
//               pointers, etc.) that must be defined to support
//               these.
////////////////////////////////////////////////////////////////////
int InterrogateDatabase::
get_num_global_types() {
  check_latest();
  return _global_types.size();
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::get_global_type
//       Access: Public
//  Description: Returns the index of the nth global type known to the
//               interrogate database.
////////////////////////////////////////////////////////////////////
TypeIndex InterrogateDatabase::
get_global_type(int n) {
  check_latest();
  if (n >= 0 && n < (int)_global_types.size()) {
    return _global_types[n];
  }
  return 0;
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::get_num_all_types
//       Access: Public
//  Description: Returns the total number of types known to the
//               interrogate database.  This includes all known types,
//               global as well as incidental.  See also
//               get_num_global_types().
////////////////////////////////////////////////////////////////////
int InterrogateDatabase::
get_num_all_types() {
  check_latest();
  return _all_types.size();
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::get_all_type
//       Access: Public
//  Description: Returns the index of the nth type known to the
//               interrogate database.
////////////////////////////////////////////////////////////////////
TypeIndex InterrogateDatabase::
get_all_type(int n) {
  check_latest();
  if (n >= 0 && n < (int)_all_types.size()) {
    return _all_types[n];
  }
  return 0;
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::get_num_global_functions
//       Access: Public
//  Description: Returns the total number of global functions known to
//               the interrogate database.  These are functions
//               defined at the global level, e.g. non-member
//               functions.
////////////////////////////////////////////////////////////////////
int InterrogateDatabase::
get_num_global_functions() {
  check_latest();
  return _global_functions.size();
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::get_global_function
//       Access: Public
//  Description: Returns the index of the nth global function known to
//               the interrogate database.
////////////////////////////////////////////////////////////////////
FunctionIndex InterrogateDatabase::
get_global_function(int n) {
  check_latest();
  if (n >= 0 && n < (int)_global_functions.size()) {
    return _global_functions[n];
  }
  return 0;
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::get_num_all_functions
//       Access: Public
//  Description: Returns the total number of functions known to the
//               interrogate database.  This includes all known
//               functions, global, method, or synthesized.  See also
//               get_num_global_functions().
////////////////////////////////////////////////////////////////////
int InterrogateDatabase::
get_num_all_functions() {
  check_latest();
  return _all_functions.size();
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::get_all_function
//       Access: Public
//  Description: Returns the index of the nth function known to the
//               interrogate database.
////////////////////////////////////////////////////////////////////
FunctionIndex InterrogateDatabase::
get_all_function(int n) {
  check_latest();
  if (n >= 0 && n < (int)_all_functions.size()) {
    return _all_functions[n];
  }
  return 0;
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::get_num_global_manifests
//       Access: Public
//  Description: Returns the total number of global manifest constants
//               known to the interrogate database.
////////////////////////////////////////////////////////////////////
int InterrogateDatabase::
get_num_global_manifests() {
  check_latest();
  return _global_manifests.size();
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::get_global_manifest
//       Access: Public
//  Description: Returns the index of the nth global manifest constant
//               known to the interrogate database.
////////////////////////////////////////////////////////////////////
ManifestIndex InterrogateDatabase::
get_global_manifest(int n) {
  check_latest();
  if (n >= 0 && n < (int)_global_manifests.size()) {
    return _global_manifests[n];
  }
  return 0;
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::get_num_global_elements
//       Access: Public
//  Description: Returns the total number of global data elements
//               known to the interrogate database.
////////////////////////////////////////////////////////////////////
int InterrogateDatabase::
get_num_global_elements() {
  check_latest();
  return _global_elements.size();
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::get_global_element
//       Access: Public
//  Description: Returns the index of the nth global data element
//               known to the interrogate database.
////////////////////////////////////////////////////////////////////
ElementIndex InterrogateDatabase::
get_global_element(int n) {
  check_latest();
  if (n >= 0 && n < (int)_global_elements.size()) {
    return _global_elements[n];
  }
  return 0;
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::get_type
//       Access: Public
//  Description: Returns the type associated with the given TypeIndex,
//               if there is one.
////////////////////////////////////////////////////////////////////
const InterrogateType &InterrogateDatabase::
get_type(TypeIndex type) {
  static InterrogateType bogus_type;

  check_latest();
  TypeMap::const_iterator ti;
  ti = _type_map.find(type);
  if (ti == _type_map.end()) {
    return bogus_type;
  }
  return (*ti).second;
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::get_function
//       Access: Public
//  Description: Returns the function associated with the given
//               FunctionIndex, if there is one.
////////////////////////////////////////////////////////////////////
const InterrogateFunction &InterrogateDatabase::
get_function(FunctionIndex function) {
  static InterrogateFunction bogus_function;

  check_latest();
  FunctionMap::const_iterator fi;
  fi = _function_map.find(function);
  if (fi == _function_map.end()) {
    return bogus_function;
  }
  return *(*fi).second;
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::get_wrapper
//       Access: Public
//  Description: Returns the function wrapper associated with the
//               given FunctionWrapperIndex, if there is one.
////////////////////////////////////////////////////////////////////
const InterrogateFunctionWrapper &InterrogateDatabase::
get_wrapper(FunctionWrapperIndex wrapper) {
  static InterrogateFunctionWrapper bogus_wrapper;

  check_latest();
  FunctionWrapperMap::const_iterator wi;
  wi = _wrapper_map.find(wrapper);
  if (wi == _wrapper_map.end()) {
    return bogus_wrapper;
  }
  return (*wi).second;
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::get_manifest
//       Access: Public
//  Description: Returns the manifest constant associated with the
//               given ManifestIndex, if there is one.
////////////////////////////////////////////////////////////////////
const InterrogateManifest &InterrogateDatabase::
get_manifest(ManifestIndex manifest) {
  static InterrogateManifest bogus_manifest;

  check_latest();
  ManifestMap::const_iterator mi;
  mi = _manifest_map.find(manifest);
  if (mi == _manifest_map.end()) {
    return bogus_manifest;
  }
  return (*mi).second;
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::get_element
//       Access: Public
//  Description: Returns the data element associated with the
//               given ElementIndex, if there is one.
////////////////////////////////////////////////////////////////////
const InterrogateElement &InterrogateDatabase::
get_element(ElementIndex element) {
  static InterrogateElement bogus_element;

  check_latest();
  ElementMap::const_iterator ei;
  ei = _element_map.find(element);
  if (ei == _element_map.end()) {
    return bogus_element;
  }
  return (*ei).second;
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::get_make_seq
//       Access: Public
//  Description: Returns the make_seq associated with the given
//               MakeSeqIndex, if there is one.
////////////////////////////////////////////////////////////////////
const InterrogateMakeSeq &InterrogateDatabase::
get_make_seq(MakeSeqIndex make_seq) {
  static InterrogateMakeSeq bogus_make_seq;

  check_latest();
  MakeSeqMap::const_iterator si;
  si = _make_seq_map.find(make_seq);
  if (si == _make_seq_map.end()) {
    return bogus_make_seq;
  }
  return (*si).second;
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::remove_type
//       Access: Public
//  Description: Erases the type from the database.
////////////////////////////////////////////////////////////////////
void InterrogateDatabase::
remove_type(TypeIndex type) {
  _type_map.erase(type);
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::get_fptr
//       Access: Public
//  Description: Returns the function pointer associated with the
//               given function wrapper, if it has a pointer
//               available.  Returns NULL if the pointer is not
//               available.
////////////////////////////////////////////////////////////////////
void *InterrogateDatabase::
get_fptr(FunctionWrapperIndex wrapper) {
  InterrogateModuleDef *def;
  int module_index;
  if (find_module(wrapper, def, module_index)) {
    if (module_index >= 0 && module_index < def->num_fptrs) {
      return def->fptrs[module_index];
    }
  }
  return (void *)NULL;
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::get_wrapper_by_unique_name
//       Access: Public
//  Description: Looks up the function wrapper corresponding to the
//               given unique name, if available.  Returns the
//               corresponding wrapper index, or 0 if no such
//               wrapper is found.
////////////////////////////////////////////////////////////////////
FunctionWrapperIndex InterrogateDatabase::
get_wrapper_by_unique_name(const string &unique_name) {
  // First, split the unique_name into a library_hash_name and a
  // wrapper_hash_name.

  // The first four characters are always the library_name.
  string library_hash_name = unique_name.substr(0, 4);
  string wrapper_hash_name = unique_name.substr(4);

  // Is the library_name defined?
  ModulesByHash::const_iterator mi;
  mi = _modules_by_hash.find(library_hash_name);
  if (mi == _modules_by_hash.end()) {
    return 0;
  }

  InterrogateModuleDef *def = (*mi).second;
  int index_offset =
    binary_search_wrapper_hash(def->unique_names,
                               def->unique_names + def->num_unique_names,
                               wrapper_hash_name);
  if (index_offset >= 0) {
    return def->first_index + index_offset;
  }

  return 0;
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::get_file_major_version
//       Access: Public
//  Description: Returns the major version number of the interrogate
//               database file currently being read.
////////////////////////////////////////////////////////////////////
int InterrogateDatabase::
get_file_major_version() {
  return _file_major_version;
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::get_file_minor_version
//       Access: Public
//  Description: Returns the minor version number of the interrogate
//               database file currently being read.
////////////////////////////////////////////////////////////////////
int InterrogateDatabase::
get_file_minor_version() {
  return _file_minor_version;
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::get_current_major_version
//       Access: Public
//  Description: Returns the major version number currently expected
//               in interrogate database files generated by this code
//               base.
////////////////////////////////////////////////////////////////////
int InterrogateDatabase::
get_current_major_version() {
  return _current_major_version;
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::get_current_minor_version
//       Access: Public
//  Description: Returns the minor version number currently expected
//               in interrogate database files generated by this code
//               base.
////////////////////////////////////////////////////////////////////
int InterrogateDatabase::
get_current_minor_version() {
  return _current_minor_version;
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::set_error_flag
//       Access: Public
//  Description: Sets the global error flag.  This should be set true
//               if there was some problem importing the database
//               (e.g. cannot find an .in file).
////////////////////////////////////////////////////////////////////
void InterrogateDatabase::
set_error_flag(bool error_flag) {
  _error_flag = error_flag;
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::get_next_index
//       Access: Public
//  Description: Returns a new index number suitable for the next
//               thing, that will not be shared with any other index
//               numbers.
////////////////////////////////////////////////////////////////////
int InterrogateDatabase::
get_next_index() {
  return _next_index++;
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::add_type
//       Access: Public
//  Description: Adds the indicated type to the database at the given
//               index number.
////////////////////////////////////////////////////////////////////
void InterrogateDatabase::
add_type(TypeIndex index, const InterrogateType &type) {
  assert(index != 0);
  bool inserted =
    _type_map.insert(TypeMap::value_type(index, type)).second;

  if (!inserted) {
    // If there was already a type at that index, maybe it was a
    // forward reference.  If its _fully_defined bit isn't set, then
    // it's ok.
    InterrogateType &old_type = _type_map[index];
    assert(!old_type.is_fully_defined());

    // It was a forward reference.  Merge it with the new one.
    old_type.merge_with(type);
  }

  if (type.is_global()) {
    _global_types.push_back(index);
  }
  _all_types.push_back(index);
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::add_function
//       Access: Public
//  Description: Adds the indicated function to the database at
//               the given index number.
////////////////////////////////////////////////////////////////////
void InterrogateDatabase::
add_function(FunctionIndex index, InterrogateFunction *function) {
  bool inserted =
    _function_map.insert(FunctionMap::value_type(index, function)).second;
  assert(inserted);

  if (function->is_global()) {
    _global_functions.push_back(index);
  }
  _all_functions.push_back(index);
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::add_wrapper
//       Access: Public
//  Description: Adds the indicated function wrapper to the database at
//               the given index number.
////////////////////////////////////////////////////////////////////
void InterrogateDatabase::
add_wrapper(FunctionWrapperIndex index,
            const InterrogateFunctionWrapper &wrapper) {
  bool inserted =
    _wrapper_map.insert(FunctionWrapperMap::value_type(index, wrapper)).second;
  assert(inserted);
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::add_manifest
//       Access: Public
//  Description: Adds the indicated manifest constant to the database
//               at the given index number.
////////////////////////////////////////////////////////////////////
void InterrogateDatabase::
add_manifest(ManifestIndex index, const InterrogateManifest &manifest) {
  bool inserted =
    _manifest_map.insert(ManifestMap::value_type(index, manifest)).second;
  assert(inserted);

  _global_manifests.push_back(index);
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::add_element
//       Access: Public
//  Description: Adds the indicated data element to the database
//               at the given index number.
////////////////////////////////////////////////////////////////////
void InterrogateDatabase::
add_element(ElementIndex index, const InterrogateElement &element) {
  bool inserted =
    _element_map.insert(ElementMap::value_type(index, element)).second;
  assert(inserted);

  if (element.is_global()) {
    _global_elements.push_back(index);
  }
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::add_make_seq
//       Access: Public
//  Description: Adds the indicated make_seq to the database at
//               the given index number.
////////////////////////////////////////////////////////////////////
void InterrogateDatabase::
add_make_seq(MakeSeqIndex index, const InterrogateMakeSeq &make_seq) {
  bool inserted =
    _make_seq_map.insert(MakeSeqMap::value_type(index, make_seq)).second;
  assert(inserted);
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::update_type
//       Access: Public
//  Description: Returns a non-const reference to the indicated type,
//               allowing the user to update it.
////////////////////////////////////////////////////////////////////
InterrogateType &InterrogateDatabase::
update_type(TypeIndex type) {
  assert(type != 0);
  check_latest();
  return _type_map[type];
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::update_function
//       Access: Public
//  Description: Returns a non-const reference to the indicated
//               function, allowing the user to update it.
////////////////////////////////////////////////////////////////////
InterrogateFunction &InterrogateDatabase::
update_function(FunctionIndex function) {
  check_latest();
  return *_function_map[function];
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::update_wrapper
//       Access: Public
//  Description: Returns a non-const reference to the indicated
//               function wrapper, allowing the user to update it.
////////////////////////////////////////////////////////////////////
InterrogateFunctionWrapper &InterrogateDatabase::
update_wrapper(FunctionWrapperIndex wrapper) {
  check_latest();
  return _wrapper_map[wrapper];
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::update_manifest
//       Access: Public
//  Description: Returns a non-const reference to the indicated
//               manifest constant, allowing the user to update it.
////////////////////////////////////////////////////////////////////
InterrogateManifest &InterrogateDatabase::
update_manifest(ManifestIndex manifest) {
  check_latest();
  return _manifest_map[manifest];
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::update_element
//       Access: Public
//  Description: Returns a non-const reference to the indicated
//               data element, allowing the user to update it.
////////////////////////////////////////////////////////////////////
InterrogateElement &InterrogateDatabase::
update_element(ElementIndex element) {
  check_latest();
  return _element_map[element];
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::update_make_seq
//       Access: Public
//  Description: Returns a non-const reference to the indicated
//               make_seq, allowing the user to update it.
////////////////////////////////////////////////////////////////////
InterrogateMakeSeq &InterrogateDatabase::
update_make_seq(MakeSeqIndex make_seq) {
  check_latest();
  return _make_seq_map[make_seq];
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::remap_indices
//       Access: Public
//  Description: Resequences all of the various index numbers so that
//               all of the functions start at first_index and
//               increment consecutively from there, and then all of
//               the types follow.  Returns the next available index
//               number.
////////////////////////////////////////////////////////////////////
int InterrogateDatabase::
remap_indices(int first_index) {
  IndexRemapper remap;
  return remap_indices(first_index, remap);
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::remap_indices
//       Access: Public
//  Description: This flavor of remap_indices() accepts a map that
//               should be empty on initial call, and will be filled
//               with the mapping of old index number to new index
//               number.  This allows the caller to update its own
//               data structures to match the new index numbers.
////////////////////////////////////////////////////////////////////
int InterrogateDatabase::
remap_indices(int first_index, IndexRemapper &remap) {
  remap.clear();

  // First, build up the complete map.

  // Get the wrapper indices first.  This is important, because the
  // InterrogateBuilder wants these to be first, and consecutive.
  FunctionWrapperMap new_wrapper_map;
  FunctionWrapperMap::iterator wi;
  for (wi = _wrapper_map.begin(); wi != _wrapper_map.end(); ++wi) {
    remap.add_mapping((*wi).first, first_index);
    new_wrapper_map[first_index] = (*wi).second;
    first_index++;
  }

  // Everything else can follow; it doesn't matter so much.
  FunctionMap new_function_map;
  FunctionMap::iterator fi;
  for (fi = _function_map.begin(); fi != _function_map.end(); ++fi) {
    remap.add_mapping((*fi).first, first_index);
    new_function_map[first_index] = (*fi).second;
    first_index++;
  }

  TypeMap new_type_map;
  TypeMap::iterator ti;
  for (ti = _type_map.begin(); ti != _type_map.end(); ++ti) {
    assert((*ti).first != 0);
    remap.add_mapping((*ti).first, first_index);
    new_type_map[first_index] = (*ti).second;
    first_index++;
  }

  ManifestMap new_manifest_map;
  ManifestMap::iterator mi;
  for (mi = _manifest_map.begin(); mi != _manifest_map.end(); ++mi) {
    remap.add_mapping((*mi).first, first_index);
    new_manifest_map[first_index] = (*mi).second;
    first_index++;
  }

  ElementMap new_element_map;
  ElementMap::iterator ei;
  for (ei = _element_map.begin(); ei != _element_map.end(); ++ei) {
    remap.add_mapping((*ei).first, first_index);
    new_element_map[first_index] = (*ei).second;
    first_index++;
  }

  MakeSeqMap new_make_seq_map;
  MakeSeqMap::iterator si;
  for (si = _make_seq_map.begin(); si != _make_seq_map.end(); ++si) {
    remap.add_mapping((*si).first, first_index);
    new_make_seq_map[first_index] = (*si).second;
    first_index++;
  }

  _next_index = first_index;

  _wrapper_map.swap(new_wrapper_map);
  _function_map.swap(new_function_map);
  _type_map.swap(new_type_map);
  _manifest_map.swap(new_manifest_map);
  _element_map.swap(new_element_map);
  _make_seq_map.swap(new_make_seq_map);

  // Then, go back through and update all of the internal references.
  for (wi = _wrapper_map.begin(); wi != _wrapper_map.end(); ++wi) {
    (*wi).second.remap_indices(remap);
  }
  for (fi = _function_map.begin(); fi != _function_map.end(); ++fi) {
    (*fi).second->remap_indices(remap);
  }
  for (ti = _type_map.begin(); ti != _type_map.end(); ++ti) {
    (*ti).second.remap_indices(remap);
  }
  for (mi = _manifest_map.begin(); mi != _manifest_map.end(); ++mi) {
    (*mi).second.remap_indices(remap);
  }
  for (ei = _element_map.begin(); ei != _element_map.end(); ++ei) {
    (*ei).second.remap_indices(remap);
  }
  for (si = _make_seq_map.begin(); si != _make_seq_map.end(); ++si) {
    (*si).second.remap_indices(remap);
  }
  GlobalFunctions::iterator gfi;
  for (gfi = _global_functions.begin(); gfi != _global_functions.end(); ++gfi) {
    (*gfi) = remap.map_from(*gfi);
  }
  for (gfi = _all_functions.begin(); gfi != _all_functions.end(); ++gfi) {
    (*gfi) = remap.map_from(*gfi);
  }
  GlobalTypes::iterator gti;
  for (gti = _global_types.begin(); gti != _global_types.end(); ++gti) {
    (*gti) = remap.map_from(*gti);
  }
  for (gti = _all_types.begin(); gti != _all_types.end(); ++gti) {
    (*gti) = remap.map_from(*gti);
  }
  GlobalManifests::iterator gmi;
  for (gmi = _global_manifests.begin(); gmi != _global_manifests.end(); ++gmi) {
    (*gmi) = remap.map_from(*gmi);
  }
  GlobalElements::iterator gei;
  for (gei = _global_elements.begin(); gei != _global_elements.end(); ++gei) {
    (*gei) = remap.map_from(*gei);
  }

  return _next_index;
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::write
//       Access: Public
//  Description: Writes the database to the indicated stream for later
//               reading.
////////////////////////////////////////////////////////////////////
void InterrogateDatabase::
write(ostream &out, InterrogateModuleDef *def) const {
  // Write out the file header.
  out << def->file_identifier << "\n"
      << _current_major_version << " " << _current_minor_version << "\n";

  // Write out the module definition.
  idf_output_string(out, def->library_name);
  idf_output_string(out, def->library_hash_name);
  idf_output_string(out, def->module_name);
  out << "\n";

  // Now write out the components.

  out << _function_map.size() << "\n";
  FunctionMap::const_iterator fi;
  for (fi = _function_map.begin(); fi != _function_map.end(); ++fi) {
    out << (*fi).first << " " << *(*fi).second << "\n";
  }

  out << _wrapper_map.size() << "\n";
  FunctionWrapperMap::const_iterator wi;
  for (wi = _wrapper_map.begin(); wi != _wrapper_map.end(); ++wi) {
    out << (*wi).first << " " << (*wi).second << "\n";
  }

  out << _type_map.size() << "\n";
  TypeMap::const_iterator ti;
  for (ti = _type_map.begin(); ti != _type_map.end(); ++ti) {
    out << (*ti).first << " " << (*ti).second << "\n";
  }

  out << _manifest_map.size() << "\n";
  ManifestMap::const_iterator mi;
  for (mi = _manifest_map.begin(); mi != _manifest_map.end(); ++mi) {
    out << (*mi).first << " " << (*mi).second << "\n";
  }

  out << _element_map.size() << "\n";
  ElementMap::const_iterator ei;
  for (ei = _element_map.begin(); ei != _element_map.end(); ++ei) {
    out << (*ei).first << " " << (*ei).second << "\n";
  }

  out << _make_seq_map.size() << "\n";
  MakeSeqMap::const_iterator si;
  for (si = _make_seq_map.begin(); si != _make_seq_map.end(); ++si) {
    out << (*si).first << " " << (*si).second << "\n";
  }
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::read
//       Access: Public
//  Description: Reads a database from the indicated stream,
//               associated with the indicated module definition and
//               merges it with any existing data in the database,
//               according to the expected index numbers specified in
//               the module def.  The header information has already
//               been read.
//
//               Returns true if the file is read successfully, false
//               if there is an error.
////////////////////////////////////////////////////////////////////
bool InterrogateDatabase::
read(istream &in, InterrogateModuleDef *def) {
  InterrogateDatabase temp;
  if (!temp.read_new(in, def)) {
    return false;
  }

  if (def->first_index == 0 && def->next_index == 0) {
    _next_index = temp.remap_indices(_next_index);

  } else {
    int next = temp.remap_indices(def->first_index);
    if (next != def->next_index) {
      interrogatedb_cat->error()
        << "Module database file " << def->database_filename
        << " is out of date.\n";
      return false;
    }
  }

  merge_from(temp);
  return true;
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::load_latest
//       Access: Private
//  Description: Reads in the latest interrogate data.
////////////////////////////////////////////////////////////////////
void InterrogateDatabase::
load_latest() {
  const DSearchPath &searchpath = interrogatedb_path;

  Requests copy_requests;
  copy_requests.swap(_requests);

  Requests::const_iterator ri;
  for (ri = copy_requests.begin(); ri != copy_requests.end(); ++ri) {
    InterrogateModuleDef *def = (*ri);

    if (def->database_filename != (char *)NULL) {
      Filename filename = def->database_filename;
      Filename pathname = filename;
      if (!pathname.empty() && pathname[0] != '/') {
        pathname = searchpath.find_file(pathname);
      }

      if (pathname.empty()) {
        interrogatedb_cat->error()
          << "Unable to find " << filename << " on " << searchpath << "\n";
        set_error_flag(true);

      } else {

        pifstream input;
        pathname.set_text();
        if (!pathname.open_read(input)) {
          interrogatedb_cat->error() << "Unable to read " << pathname << ".\n";
          set_error_flag(true);

        } else {
          int file_identifier;
          input >> file_identifier
                >> _file_major_version >> _file_minor_version;

          if (def->file_identifier != 0 &&
              file_identifier != def->file_identifier) {
            interrogatedb_cat->warning()
              << "Interrogate data in " << pathname
              << " is out of sync with the compiled-in data"
              << " (" << file_identifier << " != " << def->file_identifier << ").\n";
            set_error_flag(true);
          }

          if (_file_major_version != _current_major_version ||
              _file_minor_version > _current_minor_version) {
            interrogatedb_cat->error()
              << "Cannot read interrogate data in " << pathname
              << "; database is version " << _file_major_version << "."
              << _file_minor_version << " while we are expecting "
              << _current_major_version << "." << _current_minor_version
              << ".\n";
            set_error_flag(true);

          } else {
            if (interrogatedb_cat->is_debug()) {
              interrogatedb_cat->debug()
                << "Reading " << filename << "\n";
            }
            if (!read(input, def)) {
              interrogatedb_cat->error()
                << "Error reading " << pathname << ".\n";
              set_error_flag(true);
            }
          }
        }
      }
    }
  }

  _requests.clear();
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::read_new
//       Access: Private
//  Description: Reads from the indicated stream (the header
//               information has already been read) into the
//               newly-created database.  It is an error if the
//               database already has some data in it.
////////////////////////////////////////////////////////////////////
bool InterrogateDatabase::
read_new(istream &in, InterrogateModuleDef *def) {
  // We've already read the header.  Read the module definition.
  idf_input_string(in, def->library_name);
  idf_input_string(in, def->library_hash_name);
  idf_input_string(in, def->module_name);

  // Now read all of the components.

  { // Functions.
    int num_functions;
    in >> num_functions;
    if (in.fail()) {
      return false;
    }

    while (num_functions > 0) {
      FunctionIndex index;
      InterrogateFunction *function = new InterrogateFunction(def);
      in >> index >> *function;
      if (in.fail()) {
        delete function;
        return false;
      }

      add_function(index, function);
      num_functions--;
    }
  }

  { // Wrappers.
    int num_wrappers;
    in >> num_wrappers;
    if (in.fail()) {
      return false;
    }

    while (num_wrappers > 0) {
      FunctionWrapperIndex index;
      InterrogateFunctionWrapper wrapper(def);
      in >> index >> wrapper;
      if (in.fail()) {
        return false;
      }

      add_wrapper(index, wrapper);
      num_wrappers--;
    }
  }

  { // Types.
    int num_types;
    in >> num_types;
    if (in.fail()) {
      return false;
    }

    while (num_types > 0) {
      TypeIndex index;
      InterrogateType type(def);
      in >> index >> type;
      if (in.fail()) {
        return false;
      }

      add_type(index, type);
      num_types--;
    }
  }

  { // Manifests.
    int num_manifests;
    in >> num_manifests;
    if (in.fail()) {
      return false;
    }

    while (num_manifests > 0) {
      ManifestIndex index;
      InterrogateManifest manifest(def);
      in >> index >> manifest;
      if (in.fail()) {
        return false;
      }

      add_manifest(index, manifest);
      num_manifests--;
    }
  }

  { // Elements.
    int num_elements;
    in >> num_elements;
    if (in.fail()) {
      return false;
    }

    while (num_elements > 0) {
      ElementIndex index;
      InterrogateElement element(def);
      in >> index >> element;
      if (in.fail()) {
        return false;
      }

      add_element(index, element);
      num_elements--;
    }
  }

  { // MakeSeqs.
    int num_make_seqs;
    in >> num_make_seqs;
    if (in.fail()) {
      return false;
    }

    while (num_make_seqs > 0) {
      MakeSeqIndex index;
      InterrogateMakeSeq make_seq(def);
      in >> index >> make_seq;
      if (in.fail()) {
        return false;
      }

      add_make_seq(index, make_seq);
      num_make_seqs--;
    }
  }

  return true;
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::merge_from
//       Access: Private
//  Description: Copies all the data from the indicated database into
//               this one.  It is an error if any index numbers are
//               shared between the two databases.
////////////////////////////////////////////////////////////////////
void InterrogateDatabase::
merge_from(const InterrogateDatabase &other) {
  // We want to collapse shared types together.
  IndexRemapper remap;

  // First, we need to build a set of types by name, so we know what
  // types we already have.
  map<string, TypeIndex> types_by_name;

  TypeMap::const_iterator ti;
  for (ti = _type_map.begin(); ti != _type_map.end(); ++ti) {
    const InterrogateType &type = (*ti).second;
    if (type.has_true_name()) {
      types_by_name[type.get_true_name()] = (*ti).first;
    }
  }

  // Now go through the other set of types and determine the mapping
  // into this set.
  for (ti = other._type_map.begin(); ti != other._type_map.end(); ++ti) {
    TypeIndex other_type_index = (*ti).first;
    const InterrogateType &other_type = (*ti).second;

    if (other_type.has_name()) {
      map<string, TypeIndex>::iterator ni;
      ni = types_by_name.find(other_type.get_true_name());
      if (ni != types_by_name.end()) {
        // Here's a type that we seem to have in common!  We'll have
        // to merge them.
        TypeIndex this_type_index = (*ni).second;
        remap.add_mapping(other_type_index, this_type_index);
      }
    }
  }

  // Now that we know the full type-to-type mapping, we can copy the
  // new types, one at a time.
  for (ti = other._type_map.begin(); ti != other._type_map.end(); ++ti) {
    TypeIndex other_type_index = (*ti).first;
    const InterrogateType &other_type = (*ti).second;

    if (!remap.in_map(other_type_index)) {
      // Here's a new type.
      add_type(other_type_index, other_type);
      update_type(other_type_index).remap_indices(remap);

    } else {
      // Here's a type to merge.
      TypeIndex this_type_index = remap.map_from(other_type_index);

      InterrogateType &this_type = update_type(this_type_index);
      if (!this_type.is_global() && other_type.is_global()) {
        // If the type is about to become global, we need to add it
        // to our global_types list.
        _global_types.push_back(this_type_index);
      }

      InterrogateType merge_type = other_type;
      merge_type.remap_indices(remap);
      this_type.merge_with(merge_type);
    }
  }

  // And copy all of the functions, wrappers, manifests, and elements.
  FunctionMap::const_iterator fi;
  for (fi = other._function_map.begin();
       fi != other._function_map.end();
       ++fi) {
    FunctionIndex other_function_index = (*fi).first;
    InterrogateFunction *other_function = (*fi).second;
    add_function(other_function_index, other_function);
    update_function(other_function_index).remap_indices(remap);
  }

  FunctionWrapperMap::const_iterator wi;
  for (wi = other._wrapper_map.begin();
       wi != other._wrapper_map.end();
       ++wi) {
    FunctionWrapperIndex other_wrapper_index = (*wi).first;
    const InterrogateFunctionWrapper &other_wrapper = (*wi).second;
    add_wrapper(other_wrapper_index, other_wrapper);
    update_wrapper(other_wrapper_index).remap_indices(remap);
  }

  ManifestMap::const_iterator mi;
  for (mi = other._manifest_map.begin();
       mi != other._manifest_map.end();
       ++mi) {
    ManifestIndex other_manifest_index = (*mi).first;
    const InterrogateManifest &other_manifest = (*mi).second;
    add_manifest(other_manifest_index, other_manifest);
    update_manifest(other_manifest_index).remap_indices(remap);
  }

  ElementMap::const_iterator ei;
  for (ei = other._element_map.begin();
       ei != other._element_map.end();
       ++ei) {
    ElementIndex other_element_index = (*ei).first;
    const InterrogateElement &other_element = (*ei).second;
    add_element(other_element_index, other_element);
    update_element(other_element_index).remap_indices(remap);
  }

  MakeSeqMap::const_iterator si;
  for (si = other._make_seq_map.begin();
       si != other._make_seq_map.end();
       ++si) {
    MakeSeqIndex other_make_seq_index = (*si).first;
    const InterrogateMakeSeq &other_make_seq = (*si).second;
    add_make_seq(other_make_seq_index, other_make_seq);
    update_make_seq(other_make_seq_index).remap_indices(remap);
  }

  _lookups_fresh = 0;
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::find_module
//       Access: Private
//  Description: Looks up the wrapper definition in the set of module
//               defs that are loaded in at runtime and represent the
//               part of the interrogate database that's compiled in.
//
//               If the wrapper definition is not found, returns
//               false.  If it is found, returns true and sets def and
//               module_index to the particular module and the index
//               within the module where the wrapper is defined.
////////////////////////////////////////////////////////////////////
bool InterrogateDatabase::
find_module(FunctionWrapperIndex wrapper, InterrogateModuleDef *&def,
            int &module_index) {
  if (_modules.empty()) {
    return false;
  }

  int mi = binary_search_module(0, _modules.size(), wrapper);
  assert(mi >= 0 && mi < (int)_modules.size());
  def = _modules[mi];
  module_index = wrapper - def->first_index;

  return (wrapper < def->next_index);
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::binary_search_module
//       Access: Private
//  Description: Searches for the function module that includes the
//               given function index by binary search.
////////////////////////////////////////////////////////////////////
int InterrogateDatabase::
binary_search_module(int begin, int end, FunctionIndex function) {
  int mid = begin + (end - begin) / 2;
  if (mid == begin) {
    return mid;
  }

  int index = _modules[mid]->first_index;
  if (index <= function) {
    return binary_search_module(mid, end, function);

  } else {
    return binary_search_module(begin, mid, function);
  }
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::binary_search_wrapper_hash
//       Access: Private
//  Description: Searches for the particular function wrapper's hash
//               name within a given module.  Returns the index number
//               local to the module, or -1 if it is not found.
////////////////////////////////////////////////////////////////////
int InterrogateDatabase::
binary_search_wrapper_hash(InterrogateUniqueNameDef *begin,
                           InterrogateUniqueNameDef *end,
                           const string &wrapper_hash_name) {
  if (end <= begin) {
    return -1;
  }

  InterrogateUniqueNameDef *mid = begin + (end - begin) / 2;
  string name = mid->name;
  if (name < wrapper_hash_name) {
    return binary_search_wrapper_hash(mid, end, wrapper_hash_name);

  } else if (wrapper_hash_name < name) {
    return binary_search_wrapper_hash(begin, mid, wrapper_hash_name);

  } else {
    return mid->index_offset;
  }
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::freshen_types_by_name
//       Access: Private
//  Description: Builds up the lookup of types by name.
////////////////////////////////////////////////////////////////////
void InterrogateDatabase::
freshen_types_by_name() {
  _types_by_name.clear();
  TypeMap::const_iterator ti;
  for (ti = _type_map.begin(); ti != _type_map.end(); ++ti) {
    _types_by_name[(*ti).second.get_name()] = (*ti).first;
  }
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::freshen_types_by_scoped_name
//       Access: Private
//  Description: Builds up the lookup of types by scoped name.
////////////////////////////////////////////////////////////////////
void InterrogateDatabase::
freshen_types_by_scoped_name() {
  _types_by_scoped_name.clear();
  TypeMap::const_iterator ti;
  for (ti = _type_map.begin(); ti != _type_map.end(); ++ti) {
    _types_by_scoped_name[(*ti).second.get_scoped_name()] = (*ti).first;
  }
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::freshen_types_by_true_name
//       Access: Private
//  Description: Builds up the lookup of types by true name.
////////////////////////////////////////////////////////////////////
void InterrogateDatabase::
freshen_types_by_true_name() {
  _types_by_true_name.clear();
  TypeMap::const_iterator ti;
  for (ti = _type_map.begin(); ti != _type_map.end(); ++ti) {
    _types_by_true_name[(*ti).second.get_true_name()] = (*ti).first;
  }
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::freshen_manifests_by_name
//       Access: Private
//  Description: Builds up the lookup of manifests by name.
////////////////////////////////////////////////////////////////////
void InterrogateDatabase::
freshen_manifests_by_name() {
  _manifests_by_name.clear();
  ManifestMap::const_iterator ti;
  for (ti = _manifest_map.begin(); ti != _manifest_map.end(); ++ti) {
    _manifests_by_name[(*ti).second.get_name()] = (*ti).first;
  }
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::freshen_elements_by_name
//       Access: Private
//  Description: Builds up the lookup of elements by name.
////////////////////////////////////////////////////////////////////
void InterrogateDatabase::
freshen_elements_by_name() {
  _elements_by_name.clear();
  ElementMap::const_iterator ti;
  for (ti = _element_map.begin(); ti != _element_map.end(); ++ti) {
    _elements_by_name[(*ti).second.get_name()] = (*ti).first;
  }
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::freshen_elements_by_scoped_name
//       Access: Private
//  Description: Builds up the lookup of elements by scoped name.
////////////////////////////////////////////////////////////////////
void InterrogateDatabase::
freshen_elements_by_scoped_name() {
  _elements_by_scoped_name.clear();
  ElementMap::const_iterator ti;
  for (ti = _element_map.begin(); ti != _element_map.end(); ++ti) {
    _elements_by_scoped_name[(*ti).second.get_scoped_name()] = (*ti).first;
  }
}

////////////////////////////////////////////////////////////////////
//     Function: InterrogateDatabase::lookup
//       Access: Private
//  Description: Looks up a type, manifest, or element in the
//               indicated lookup table by name.  This is an internal
//               support function.
////////////////////////////////////////////////////////////////////
int InterrogateDatabase::
lookup(const string &name, Lookup &lookup, LookupType type,
       void (InterrogateDatabase::*freshen)()) {
  if ((_lookups_fresh & (int)type) == 0) {
    // The lookup table isn't fresh; we need to freshen it.
    (this->*freshen)();
    _lookups_fresh |= (int)type;
  }

  Lookup::const_iterator li;
  li = lookup.find(name);
  if (li != lookup.end()) {
    return (*li).second;
  }
  return 0;
}
