// Filename: eggGroupUniquifier.cxx
// Created by:  drose (22Feb01)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license.  You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////

#include "eggGroupUniquifier.h"
#include "eggGroup.h"

#include "pnotify.h"

#include <ctype.h>

TypeHandle EggGroupUniquifier::_type_handle;


////////////////////////////////////////////////////////////////////
//     Function: EggGroupUniquifier::Constructor
//       Access: Public
//  Description: If filter_names is true, then the group names will be
//               coerced into a fairly safe, standard convention that
//               uses no characters other than a-z, A-Z, 0-9, and
//               underscore.  If filter_names is false, the group
//               names will be left unchanged.
////////////////////////////////////////////////////////////////////
EggGroupUniquifier::
EggGroupUniquifier(bool filter_names)
  : _filter_names(filter_names)
{
}

////////////////////////////////////////////////////////////////////
//     Function: EggGroupUniquifier::get_category
//       Access: Public
//  Description: Returns the category name into which the given node
//               should be collected, or the empty string if the
//               node's name should be left alone.
////////////////////////////////////////////////////////////////////
string EggGroupUniquifier::
get_category(EggNode *node) {
  if (node->is_of_type(EggGroup::get_class_type()) && node->has_name()) {
    return "group";
  }

  return string();
}

////////////////////////////////////////////////////////////////////
//     Function: EggGroupUniquifier::filter_name
//       Access: Public, Virtual
//  Description: Returns the name of the given node, or at least the
//               name it should be.  This provides a hook to adjust
//               the name before attempting to uniquify it, if
//               desired, for instance to remove invalid characters.
////////////////////////////////////////////////////////////////////
string EggGroupUniquifier::
filter_name(EggNode *node) {
  string name = node->get_name();
  if (!_filter_names) {
    return name;
  }
  nassertr(!name.empty(), string());

  string result;

  // First, replace characters not A-Z, a-z, 0-9, or '_' with
  // underscore, and remove consecutive underscores.
  string::const_iterator pi;
  bool last_underscore = false;
  for (pi = name.begin(); pi != name.end(); ++pi) {
    if (isalnum(*pi)) {
      result += *pi;
      last_underscore = false;

    } else if (!last_underscore) {
      result += '_';
      last_underscore = true;
    }
  }

  // Next, ensure the name does not begin with a digit.
  nassertr(!result.empty(), string());
  if (isdigit(result[0])) {
    result = "_" + result;
  }

  return result;
}

////////////////////////////////////////////////////////////////////
//     Function: EggGroupUniquifier::generate_name
//       Access: Public, Virtual
//  Description: Generates a new name for the given node when its
//               existing name clashes with some other node.  This
//               function will be called repeatedly, if necessary,
//               until it returns a name that actually is unique.
//
//               The category is the string returned by
//               get_category(), and index is a uniquely-generated
//               number that may be useful for synthesizing the name.
////////////////////////////////////////////////////////////////////
string EggGroupUniquifier::
generate_name(EggNode *node, const string &category, int index) {
  ostringstream str;
  str << node->get_name() << "_group" << index;
  return str.str();
}
