// Filename: dcSwitch.cxx
// Created by:  drose (23Jun04)
//
////////////////////////////////////////////////////////////////////
//
// 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 "dcSwitch.h"
#include "dcField.h"
#include "dcParameter.h"
#include "hashGenerator.h"
#include "dcindent.h"
#include "dcPacker.h"

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::Constructor
//       Access: Public
//  Description: The key_parameter must be recently allocated via
//               new; it will be deleted via delete when the switch
//               destructs.
////////////////////////////////////////////////////////////////////
DCSwitch::
DCSwitch(const string &name, DCField *key_parameter) :
  _name(name),
  _key_parameter(key_parameter)
{
  _default_case = NULL;
  _fields_added = false;
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::Destructor
//       Access: Public, Virtual
//  Description:
////////////////////////////////////////////////////////////////////
DCSwitch::
~DCSwitch() {
  nassertv(_key_parameter != (DCField *)NULL);
  delete _key_parameter;

  Cases::iterator ci;
  for (ci = _cases.begin(); ci != _cases.end(); ++ci) {
    SwitchCase *dcase = (*ci);
    delete dcase;
  }

  CaseFields::iterator fi;
  for (fi = _case_fields.begin(); fi != _case_fields.end(); ++fi) {
    SwitchFields *fields = (*fi);
    delete fields;
  }

  Fields::iterator ni;
  for (ni = _nested_fields.begin(); ni != _nested_fields.end(); ++ni) {
    DCField *field = (*ni);
    delete field;
  }
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::as_switch
//       Access: Published, Virtual
//  Description: 
////////////////////////////////////////////////////////////////////
DCSwitch *DCSwitch::
as_switch() {
  return this;
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::as_switch
//       Access: Published, Virtual
//  Description: 
////////////////////////////////////////////////////////////////////
const DCSwitch *DCSwitch::
as_switch() const {
  return this;
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::get_name
//       Access: Published
//  Description: Returns the name of this switch.
////////////////////////////////////////////////////////////////////
const string &DCSwitch::
get_name() const {
  return _name;
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::get_key_parameter
//       Access: Published
//  Description: Returns the key parameter on which the switch is
//               based.  The value of this parameter in the record
//               determines which one of the several cases within the
//               switch will be used.
////////////////////////////////////////////////////////////////////
DCField *DCSwitch::
get_key_parameter() const {
  return _key_parameter;
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::get_num_cases
//       Access: Published
//  Description: Returns the number of different cases within the
//               switch.  The legal values for case_index range from 0
//               to get_num_cases() - 1.
////////////////////////////////////////////////////////////////////
int DCSwitch::
get_num_cases() const {
  return _cases.size();
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::get_case_by_value
//       Access: Published
//  Description: Returns the index number of the case with the
//               indicated packed value, or -1 if no case has this
//               value.
////////////////////////////////////////////////////////////////////
int DCSwitch::
get_case_by_value(const string &case_value) const {
  CasesByValue::const_iterator vi;
  vi = _cases_by_value.find(case_value);
  if (vi != _cases_by_value.end()) {
    return (*vi).second;
  }

  return -1;
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::get_case
//       Access: Published
//  Description: Returns the DCPackerInterface that packs the nth case.
////////////////////////////////////////////////////////////////////
DCPackerInterface *DCSwitch::
get_case(int n) const {
  nassertr(n >= 0 && n < (int)_cases.size(), NULL);
  return _cases[n]->_fields;
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::get_default_case
//       Access: Published
//  Description: Returns the DCPackerInterface that packs the default
//               case, or NULL if there is no default case.
////////////////////////////////////////////////////////////////////
DCPackerInterface *DCSwitch::
get_default_case() const {
  return _default_case;
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::get_value
//       Access: Published
//  Description: Returns the packed value associated with the
//               indicated case.
////////////////////////////////////////////////////////////////////
string DCSwitch::
get_value(int case_index) const {
  nassertr(case_index >= 0 && case_index < (int)_cases.size(), string());
  return _cases[case_index]->_value;
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::get_num_fields
//       Access: Published
//  Description: Returns the number of fields in the indicated case.
////////////////////////////////////////////////////////////////////
int DCSwitch::
get_num_fields(int case_index) const {
  nassertr(case_index >= 0 && case_index < (int)_cases.size(), 0);
  return _cases[case_index]->_fields->_fields.size();
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::get_num_fields
//       Access: Published
//  Description: Returns the nth field in the indicated case.
////////////////////////////////////////////////////////////////////
DCField *DCSwitch::
get_field(int case_index, int n) const {
  nassertr(case_index >= 0 && case_index < (int)_cases.size(), NULL);
  nassertr(n >= 0 && n < (int)_cases[case_index]->_fields->_fields.size(), NULL);
  return _cases[case_index]->_fields->_fields[n];
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::get_field_by_name
//       Access: Published
//  Description: Returns the field with the given name from the
//               indicated case, or NULL if no field has this name.
////////////////////////////////////////////////////////////////////
DCField *DCSwitch::
get_field_by_name(int case_index, const string &name) const {
  nassertr(case_index >= 0 && case_index < (int)_cases.size(), NULL);

  const FieldsByName &fields_by_name = _cases[case_index]->_fields->_fields_by_name;
  FieldsByName::const_iterator ni;
  ni = fields_by_name.find(name);
  if (ni != fields_by_name.end()) {
    return (*ni).second;
  }

  return NULL;
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::is_field_valid
//       Access: Public
//  Description: Returns true if it is valid to add a new field at
//               this point (implying that a case or default has been
//               added already), or false if not.
////////////////////////////////////////////////////////////////////
bool DCSwitch::
is_field_valid() const {
  return !_current_fields.empty();
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::add_case
//       Access: Public
//  Description: Adds a new case to the switch with the indicated
//               value, and returns the new case_index.  If the value
//               has already been used for another case, returns -1.
//               This is normally called only by the parser.
////////////////////////////////////////////////////////////////////
int DCSwitch::
add_case(const string &value) {
  int case_index = (int)_cases.size();
  if (!_cases_by_value.insert(CasesByValue::value_type(value, case_index)).second) {
    add_invalid_case();
    return -1;
  }

  SwitchFields *fields = start_new_case();
  SwitchCase *dcase = new SwitchCase(value, fields);
  _cases.push_back(dcase);
  return case_index;
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::add_invalid_case
//       Access: Public
//  Description: Adds a new case to the switch that will never be
//               matched.  This is only used by the parser, to handle
//               an error condition more gracefully without bitching
//               the parsing (which behaves differently according to
//               whether a case has been encountered or not).
////////////////////////////////////////////////////////////////////
void DCSwitch::
add_invalid_case() {
  start_new_case();
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::add_default
//       Access: Public
//  Description: Adds a default case to the switch.  Returns true if
//               the case is successfully added, or false if it had
//               already been added.  This is normally called only by
//               the parser.
////////////////////////////////////////////////////////////////////
bool DCSwitch::
add_default() {
  if (_default_case != (SwitchFields *)NULL) {
    add_invalid_case();
    return false;
  }

  SwitchFields *fields = start_new_case();
  _default_case = fields;
  return true;
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::add_field
//       Access: Public
//  Description: Adds a field to the currently active cases (those
//               that have been added via add_case() or add_default(),
//               since the last call to add_break()).  Returns true if
//               successful, false if the field duplicates a field
//               already named within this case.  It is an error to
//               call this before calling add_case() or add_default().
//               This is normally called only by the parser.
////////////////////////////////////////////////////////////////////
bool DCSwitch::
add_field(DCField *field) {
  nassertr(!_current_fields.empty(), false);

  bool all_ok = true;

  CaseFields::iterator fi;
  for (fi = _current_fields.begin(); fi != _current_fields.end(); ++fi) {
    SwitchFields *fields = (*fi);
    if (!fields->add_field(field)) {
      all_ok = false;
    }
  }
  _nested_fields.push_back(field);
  _fields_added = true;

  return all_ok;
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::add_break
//       Access: Public
//  Description: Adds a break statement to the switch.  This closes
//               the currently open cases and prepares for a new,
//               unrelated case.
////////////////////////////////////////////////////////////////////
void DCSwitch::
add_break() {
  _current_fields.clear();
  _fields_added = false;
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::apply_switch
//       Access: Public
//  Description: Returns the DCPackerInterface that presents the
//               alternative fields for the case indicated by the
//               given packed value string, or NULL if the value
//               string does not match one of the expected cases.
////////////////////////////////////////////////////////////////////
const DCPackerInterface *DCSwitch::
apply_switch(const char *value_data, size_t length) const {
  CasesByValue::const_iterator vi;
  vi = _cases_by_value.find(string(value_data, length));
  if (vi != _cases_by_value.end()) {
    return _cases[(*vi).second]->_fields;
  }

  // Unexpected value--use the default.
  if (_default_case != (SwitchFields *)NULL) {
    return _default_case;
  }

  // No default.
  return NULL;
}

////////////////////////////////////////////////////////////////////
//     Function : DCSwitch::output
//       Access : Public, Virtual
//  Description : Write a string representation of this instance to
//                <out>.
////////////////////////////////////////////////////////////////////
void DCSwitch::
output(ostream &out, bool brief) const {
  output_instance(out, brief, "", "", "");
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::write
//       Access: Public, Virtual
//  Description: Generates a parseable description of the object to
//               the indicated output stream.
////////////////////////////////////////////////////////////////////
void DCSwitch::
write(ostream &out, bool brief, int indent_level) const {
  write_instance(out, brief, indent_level, "", "", "");
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::output_instance
//       Access: Public
//  Description: Generates a parseable description of the object to
//               the indicated output stream.
////////////////////////////////////////////////////////////////////
void DCSwitch::
output_instance(ostream &out, bool brief, const string &prename, 
                const string &name, const string &postname) const {
  out << "switch";
  if (!_name.empty()) {
    out << " " << _name;
  }
  out << " (";
  _key_parameter->output(out, brief);
  out << ") {";

  const SwitchFields *last_fields = NULL;

  Cases::const_iterator ci;
  for (ci = _cases.begin(); ci != _cases.end(); ++ci) {
    const SwitchCase *dcase = (*ci);
    if (dcase->_fields != last_fields && last_fields != (SwitchFields *)NULL) {
      last_fields->output(out, brief);
    }
    last_fields = dcase->_fields;
    out << "case " << _key_parameter->format_data(dcase->_value, false) << ": ";
  }

  if (_default_case != (SwitchFields *)NULL) {
    if (_default_case != last_fields && last_fields != (SwitchFields *)NULL) {
      last_fields->output(out, brief);
    }
    last_fields = _default_case;
    out << "default: ";
  }
  if (last_fields != (SwitchFields *)NULL) {
    last_fields->output(out, brief);
  }

  out << "}";
  if (!prename.empty() || !name.empty() || !postname.empty()) {
    out << " " << prename << name << postname;
  }
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::write_instance
//       Access: Public, Virtual
//  Description: Generates a parseable description of the object to
//               the indicated output stream.
////////////////////////////////////////////////////////////////////
void DCSwitch::
write_instance(ostream &out, bool brief, int indent_level,
               const string &prename, const string &name, 
               const string &postname) const {
  indent(out, indent_level)
    << "switch";
  if (!_name.empty()) {
    out << " " << _name;
  }
  out << " (";
  _key_parameter->output(out, brief);
  out << ") {\n";

  const SwitchFields *last_fields = NULL;

  Cases::const_iterator ci;
  for (ci = _cases.begin(); ci != _cases.end(); ++ci) {
    const SwitchCase *dcase = (*ci);
    if (dcase->_fields != last_fields && last_fields != (SwitchFields *)NULL) {
      last_fields->write(out, brief, indent_level + 2);
    }
    last_fields = dcase->_fields;
    indent(out, indent_level)
      << "case " << _key_parameter->format_data(dcase->_value, false) << ":\n";
  }

  if (_default_case != (SwitchFields *)NULL) {
    if (_default_case != last_fields && last_fields != (SwitchFields *)NULL) {
      last_fields->write(out, brief, indent_level + 2);
    }
    last_fields = _default_case;
    indent(out, indent_level)
      << "default:\n";
  }
  if (last_fields != (SwitchFields *)NULL) {
    last_fields->write(out, brief, indent_level + 2);
  }

  indent(out, indent_level)
    << "}";
  if (!prename.empty() || !name.empty() || !postname.empty()) {
    out << " " << prename << name << postname;
  }
  out << ";\n";
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::generate_hash
//       Access: Public, Virtual
//  Description: Accumulates the properties of this switch into the
//               hash.
////////////////////////////////////////////////////////////////////
void DCSwitch::
generate_hash(HashGenerator &hashgen) const {
  hashgen.add_string(_name);

  _key_parameter->generate_hash(hashgen);

  hashgen.add_int(_cases.size());
  Cases::const_iterator ci;
  for (ci = _cases.begin(); ci != _cases.end(); ++ci) {
    const SwitchCase *dcase = (*ci);
    hashgen.add_string(dcase->_value);

    const SwitchFields *fields = dcase->_fields;
    hashgen.add_int(fields->_fields.size());
    Fields::const_iterator fi;
    for (fi = fields->_fields.begin(); fi != fields->_fields.end(); ++fi) {
      (*fi)->generate_hash(hashgen);
    }
  }

  if (_default_case != (SwitchFields *)NULL) {
    const SwitchFields *fields = _default_case;
    hashgen.add_int(fields->_fields.size());
    Fields::const_iterator fi;
    for (fi = fields->_fields.begin(); fi != fields->_fields.end(); ++fi) {
      (*fi)->generate_hash(hashgen);
    }
  }
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::pack_default_value
//       Access: Public
//  Description: Packs the switchParameter's specified default value
//               (or a sensible default if no value is specified) into
//               the stream.  Returns true if the default value is
//               packed, false if the switchParameter doesn't know how
//               to pack its default value.
////////////////////////////////////////////////////////////////////
bool DCSwitch::
pack_default_value(DCPackData &pack_data, bool &pack_error) const {
  SwitchFields *fields = NULL;
  DCPacker packer;
  packer.begin_pack(_key_parameter);
  if (!_cases.empty()) {
    // If we have any cases, the first case is always the default
    // case, regardless of the default value specified by the key
    // parameter.  That's just the easiest to code.
    packer.pack_literal_value(_cases[0]->_value);
    fields = _cases[0]->_fields;

  } else {
    // If we don't have any cases, just pack the key parameter's
    // default.
    packer.pack_default_value();
    fields = _default_case;
  }    

  if (!packer.end_pack()) {
    pack_error = true;
  }

  if (fields == (SwitchFields *)NULL) {
    pack_error = true;

  } else {
    // Then everything within the case gets its normal default.
    for (size_t i = 1; i < fields->_fields.size(); i++) {
      packer.begin_pack(fields->_fields[i]);
      packer.pack_default_value();
      if (!packer.end_pack()) {
        pack_error = true;
      }
    }
  }

  pack_data.append_data(packer.get_data(), packer.get_length());

  return true;
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::do_check_match_switch
//       Access: Public
//  Description: Returns true if this switch matches the indicated
//               other switch--that is, the two switches are bitwise
//               equivalent--false otherwise.  This is only intended
//               to be called internally from
//               DCSwitchParameter::do_check_match_switch_parameter().
////////////////////////////////////////////////////////////////////
bool DCSwitch::
do_check_match_switch(const DCSwitch *other) const {
  if (!_key_parameter->check_match(other->_key_parameter)) {
    return false;
  }

  if (_cases.size() != other->_cases.size()) {
    return false;
  }

  Cases::const_iterator ci;
  for (ci = _cases.begin(); ci != _cases.end(); ++ci) {
    const SwitchCase *c1 = (*ci);
    CasesByValue::const_iterator vi;
    vi = other->_cases_by_value.find(c1->_value);
    if (vi == other->_cases_by_value.end()) {
      // No matching value.
      return false;
    }
    int c2_index = (*vi).second;
    nassertr(c2_index >= 0 && c2_index < (int)other->_cases.size(), false);
    const SwitchCase *c2 = other->_cases[c2_index];

    if (!c1->do_check_match_switch_case(c2)) {
      return false;
    }
  }

  return true;
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::start_new_case
//       Access: Private
//  Description: Creates a new field set for the new case, or shares
//               the field set with the previous case, as appropriate.
//               Returns the appropriate field set.
////////////////////////////////////////////////////////////////////
DCSwitch::SwitchFields *DCSwitch::
start_new_case() {
  SwitchFields *fields = NULL;

  if (_current_fields.empty() || _fields_added) {
    // If we have recently encountered a break (which removes all of
    // the current field sets) or if we have already added at least
    // one field to the previous case without an intervening break,
    // then we can't share the field set with the previous case.
    // Create a new one.
    fields = new SwitchFields(_name);
    fields->add_field(_key_parameter);

    _case_fields.push_back(fields);
    _current_fields.push_back(fields);

  } else {
    // Otherwise, we can share the field set with the previous case.
    fields = _current_fields.back();
  }

  _fields_added = false;

  return fields;
}


////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::SwitchFields::Constructor
//       Access: Public
//  Description: 
////////////////////////////////////////////////////////////////////
DCSwitch::SwitchFields::
SwitchFields(const string &name) :
  DCPackerInterface(name)
{
  _has_nested_fields = true;
  _num_nested_fields = 0;
  _pack_type = PT_switch;

  _has_fixed_byte_size = true;
  _fixed_byte_size = 0;
  _has_fixed_structure = true;
  _has_range_limits = false;
  _has_default_value = false;
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::SwitchFields::Destructor
//       Access: Public
//  Description: 
////////////////////////////////////////////////////////////////////
DCSwitch::SwitchFields::
~SwitchFields() {
  // We don't delete any of the nested fields here, since they might
  // be shared by multiple SwitchFields objects.  Instead, we delete
  // them in the DCSwitch destructor.
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::SwitchFields::get_nested_field
//       Access: Public, Virtual
//  Description: Returns the DCPackerInterface object that represents
//               the nth nested field.  This may return NULL if there
//               is no such field (but it shouldn't do this if n is in
//               the range 0 <= n < get_num_nested_fields()).
////////////////////////////////////////////////////////////////////
DCPackerInterface *DCSwitch::SwitchFields::
get_nested_field(int n) const {
  nassertr(n >= 0 && n < (int)_fields.size(), NULL);
  return _fields[n];
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::SwitchFields::add_field
//       Access: Public
//  Description: Adds a field to this case.  Returns true if
//               successful, false if the field duplicates a field
//               already named within this case.  This is normally
//               called only by the parser.
////////////////////////////////////////////////////////////////////
bool DCSwitch::SwitchFields::
add_field(DCField *field) {
  if (!field->get_name().empty()) {
    bool inserted = _fields_by_name.insert
      (FieldsByName::value_type(field->get_name(), field)).second;
    
    if (!inserted) {
      return false;
    }
  }

  _fields.push_back(field);

  _num_nested_fields = (int)_fields.size();

  // See if we still have a fixed byte size.
  if (_has_fixed_byte_size) {
    _has_fixed_byte_size = field->has_fixed_byte_size();
    _fixed_byte_size += field->get_fixed_byte_size();
  }
  if (_has_fixed_structure) {
    _has_fixed_structure = field->has_fixed_structure();
  }
  if (!_has_range_limits) {
    _has_range_limits = field->has_range_limits();
  }
  if (!_has_default_value) {
    _has_default_value = field->has_default_value();
  }
  return true;
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::SwitchFields::do_check_match_switch_case
//       Access: Public
//  Description: Returns true if this case matches the indicated
//               case, false otherwise.  This is only intended to be
//               called internally from
//               DCSwitch::do_check_match_switch().
////////////////////////////////////////////////////////////////////
bool DCSwitch::SwitchFields::
do_check_match_switch_case(const DCSwitch::SwitchFields *other) const {
  if (_fields.size() != other->_fields.size()) {
    return false;
  }
  for (size_t i = 0; i < _fields.size(); i++) {
    if (!_fields[i]->check_match(other->_fields[i])) {
      return false;
    }
  }

  return true;
}
    
////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::SwitchFields::output
//       Access: Public
//  Description: 
////////////////////////////////////////////////////////////////////
void DCSwitch::SwitchFields::
output(ostream &out, bool brief) const {
  Fields::const_iterator fi;
  if (!_fields.empty()) {
    fi = _fields.begin();
    ++fi;
    while (fi != _fields.end()) {
      (*fi)->output(out, brief);
      out << "; ";
      ++fi;
    }
  }
  out << "break; ";
}
    
////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::SwitchFields::write
//       Access: Public
//  Description: 
////////////////////////////////////////////////////////////////////
void DCSwitch::SwitchFields::
write(ostream &out, bool brief, int indent_level) const {
  Fields::const_iterator fi;
  if (!_fields.empty()) {
    fi = _fields.begin();
    ++fi;
    while (fi != _fields.end()) {
      (*fi)->write(out, brief, indent_level);
      ++fi;
    }
  }
  indent(out, indent_level)
    << "break;\n";
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::SwitchFields::do_check_match
//       Access: Protected, Virtual
//  Description: Returns true if the other interface is bitwise the
//               same as this one--that is, a uint32 only matches a
//               uint32, etc. Names of components, and range limits,
//               are not compared.
////////////////////////////////////////////////////////////////////
bool DCSwitch::SwitchFields::
do_check_match(const DCPackerInterface *) const {
  // This should never be called on a SwitchFields.
  nassertr(false, false);
  return false;
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::SwitchCase::Constructor
//       Access: Public
//  Description: 
////////////////////////////////////////////////////////////////////
DCSwitch::SwitchCase::
SwitchCase(const string &value, DCSwitch::SwitchFields *fields) :
  _value(value),
  _fields(fields)
{
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::SwitchCase::Destructor
//       Access: Public
//  Description: 
////////////////////////////////////////////////////////////////////
DCSwitch::SwitchCase::
~SwitchCase() {
}

////////////////////////////////////////////////////////////////////
//     Function: DCSwitch::SwitchCase::do_check_match_switch_case
//       Access: Public
//  Description: Returns true if this case matches the indicated
//               case, false otherwise.  This is only intended to be
//               called internally from
//               DCSwitch::do_check_match_switch().
////////////////////////////////////////////////////////////////////
bool DCSwitch::SwitchCase::
do_check_match_switch_case(const DCSwitch::SwitchCase *other) const {
  return _fields->do_check_match_switch_case(other->_fields);
}
