#!/usr/bin/perl

# change_text.pl
# This script modifies text in RUTL-related files to 
# update it to the latest standards. Use to update working
# copies of the source and doc files. For data safety reasons,
# the output files do not replace the original files but instead
# have "wkg_" appended to the start of their names. Be sure to 
# check the files for problems before letting the script continue 
# and replacing the originals with these files.
#
# You modify the doc file to update the doc.
# You modify copies of the older source to get the name changes
# in, so that you can then diff them with the new code to see
# if any functionality has changed. (Since there are so many
# name changes, the diff gets hard to read without doing this.)
#
# Lines with "# DEBUG" report progress and can be deleted without
# affecting functionality.
#
# To lessen unintended renamings, the keys to the change text are
# sorted by longest length (so that the longest text changes are done
# first). For example, for the following:
#    fish    => trout
#    fishies => guppies
# The sorting thus processes fishies first, then fish. Thus:
#    "I like fish but I don't like fishies"
# becomes:
#    "I like trout but I don't like guppies"
# If this sorting was not done, "fish" might be processed before
# "fishies", incorrect changing the sentence to:
#    "I like trout but I don't like trouties"
# This by-length ordering doesn't guarantee everything is changed
# correctly, but it should do the job for most or all identifiers
# in the source code. Warning: If, say, an argument of a function
# and the name of a method happen to use the same name (such as 
# "numBits" but they are changed to different things (such as 
# "num_bits" for the argument and "get_num_bits" for the method),
# this script cannot handle the renaming.
#
# One big limitation is: Do not specify a string that is used in 
# text you do not want changed. For example, if your text used "fisheries" 
# and you do not want to change it, then you cannot specify fish => trout. 
#
# Finally, the script has no knowledge of classes, program structure, or
# anything that requires knowledge of context. Say two classes each have 
# a "getData" method, but for some seemingly valid reason you want to rename 
# class A's getData to get_data and class B's getData to get_info. There is 
# no way the script can figure out the class or context a particular getData
# is used.


use strict;

# List of files to process.
my @procFiles;
$procFiles[0] = "C:\\Astell-THQ\\Helixe\\rutl_doc\\rutl\\rutl_overview.html";

# Changes are made in "working" files without modifying originals until everything succeeds.
# List files in @wkgFiles in same order as in @procFiles (i.e., wkgFiles[0] is the working
# file for procFiles[0].)
my @wkgFiles;
$wkgFiles[0]  = "C:\\Astell-THQ\\Helixe\\rutl_doc\\rutl\\wkg_rutl_overview.html";

my $numFiles  = @procFiles;   # Number of files to be processed.

# The Change List. The text to be changed is used as the keys in the hash,
# and the hash values are what the text should be changed to. (The comments
# track the files the changes originate in. When multiple files are listed, it
# means there were separate identifiers with the same name.)
my %changeList; 
%changeList = (
   "CBUF_ERROR"    => "cbuf_error_t",     # cbuffer
   "CBUF_BASE"     => "cbuf_base_t",      # cbuffer
   "CBUF_LINETERM" => "cbuf_lineterm_t",  # cbuffer
   "ENV_VAR_TYPE"  => "env_var_t",        # aenvir
   "MTBF_ERROR"    => "mtbf_error_t",     # multibuf

   "cEnvirFloatCallback"  => "env_float_callback_t",      # aenvir
   "cEnvirIntCallback"    => "env_int_callback_t",        # aenvir
   "cEnvirStringCallback" => "env_string_callback_t",     # aenvir
   "cGrid"                => "grid_t",                    # agrid
   "cHandleEntry"         => "handle_entry_t",            # uhtable
   "cMultiBufferEntry"    => "multi_buffer_entry_t",      # multibuf
   "cRutlBinTree"         => "rutl_b_tree_t",             # abintree
   "cRutlBinTreeNode"     => "rutl_b_tree_node_t",        # abintree
   "cRutlBitVecLens"      => "rutl_bit_vec_lens_t",       # abitvec
   "cRutlCursorBuffer"    => "rutl_cursor_buffer_t",      # cbuffer
   "cRutlDictionary"      => "rutl_dict_t",               # dict
   "cRutlDNATreeVisitor"  => "rutl_dna_tree_visitor_t",   # dnatree
   "cRutlDUHTable"        => "rutl_duh_table_t",          # uhtable
   "cRutlEnvironment"     => "rutl_env_t",                # aenvir
   "cRutlFixedList"       => "rutl_fixed_list_t",         # fixedlist
   "cRutlMultiBuffer"     => "rutl_multi_buffer_t",       # multibuf
   "cRutlQueue"           => "rutl_queue_t",              # aqueue
   "cRutlRaggedList"      => "rutl_ragged_list_t",        # ragged
   "cRutlSet"             => "rutl_set_t",                # aset
   "cRutlSymbol"          => "rutl_symbol_t",             # symbol
   "cRutlSymbolTable"     => "rutl_symbol_table_t",       # symbol
   "cRutlTinyBTree"       => "rutl_b_tree8_t",            # abintree
   "cRutlTinyTree"        => "rutl_tree8_t",              # atree
   "cRutlTree"            => "rutl_tree_t",               # atree
   "cRutlTreeNode"        => "rutl_tree_node_t",          # atree
   "cRutlMedBTree"        => "rutl_b_tree16_t",           # abintree
   "cRutlMedTree"         => "rutl_tree16_t",             # atree
   "cRutlUHTable"         => "rutl_uh_table_t",           # uhtable
   "cRutlVector"          => "rutl_vector_t",             # avector
   "cSerializable"        => "serializable_t",            # serial
   "cSymTableEntry"       => "sym_table_entry_t",         # symbol

   "addCallback"               => "add_callback",                 # aenvir
   "addChildLeft"              => "add_child_left",               # abintree, atree
   "addChildRight"             => "add_child_right",              # abintree, atree
   "addCursorBuffer"           => "add_cursor_buffer",            # multibuf
   "addExternalHandle"         => "add_external_handle",          # uhtable
   "addRoot"                   => "add_root",                     # abintree, atree
   "adjacentEast"              => "adjacent_east",                # agrid
   "adjacentNorth"             => "adjacent_north",               # agrid
   "adjacentSouth"             => "adjacent_south",               # agrid
   "adjacentWest"              => "adjacent_west",                # agrid
   "associateHandle"           => "associate_handle",             # serial
   "charLessComp"              => "s8_less_comp",                 # aset
   "clearAndResize"            => "clear_and_resize",             # cbuffer
   "clearList"                 => "clear_list",                   # ragged
   "cMultiBufferLessCompare"   => "multi_buffer_less_compare_t",  # multibuf
   "compFunc"                  => "comp_func",                    # dict
   "compLess"                  => "comp_less",                    # aset
   "convertFromByteStripes"    => "convert_from_byte_stripes",    # cbuffer
   "convertHandle"             => "convert_handle",               # serial
   "convertPointer"            => "convert_pointer",              # serial
   "convertToByteStripes"      => "convert_to_byte_stripes",      # cbuffer
   "countBits"                 => "count_bits",                   # uhtable
   "defined"                   => "is_defined",                   # dict
   "domainBits"                => "domain_bits",                  # uhtable
   "dominatedTerminals"        => "dominated_terminals",          # abintree, atree
   "dumpToFile"                => "dump_to_file",                 # cbuffer, multibuf
   "entryLessCompare"          => "entry_less_compare",           # symbol
   "envirFloatCallback"        => "env_float_callback_func_t",    # aenvir
   "envirIntCallback"          => "env_int_callback_func_t",      # aenvir
   "envirStringCallback"       => "env_string_callback_func_t",   # aenvir
   "fileName"                  => "file_name",                    # multibuf
   "firstChild"                => "first_child",                  # abintree, atree
   "firstHandle"               => "first_handle",                 # uhtable
   "floatLessComp"             => "float_less_comp",              # aset
   "getBuffer"                 => "get_buffer",                   # cbuffer, multibuf
   "getCursor"                 => "get_cursor",                   # cbuffer
   "getEnvIdxFloat"            => "get_float",                    # aenvir
   "getEnvIdxInt"              => "get_int",                      # aenvir
   "getEnvIdxString"           => "get_string",                   # aenvir
   "getExistingHandle"         => "get_existing_handle",          # uhtable
   "getLineNum"                => "get_line_num",                 # multibuf
   "getName"                   => "get_name",                     # multibuf
   "getNextIdx"                => "get_next_idx",                 # fixedlist
   "getNumLines"               => "get_num_lines",                # cbuffer
   "getNumTabs"                => "get_num_tabs",                 # cbuffer
   "getOrCreateSymbol"         => "get_or_create_symbol",         # symbol
   "getSize"                   => "get_size",                     # cbuffer
   "getString"                 => "get_string",                   # symbol
   "getTabSize"                => "get_tab_size",                 # cbuffer
   "getValue"                  => "get_value",                    # aenvir
   "hammingLength"             => "hamming_length",               # abitvec
   "idxIsValid"                => "idx_is_valid",                 # aqueue, avector, ragged, abintree, dict
   "insertAfter"               => "insert_after",                 # ragged
   "insertAt"                  => "insert_at",                    # avector
   "insertInList"              => "insert_in_list",               # ragged
   "insertTail"                => "insert_tail",                  # ragged
   "insertUnique"              => "insert_unique",                # avector
   "intLessComp"               => "s32_less_comp",                # aset
   "invalidIndex"              => "invalid_idx",                  # ragged, abintree, atree, dnatree, aenvir
   "invalidHandle"             => "invalid_handle",               # uhtable
   "isDefined"                 => "is_defined",                   # aenvir
   "isEmpty"                   => "is_empty",                     # cbuffer, aqueue, abitvec, avector, abintree, atree
   "isParent"                  => "is_parent",                    # abintree, atree
   "isRoot"                    => "is_root",                      # abintree, atree
   "isSubset"                  => "is_subset",                    # abitvec
   "isTerm"                    => "is_term",                      # abintree, atree
   "isValid"                   => "is_valid",                     # fixedlist, abintree, atree, uhtable, symbol
   "keyIndex"                  => "key_idx",                      # dict
   "keyStore"                  => "key_store",                    # dict
   "largestNode"               => "largest_node",                 # aset
   "largestKey"                => "largest_key",                  # dict
   "lastChild"                 => "last_child",                   # abintree
   "lastId"                    => "last_id",                      # symbol
   "leftChild"                 => "left_child",                   # abintree, aset
   "leftSibling"               => "left_sibling",                 # abintree
   "levelOffset"               => "level_offset",                 # dnatree
   "makeDomain"                => "make_domain",                  # uhtable
   "makeDomainHandle"          => "make_domain_handle",           # uhtable
   "makeDomainId"              => "make_domain_id",               # uhtable
   "makeHandle"                => "make_handle",                  # uhtable
   "makeLocalDomain"           => "make_local_domain",            # uhtable
   "makeLocalHandle"           => "make_local_handle",            # uhtable
   "maxIndex"                  => "max_idx",                      # abintree, atree
   "mBuffer"                   => "m_buffer",                     # multibuf
   "mBuffers"                  => "m_buffers",                    # multibuf
   "mCountBits"                => "m_count_bits",                 # uhtable
   "mDomainTable"              => "m_domain_table",               # uhtable
   "mEmpties"                  => "m_empties",                    # uhtable
   "mEntrySet"                 => "m_entry_set",                  # symbol
   "mFileName"                 => "m_file_name",                  # multibuf
   "mFloatVars"                => "m_float_vars",                 # aenvir
   "mHandle"                   => "m_handle",                     # uhtable
   "mHandles"                  => "m_handles",                    # uhtable
   "mHeight"                   => "m_height",                     # dnatree
   "mId"                       => "m_id",                         # symbol
   "mIntVars"                  => "m_int_vars",                   # aenvir
   "mLineNum"                  => "m_line_num",                   # multibuf
   "mName"                     => "m_name",                       # symbol, multibuf
   "mNodes"                    => "m_nodes",                      # abintree
   "mOffset"                   => "m_offset",                     # abintree
   "mRoot"                     => "m_root",                       # atree
   "mSentinelId"               => "m_sentinel_id",                # serial
   "mSerializeErrorHandler"    => "m_serializer_error_handler",   # serial
   "mStringVars"               => "m_string_vars",                # aenvir
   "mTable"                    => "m_table",                      # symbol
   "mValue"                    => "m_value",                      # uhtable
   "newIdx"                    => "new_idx",                      # abintree
   "newList"                   => "new_list",                     # ragged
   "nextData"                  => "next_data",                    # abitvec
   "nextEmpty"                 => "next_empty",                   # atree
   "nextHandle"                => "next_handle",                  # uhtable
   "nextId"                    => "next_id",                      # symbol
   "nextSibling"               => "next_sibling",                 # abintree, atree
   "numBits"                   => "num_bits",                     # abitvec
   "numBuffers"                => "num_buffers",                  # multibuf
   "numBytes"                  => "num_bytes",                    # abitvec
   "numEmpties"                => "num_empties",                  # fixedlist, atree
   "numEntries"                => "num_entries",                  # aqueue, avector, fixedlist, ragged, atree, dict
   "numLeaves"                 => "num_leaves",                   # dnatree
   "numLists"                  => "num_lists",                    # ragged
   "numNodes"                  => "num_nodes",                    # abintree, dnatree
   "numValidEntries"           => "num_valid_entries",            # fixedlist
   "numValues"                 => "num_values",                   # dict
   "numWords"                  => "num_words",                    # abitvec
   "oldRoot"                   => "old_root",                     # atree
   "padLength"                 => "pad_length",                   # cbuffer
   "peerNumber"                => "peer_number",                  # dnatree
   "pName"                     => "p_name",                       # aenvir
   "popTab"                    => "pop_tab",                      # cbuffer
   "popList"                   => "pop_list",                     # ragged
   "prevSibling"               => "prev_sibling",                 # atree
   "printHandle"               => "print_handle",                 # uhtable
   "pType"                     => "p_type",                       # aenvir
   "pushList"                  => "push_list",                    # ragged
   "pushTab"                   => "push_tab",                     # cbuffer
   "raySource"                 => "ray_source",                   # dnatree
   "readFromFile"              => "read_from_file",               # cbuffer, multibuf
   "readStructuredText"        => "read_structured_text",         # multibuf
   "recPrint"                  => "rec_print",                    # abintree, atree
   "regSym"                    => "reg_symbol",                   # symbol
   "releaseHandle"             => "release_handle",               # uhtable
   "removeAfter"               => "remove_after",                 # ragged
   "removeAt"                  => "remove_at",                    # avector, fixedlist, atree, aset, dict
   "removeBuffer"              => "remove_buffer",                # multibuf
   "removeCallback"            => "remove_callback",              # aenvir
   "removeDomain"              => "remove_domain",                # uhtable
   "removeFromListIdx"         => "remove_from_list_idx",         # ragged
   "removeFromList"            => "remove_from_list",             # ragged
   "removeList"                => "remove_list",                  # ragged
   "removeNode"                => "remove_node",                  # atree
   "removeRegion"              => "remove_region",                # avector
   "removeSubTree"             => "remove_sub_tree",              # abintree, atree
   "removeTail"                => "remove_tail",                  # ragged
   "reserveBits"               => "reserve_bits",                 # uhtable
   "resetSerializationContext" => "reset_serialization_context",  # serial
   "rightChild"                => "right_child",                  # abintree, aset
   "rightSibling"              => "right_sibling",                # abintree
   "rootOf"                    => "root_of",                      # atree
   "runLengthDecode"           => "run_length_decode",            # cbuffer
   "runLengthEncode"           => "run_length_encode",            # cbuffer
   "serialSize"                => "serial_size",                  # cbuffer, aqueue, avector, abintree, atree, aset, serial, uhtable
   "setBase"                   => "set_base",                     # cbuffer
   "setComparisonFunc"         => "set_comparison_func",          # aset
   "setComparisonFunction"     => "set_comparison_function",      # dict
   "setCursor"                 => "set_cursor",                   # cbuffer
   "setData"                   => "set_data",                     # abitvec
   "setEntries"                => "set_entries",                  # avector
   "setFirstChild"             => "set_first_child",              # atree
   "setFirstSymbol"            => "set_first_symbol",             # symbol
   "setLineTermination"        => "set_line_termination",         # cbuffer
   "setListArray"              => "set_list_array",               # ragged
   "setNextempty"              => "set_next_empty",               # atree
   "setNextSibling"            => "set_next_sibling",             # atree
   "setNextSymbol"             => "set_next_symbol",              # symbol
   "setNumBits"                => "set_num_bits",                 # abitvec
   "setNumTabs"                => "set_num_tabs",                 # cbuffer
   "setParent"                 => "set_parent",                   # atree
   "setPrevSibling"            => "set_prev_sibling",             # atree
   "setSerializationErrorHandler" => "set_serialization_error_handler",  # serial
   "setStructure"              => "set_structure",                # dnatree
   "setTable"                  => "set_table",                    # symbol
   "setTabSize"                => "set_tab_size",                 # cbuffer
   "setValue"                  => "set_value",                    # abintree, atree
   "shortLessComp"             => "s16_less_comp",                # aset
   "siblingNumber"             => "sibling_number",               # dnatree
   "sizetLessComp"             => "sizet_less_comp",              # aset
   "sizetLessCompare"          => "sizet_less_compare",           # uhtable
   "smallestKey"               => "smallest_key",                 # dict
   "smallestNode"              => "smallest_node",                # aset
   "symLessCompare"            => "sym_less_compare",             # aenvir
   "symbolLessCompare"         => "symbol_less_compare",          # symbol
   "tweakNode"                 => "tweak_node",                   # dnatree
   "ucharLessComp"             => "u8_less_comp",                 # aset
   "uintLessComp"              => "u32_less_comp",                # aset
   "ushortLessComp"            => "u16_less_comp",                # aset
   "valueIndex"                => "value_idx",                    # dict
   "valueKey"                  => "value_key",                    # dict
   "visitFirstChild"           => "visit_first_child",            # dnatree
   "visitFirstLeaf"            => "visit_first_leaf",             # dnatree
   "visitFirstLevelOrder"      => "visit_first_level_order",      # dnatree
   "visitFirstPreOrder"        => "visit_first_pre_order",        # dnatree
   "visitFirstPostOrder"       => "visit_first_post_order",       # dnatree
   "visitingLastChild"         => "visiting_last_child",          # dnatree
   "visitingLastInLevel"       => "visiting_last_in_level",       # dnatree
   "visitingLeaf"              => "visiting_leaf",                # dnatree
   "visitingRoot"              => "visiting_root",                # dnatree
   "visitNextLeaf"             => "visit_next_leaf",              # dnatree
   "visitNextLevelOrder"       => "visit_next_level_order",       # dnatree
   "visitNextPreOrder"         => "visit_next_pre_order",         # dnatree
   "visitNextPostOrder"        => "visit_next_post_order",        # dnatree
   "visitNextSibling"          => "visit_next_sibling",           # dnatree
   "visitNode"                 => "visit_node",                   # dnatree
   "visitParent"               => "visit_parent",                 # dnatree
   "visitRay"                  => "visit_ray",                    # dnatree
   "visitRoot"                 => "visit_root",                   # dnatree
   "writeAsStaticC"            => "write_as_static_c",            # cbuffer

   "tARAGsIdx"              => "u16",                       # ragged
   "tEnvIdx"                => "u16",                       # aenvir
   "tGridIndex"             => "s32",                       # agrid
   "tPointerHandle"         => "pointer_handle_t",          # serial
   "tSerializeErrorHandler" => "serialize_error_handler_t", # serial
   "tSymSymbolId"           => "u16",                       # symbol

   "UHTAB_INDEX_FROM_HANDLE" => "UHTAB_IDX_FROM_HANDLE", # uhtable
   "UHTAB_INDEX_IS_VALID"    => "UHTAB_IDX_IS_VALID",    # uhtable
);
# The following were removed from the list as proven or potential problem names
#   "defined"     => "is_defined",     # dict Removed because it's a common word too likely
# to be used in contexts outside the rutl_dict_t method name.
#   "symbolTable" => "symbol_table",   # symbol Removed because it seemd to affect cSymTableEntry?!

my @changeOrder = reverse sort keys( %changeList );
my $changeText;
my $response;
 
my $i;
for ( $i = 0; $i < $numFiles; $i++ )
{
   ChangeText();
}

print "\nALL CHANGES DONE!\nPlease check out the following files:\n"
   . "   @wkgFiles \nPress one of the following:\n"
   . "y to replace the original files with these files\n"
   . "d to just delete the working files without replacing the originals\n"
   . "q or anything to quit without doing anything more\n\n"
   . "Your choice (y/d/q)? ";
$response = ;
chomp $response;

if ( $response eq "y" )
{
   for ( $i = 0; $i < $numFiles; $i++ )
   {
      rename( "$wkgFiles[$i]", "$procFiles[$i]" )
         or die "$wkgFiles[$i] could not be renamed $procFiles[$i], check out what is going on: $!\n";
      print "$wkgFiles[$i] was renamed $procFiles[$i]\n";   # DEBUG
   }
   exit;
} elsif ( $response eq "d" )
{
   for ( $i = 0; $i < $numFiles; $i++ )
   {
      unlink( "$wkgFiles[$i]" )
         or die "$wkgFiles[$i] could not be deleted: $!\n";
      print "$wkgFiles[$i] was deleted\n";   # DEBUG
   }
   exit;
} else
{
   exit;
}


sub ChangeText
{
   my $line;
   open( IN, "$procFiles[$i]" )
      or die "Cannot open $procFiles[$i]: $!\n";
   print "Opened for reading $procFiles[$i]\n";   # DEBUG

   if ( -e $wkgFiles[$i] )
   {
      print "\nWARNING!\n$wkgFiles[$i] already exists. It will be overwritten "
         . "if you continue. Do you want to continue (y/any)? ";
      $response = ;
      chomp $response;
      unless ( $response eq "y" )
      {
         exit;
      }
   }
   open( OUT, ">$wkgFiles[$i]" )
      or die "Cannot open $wkgFiles[$i]: $!\n";
   print "Opened for writing $wkgFiles[$i]\n";   # DEBUG

   while (  )
   {
      $line = $_;
      foreach $changeText ( @changeOrder )
      {
         $line =~ s/$changeText/$changeList{$changeText}/g;
      }
      print OUT $line;
   }
   print "$wkgFiles[$i] now contains the changed text\n";   # DEBUG
   close( IN )
      or warn "Cannot close $procFiles[$i]: $!\n";
   print "Closed $procFiles[$i]\n";   # DEBUG
   close( OUT )
      or warn "Cannot close $wkgFiles[$i]: $!\n";
   print "Closed $wkgFiles[$i]\n\n";   # DEBUG
}