#!/usr/bin/perl

#############################################################################
# File Name:          pdbparser.pl
# Contents:           PDBParser will convert a Bioinformatics's PDB file 
#                     format to xml format, based on a supplied DTD.
#                     
# Author:             Catalina Price
# Creation Date:      20040308
# Code Origination:   Catalina Price
# Origination Date:   20040308
# Last Modified by:   Catalina Price
# Modification Date:  20050515
# Project:            URI(tm) Universal Research Interchange Format 
# Legal:              Copyright (C) 2004, URI, Bioinformatics, CSC592 
#############################################################################

########################## PERL LG. INFO   ##################################
#  Perl:
#  This program has been authored using the version of Perl listed below.
#
#############################################################################
#>perl -v
#This is perl, v5.6.1 built for MSWin32-x86-multi-thread
#(with 1 registered patch, see perl -V for more detail)

#Copyright 1987-2001, Larry Wall

#Binary build 631 provided by ActiveState Tool Corp. http://www.ActiveState.com
#Built 17:16:22 Jan  2 2002
#Perl may be copied only under the terms of either the Artistic License or the
#GNU General Public License, which may be found in the Perl 5 source kit.

#Complete documentation for Perl, including FAQ lists, should be found on
#this system using `man perl' or `perldoc perl'.  If you have access to the
#Internet, point your browser at http://www.perl.com/, the Perl Home Page.

#>perl -V
#Summary of my perl5 (revision 5 version 6 subversion 1) configuration:
#  Platform:
#    osname=MSWin32, osvers=4.0, archname=MSWin32-x86-multi-thread
#    uname=''
#    config_args='undef'
#    hint=recommended, useposix=true, d_sigaction=undef
#    usethreads=undef use5005threads=undef useithreads=define usemultiplicity=define
#    useperlio=undef d_sfio=undef uselargefiles=undef usesocks=undef
#    use64bitint=undef use64bitall=undef uselongdouble=undef
#  Compiler:
#    cc='cl', ccflags ='-nologo -O1 -MD -DNDEBUG -DWIN32 -D_CONSOLE -DNO_STRICT -DHAVE_DES_FCRYPT  -DPERL_IMPLICIT_CONTEXT -DPERL_IMPLICIT_SYS -DP
#ERL_MSVCRT_READFIX',
#    optimize='-O1 -MD -DNDEBUG',
#    cppflags='-DWIN32'
#    ccversion='', gccversion='', gccosandvers=''
#    intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234
#    d_longlong=undef, longlongsize=8, d_longdbl=define, longdblsize=10
#    ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=4
#    alignbytes=8, usemymalloc=n, prototype=define
#  Linker and Libraries:
#    ld='link', ldflags ='-nologo -nodefaultlib -release  -libpath:"C:\Perl\lib\CORE"  -machine:x86'
#    libpth="C:\Perl\lib\CORE"
#    libs=  oldnames.lib kernel32.lib user32.lib gdi32.lib winspool.lib  comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib  netapi32.li
#b uuid.lib wsock32.lib mpr.lib winmm.lib  version.lib odbc32.lib odbccp32.lib msvcrt.lib
#    perllibs=  oldnames.lib kernel32.lib user32.lib gdi32.lib winspool.lib  comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib  netapi3
#2.lib uuid.lib wsock32.lib mpr.lib winmm.lib  version.lib odbc32.lib odbccp32.lib msvcrt.lib
#    libc=msvcrt.lib, so=dll, useshrplib=yes, libperl=perl56.lib
#  Dynamic Linking:
#    dlsrc=dl_win32.xs, dlext=dll, d_dlsymun=undef, ccdlflags=' '
#    cccdlflags=' ', lddlflags='-dll -nologo -nodefaultlib -release  -libpath:"C:\Perl\lib\CORE"  -machine:x86'


#Characteristics of this binary (from libperl):
#  Compile-time options: MULTIPLICITY USE_ITHREADS PERL_IMPLICIT_CONTEXT PERL_IMPLICIT_SYS
#  Locally applied patches:
#        ActivePerl Build 631
#  Built under MSWin32
#  Compiled at Jan  2 2002 17:16:22
#  @INC:
#    c:/Perl/lib
#    c:/Perl/site/lib
########################## END PERL LG. INFO   ##################################
#################################################################################

##########################################################
# Current draw backs in reading a DTD:
##########################################################
# 1. The pdbparser does not handle NameSpaces
# 2. The pdbparser does not handle multiple attributes
#    placed in a single !ATTLIST tag.

##########################################################
# Local system includes.
##########################################################
# 'use' is equiv to #include in C 
use strict; ## similar to strong typechecking in C; (example variables have to be explicitly declared)
use Cwd; ## source code module: "current working directory" - gives functions regarding the cwd (ex: 'cddir' func for change directory)
use IO::Handle;        # NT appears to not be autoflushing
STDERR->autoflush(1);  # STDERR, so we do it explicitly. (so that writing to file is done "real-time"-no OS-controlled buffering)

use pdb_dtd_table;  
##########################################################
#  Debugging  variables: 
#  1 = TRUE  Sends all output to screen.
#  0 = FALSE Sends all output to logfile
##########################################################
    my $bRunTimeDebug = 0;
    my $bVerify = 0;
    my $bLineProcess = 0;
    my $bQStat = 0; ## these first four are debugging vars that control what debugging output will be printed to the screen
    my $bDBCommentsAllowedInPDBFile  = 1; # Allows "#" comments to exist (and be ignored when parsed) in a PDB file.
##########################################################

##########################################################
# Prototypes.
##########################################################
# 'sub' in perl is the convention to declare a function prototype

    ################################################################################################
    ###########                             DTD Functions                                ###########
    ################################################################################################
sub ReadDTDFile;
sub BuildDTDTree;
sub ReviewDTDTreeForErrors;
    ################################################################################################
    ###########                             PDB Functions                                ###########
    ################################################################################################
    ############################################################################
    ###########        Divide And Conquer                            ###########
    ############################################################################
sub ReadPDBFile;
sub CalculatePhiPsiAngles;
sub ParseAtomLine;
sub dihedral;
sub BuildPDBTree; ## builds the tree based on master DTD tree definition
sub ReviewSingle;
sub ReviewSingleCont;
sub ReviewMultiple;
sub ReviewMultipleCont;
sub VisitPDBNode; ## is called to check if a found PDB record is corresponding to some DTD element-node in the DTD tree
sub ReviewSingleContVisit;
sub ReviewMultipleContVisit;
sub ReviewOther;
sub ProcessSEQRES;
    ############################################################################
    ###########                ProcessLine Functions                 ###########
    ############################################################################
sub ProcessLine;
sub UpdatePivotPoint;
    ############################################################################
    ###########        Node & Record State Functions                 ###########
    ############################################################################
sub AdjustLineToMasterPivot;
sub GetPrevFieldToMasterPivot;
sub GetMultiKeyOfLineMatchingPDBNode;
sub GetNewMasterPivot;
sub GetMultiKeyAndMasterPivotForNode; #c? old
sub CompareFieldsOfLineToNextBasedOnMKeys;
    ############################################################################
    ###########        PDB Creation and Access Functions             ###########
    ############################################################################
sub CreatePDBNode;
sub GetNewRecordLine; # creates mem to store that new line
sub GetCopyOfNextRecord;
sub PeekAtNextRecordName; ## reads the pdb file and finds out what the rec type is field 1_6
sub AdjustRecordNameForGroupType;
    ############################################################################
    ###########        PDB DTD table access Functions                ###########
    ############################################################################
sub GetRecordField;         #To get a particular field from a record. 
sub GetPDBToDTDField;
    ############################################################################
    ###########        Specialty Functions                           ###########
    ############################################################################
sub SortRecordFormatFields;
sub PDB1LetterSeqsEx;
sub PDB1LetterSeqs;
sub RemoveOccurrenceSign;
sub MoveChildToProcessedList;
sub ConvertSecondsToTime;
    ################################################################################################
    ###########                          Interface Functions                             ###########
    ################################################################################################
sub PrintLineReport;
sub PrintNodeReport;
sub QuickStat;
sub PrintVersion;
sub GetFileName;
sub GetUserResponse;
sub BuildPrintableXMLFromPDBTree;
sub PrintXMLFile;
sub PrintFormatList;
sub PrintAllDTDGlobalList;

##########################################################
#  PDB PARSER TABLE - Configuration Infomation.
##########################################################

#########################################
# Record Type definitions and their values
#########################################
## Key
my $REC_TYPE         = 'RecType';    #  Type of record specified.
my $REF_MULTI_KEY    = 'RefMultiKey';#
my $REF_GROUP_KEY    = 'RefGroupKey';# For records of type REC_GROUP
my $REF_KEY_ORDER    = 'RefKeyOrder';#
my $REF_FIELD        = 'refFieldHash';# Ref to the Record Field data Hash.
my $REF_SPECIAL      = 'refSpecial';
#########################################
## The keys of the Record Field data Hash are preset field column locations.
## The Values are the corresponding DTD associations from the DTD file.

## Values
my $REC_SINGLE        = 'RecSingle';    #May appear only once, otherwise duplicate error.
my $REC_SINGLE_CONT   = 'RecSingleCont';#May logically appear once over multiple lines otherwise duplicate error. 
                                        #Subsequent lines contain a continuation field an incrementing counter.
my $REC_MULTIPLE      = 'RecMultiple';  #May appear multiple times, often the information is in list form and is not 
                                        #logically concatenated. These record types usually have a custom serialization
                                        #to denote order and connect to other record types. 
my $REC_MULTIPLE_CONT = 'RecMultipleCont';#May appear multiple times and logically over multiple lines.  Subsequent 
                                          #lines contain a continuation field an incrementing counter.
my $REC_GROUP         = 'RecGroup';     # There are three record types used to group other records. {REMARK: REMARK1, REMARKn}
                                        # records surround groups of ATOM, HETATM, SIGATM, ANISOU, SIGUIJ, and TER 
                                        # records. TER records indicate the end of a chain.
my $REC_OTHER         = 'RecOther';     #The remaining record types have a detailed inner structure. 
#########################################
## Key
my $EXIST_TYPE        = 'ExistType';    #Existence requirement.
## Values
my  $EXIST_REQUIRED   = 'ExistRequired';#Existence Required
my  $EXIST_OPTIONAL   = 'ExistOptional';#Existence Optional
my  $EXIST_DEFERED    = 'ExistDefered'; #Existence Defered to the next sub-recored.
#########################################
## Key
my $LOGICAL_REC_COUNT = 'LogicalRecCount';  #How many logical records occurred. #c?
## Values is iteratively set at run-time.
#########################################
## Key
my $FUNCTION_NAME    = 'FunctionName';
my $REF_ACTION       = 'RefAction';     # Ref to the ACTION hash.
my $ACTION           = 'Action';        # The type of operation to perform, and criteria if warranted.
my $TOKEN            = 'Token';         # A char string to act upon.
## Values
my $READ             = 'Read';    # Read and copy the data as is.
my $CONCAT           = 'ConCat';  # ????????????????????????????????????????????????????????????????????????????????
my $SEARCH           = 'Search';  # Determine the record type by $TOKEN. 
my $PARSE            = 'Parse';   # Parse the record's data denoted by $TOKEN. 
my $PARSE_TO_MULTI_CHILDREN = 'ParseToMultiChildren';#Allows w/ MKey to
# Definition of MKey
#if Line Processed, Matches Next on some fields and a MKey's Data (elem names) matches current Node, then if at same level of match get the next record,
#since same type, that should pivot more on an inner field.

#REC_SINGLE:        $ACTION  $TOKEN
#                   $READ

#REC_MULTIPLE:      $ACTION  $TOKEN
#                   $READ

#REC_SINGLE_CONT:   $ACTION  $TOKEN
#                   $CONCAT  $TOKEN => '32_70' # Get all the data found in the specified fields denoted by TOKEN on multiple lines of 
#                                              # the continued record and place all gathered data in one element's pcdata.
#                   $PARSE   $TOKEN => '11_70' # Get all the data found in the specified fields denoted by TOKEN on multiple lines of 
#                                              # the continued record and create a child element for each piece of data found.

#REC_MULTIPLE_CONT: $ACTION  $TOKEN
#                   $PARSE,  $TOKEN => '40_45' # Master Pivot on Pocessing line
#                   $SEARCH, $TOKEN => '8_11' 


#$REC_OTHER:        $ACTION  $TOKEN
#                   $READ

#########################################
# PDB Parser Table
#########################################

my $refPDB_DTD_TABLE = GetPDB_DTDTable();
my %PDB_DTD_TABLE = %{$refPDB_DTD_TABLE};

##########################################################
#  END OF: PDB PARSER TABLE - Configuration Infomation.
##########################################################
#########################################
#
# Residue
#
#########################################
## Key
my $RESIDUE_NAME         = 'ResidueName';
my $THREE_LETTER_RESIDUE = 'ThreeLetterRedidue';
my $ONE_LETTER_RESIDUE   = 'OneLetterRedidue';
my $PHI_ANGLE            = 'PhiAngle';
my $PSI_ANGLE            = 'PsiAngle';
my $RAMACHANDRAN         = 'Ramachandran';
my $RESIDUE_WEIGHT       = 'ResidueWeight';
my $RESIDUE_FORMULA      = 'ResidueFormula';
my $HYDROPHOBICITY_HOPP_WOODS     = 'HydrophobicityHoppWoods';
my $HYDROPHOBICITY_KYTE_DOOLITTLE = 'HydrophobicityKyteDoolittle';

my $refSEQRESTable = GetSEQRESTable();
my %SEQRES_TABLE = %{$refSEQRESTable};
##########################################################
#  DTD - Type Definition Section 
##########################################################

#########################################
# Parse Entry for DTD #c?
# Write Entry for XML. #c?
#########################################

    my $EMPTY_SIGN = '';         # (element-content)  Content must occur once, and only once. 
    my $PLUS_SIGN= '+';          # (element-content+) Content must occur one or more times. 
    my $MULTIPLE_SIGN = '*';     # (element-content*) Content can occur zero or more times. 
    my $QUESTIONMARK_SIGN = '?'; # (element-content?) Content can occur zero or one times. 
#########################################
# General Hash Entry Types
#########################################
## Hash Entry Types - %ElementTreeNode

    my %g_DTDDeclareSyntax = ( 
        'Element'   => '<!ELEMENT', #Syntax: <!ELEMENT element-name category> or <!ELEMENT element-name (element-content)>
        'Attribute' => '<!ATTLIST', #Syntax: <!ATTLIST element-name attribute-name attribute-type default-value>
        'Entity'    => '<!ENTITY',  #Syntax: <!ENTITY  entity-name "entity-value">
        );

##########################################################
#  General Hash and Hash Entry Definitions Section 
##########################################################

#########################################
# General Hash Entry Types
#########################################
## Hash Entry Types - %ElementTreeNode
    my $ELEMENT_NAME                = 'ElementName'; # used (in combination with the 'use strict') to avoid typos that might lead Perl into creating $ variables on the fly; same comment goes for all my $SOME-FLAG-NAME-IN-CAPITALS that are declared in this section
    my $ELEMENT_CATEGORY            = 'ElementCategory';
    my $ELEMENT_LINE_NUM            = 'ElementLineNum';
    my $ref_MYNODE                  = 'refMyNode';
    my $ref_PARENTNODE              = 'refParentNode';
    my $ref_CHILDNODE_LIST          = 'refChildNodeList';
    my $ref_ATTRIBUTE_LIST          = 'refAttributeList';
    my $ref_ATTRIBUTE_NAME_LIST     = 'refAttributeNameList';
    my $BEGIN_TAG                   = 'BeginTag'; 
    my $PCDATA                      = 'PCData';
    my $END_TAG                     = 'EndTag';

## Element Category (s)
    my $ELEM_CAT_LIST               = 'LIST';
    my $ELEM_CAT_PND_PCDATA         = '#PCDATA';
    my $ELEM_CAT_ANY                = 'ANY';
    my $ELEM_CAT_EMPTY              = 'EMPTY';

#########################################
# ATTRIBUTES TYPES/DEFAULT VALUES
#########################################
## ATTRIB Value types                             Explanation
    my $ATTRIB_TYPE_CDATA           = 'CDATA';    #The value is character data.
    my $ATTRIB_TYPE_ENUM            = 'ENUM';     #The value must be one from an enumerated list.
    my $ATTRIB_TYPE_ID              = 'ID';       #The value is a unique id.
    my $ATTRIB_TYPE_IDREF           = 'IDREF';    #The value is the id of another element.
    my $ATTRIB_TYPE_IDREFS          = 'IDREFS';   #The value is a list of other ids.
    my $ATTRIB_TYPE_NMTOKEN         = 'NMTOKEN';  #The value is a valid XML name.
    my $ATTRIB_TYPE_NMTOKENS        = 'NMTOKENS'; #The value is a list of valid XML names.
    my $ATTRIB_TYPE_ENTITY          = 'ENTITY';   #The value is an entity.
    my $ATTRIB_TYPE_ENTITIES        = 'ENTITIES'; #The value is a list of entities.
    my $ATTRIB_TYPE_NOTATION        = 'NOTATION'; #The value is a name of a notation.
    my $ATTRIB_TYPE_XML             = 'xml:';     #The value is a predefined xml value

## ATTRIB Default Value types  
    my $ATTRIB_DEFVALUE_REQUIRED    = '#REQUIRED';#The attribute value must be included in the element
    my $ATTRIB_DEFVALUE_IMPLIED     = '#IMPLIED'; #The attribute does not have to be included
    my $ATTRIB_DEFVALUE_FIXED       = '#FIXED';   #value ??????????? The attribute value is fixed

##########################################################
#   END OF: DTD - Type Definition Section 
##########################################################

##########################################################
#   PDB - Type Definition Section
##########################################################

#########################################
# PDBInstanceTree Exclusive Hash Entry Types
#########################################
my $NODE_VISIT_STATUS  = 'NodeVisitStatus';

## Values
my $VISIT_STATUS_WHITE = 'White';
my $VISIT_STATUS_GREY  = 'Grey';
my $VISIT_STATUS_BLACK = 'Black';
#########################################
my $NODE_STATUS        = 'NodeStatus';

## Values
my $SATISFIED         = 'Satisfied';
my $NOT_SATISFIED     = 'NotSatisfied';

##########################################################
#   END OF: DTD - Type Definition Section 
##########################################################

#########################################
# LineInfo Exclusive Hash Entry Types
#########################################
## Hash Entry Types - %LineInfo
#******** LineInfo: ********
    my $RECORD_NAME        = 'RecordName';     #The name of the record found in column 1-6.
    my $ELEMENT_NAME       = 'ElementName';    #The name of the corresponding element in the DTD.
    my $RECORD_TYPE        = 'RecordType';     #The type of record: REC_SINGLE,REC_SINGLE_CONT, ...
    my $PDB_LINE           = 'PDBLine';        #A line from the PDB file.
    my $ref_FIELD_HASH     = 'refFieldHash';   #The record hash for association of field keys and DTD Node entries.
    my $KEY_COUNT          = 'KeyCount';       #The total number of keys in the master copy ie ref_KEYS.
    my $ref_KEYS           = 'refKeys';        #A master copy of all keys of the line defined by the table record.
    my $ref_CURR_KEYS      = 'refCurrKeys';    #Current unprocessed keys of the line
    my $ref_USED_KEYS      = 'refUsedKeys';    #Current processed keys of the line
#**Current Pivot Data** 
    my $PIVOT_INDEX        = 'PivotIndex';     #Index to the key list denoting the line's column field being accessed.
    my $PIVOT_KEY          = 'PivotKey';       #The key denoting the line's column field being accessed.
    my $PIVOT_ENTRY        = 'PivotEntry';     #The Data at the denoted line's column field.
    my $MASTER_PIVOT_KEY   = 'MasterPivotKey'; #The first column field where continuous data is accessed.
#**Record Pivot Data**
    my $MULTIKEY_STATE     = 'MultiKeyState';  #A logical Pivot boundry between records, its value denoting
                                               #the quantity of keys comprising the multi keyed, otherwise zero.
    my $GEN_MKEY           = 'MKey';           #Generic Key name.
    my $GEN_MKEY_FIELD_DATA= 'MKeyFieldData';  #Generic Key to denote a field.
    my $MKEY1              = "${GEN_MKEY}1";   #The first field key to denote the first logical discrete boundry.
    my $MKEY_FIELD_DATA1   = "${GEN_MKEY_FIELD_DATA}1"; #The record field data found at multi key 1.
    my $MKEY2              = "${GEN_MKEY}2";   #The second field key to denote the second logical discrete boundry.
    my $MKEY_FIELD_DATA2   = "${GEN_MKEY_FIELD_DATA}2"; #The record field data found at multi key 2.
    my $MKEY3              = "${GEN_MKEY}3";   #The thrid field key to denote the third logical discrete boundry.
    my $MKEY_FIELD_DATA3   = "${GEN_MKEY_FIELD_DATA}3"; #The record field data found at multi key 3.
    my $MKEY4              = "${GEN_MKEY}4";   #The fourth field key to denote the third logical discrete boundry.
    my $MKEY_FIELD_DATA4   = "${GEN_MKEY_FIELD_DATA}4"; #The record field data found at multi key 4.
    my $MKEY5              = "${GEN_MKEY}5";   #The fifth field key to denote the third logical discrete boundry.
    my $MKEY_FIELD_DATA5   = "${GEN_MKEY_FIELD_DATA}5"; #The record field data found at multi key 5.


#**Entry ID Count**
    my $ENTRY_ID_COUNT     = 'EntryIDCount';   #The count to denote the number of elements of a list.
#*************
# Line Status:  
    #########################################
    ## Key
    my $LINE_STATUS        = 'LineStatus';   #The Line's process status.
    ## Values
    my  $NEED_LINE         = 'NeedLine';     #
    my  $UNPROCESSED       = 'UnProcessed';  #
    my  $PROCESSING        = 'Processing';   #
    my  $PROCESSED         = 'Processed';    #
#########################################

#########################################
#### Residue flags
#########################################
    my  $RESIDUE_SEQ_NUM   = 'ResidueSeqNum'; #
    my  $PHI               = 'Phi';           #
    my  $PSI               = 'Psi';           #
    my  $RAMACHANDRAN      = 'Ramachandran';  #

#########################################

## ERROR Types
    my $ERROR_DTD_NOERROR = 0;
    my $ERROR_DTD_READ    = 1;
    my $ERROR_DTD_BUILD   = 2;
#####################################33

##########################################################
# Internal: Global Flags and Variables.  READ ONLY 
##########################################################
    my $PDB_EXT                                = "ent";
    my $DTD_EXT                                = "dtd";
    my $DTD_LINENUM                            = "DTDLine:";
    my $PDB_PARSER_VERSION                     = "2.0-1";#PDBParser Version control number.
    my $PDB_REC_NAME_FIELD                     = '1_6';
    my $DTD_ELEM_NAME_FIELD                    = '1_6';

    my $FileNamePDB                            = "";
    my $FileNameDTD                            = "";
    my $FileNameXML                            = "";
    my $junk                                   = "";
    my $g_TreeRoot                             = "ROOT";
    my $g_RootElement                          = "";
    my $g_RootLineNum                          =  0;
    my $REC_CONT                               = "CONT";
    my $LINE_SPACE                             =  2;
    my $PDB_ID                                 = "pdb_id";
    my $g_pdb_id                               = "";
    my $bPrintXMLToScreen                      = 0; 
    my $bPrintConvertedSequence                = 0;  ## last two are logical internal variable to control printing to screen
    my @g_ElementDeclarationList               = (); ## list of all complete declarations of all DTD elements
    my @g_ElementNameList           = (); # list of all DTD element names(ex: uri_protein)
    my @g_RealizedAssociatedElementNameList    = (); ## list of all DTD element names that are placed in the DTD tree
    my $g_RealizedAssociatedElementNameCount   =  0; ## 
    my $g_RealizedAssociatedElementNameReusedCount = 0; #20050424
    my $g_ProclaimedAssociatedElementCount     =  0; ##? 

    my @g_AttributeDeclarationList             = (); ## list of all complete declarations of all DTD attributes
    my @g_AttributeNameList         = ();  # list of all DTD attribute names
    my $g_AttributesAssociatedWithElementCount =  0; #
    my $g_AttributesAssociatedWithElementReusedCount = 0;
    my @g_AttributesAssociatedWithElements     = (); #

    my @g_EntityDeclarationList                = ();
    my @g_EntityNameList                       = ();

    my @g_PDBMasterRecordFileList              = (); # the complete file listing
    my @g_PDBRecordFileList                    = (); # a copy of the above 
    my $g_bLongFile                            =  0;
    my @g_PrintableXMLFile                     = (); # walk the pdb tree and gather the info for xml
    my %g_PhiPsiChainHash                      = (); #MUST BE EXPLICITLY INIT'ED TO ()

    exit(!MainFunction());		 

    ################################################################################################
    ###########                                                                          ###########
    ###########                             Main Section                                 ###########
    ###########                                                                          ###########
    ################################################################################################

#########################################################
# Main()
#########################################################
sub MainFunction{

    my %DTDTree             = ($ELEMENT_NAME       => '',
                               $ELEMENT_CATEGORY   => '',
                               $ELEMENT_LINE_NUM   => '',
                               $ref_MYNODE         => '',
                               $ref_PARENTNODE     => '',
                               $ref_CHILDNODE_LIST => '',
                               $ref_ATTRIBUTE_NAME_LIST => '',
                               $ref_ATTRIBUTE_LIST => '',
                               $BEGIN_TAG          => '',
                               $PCDATA             => '',
                               $END_TAG            => ''); # we declare a dtd tree

    my %PDBInstanceTree     = ($ELEMENT_NAME       => '',
                               $ELEMENT_CATEGORY   => '',
                               $ELEMENT_LINE_NUM   => '',
                               $ref_MYNODE         => '',
                               $ref_PARENTNODE     => '',
                               $ref_CHILDNODE_LIST => '',
                               $ref_ATTRIBUTE_NAME_LIST => '',
                               $ref_ATTRIBUTE_LIST => '',
                               $BEGIN_TAG          => '',
                               $PCDATA             => '',
                               $END_TAG            => '',
                               $NODE_STATUS        => '',
                               $NODE_VISIT_STATUS  => ''); # we declare a pdb tree

    my %LineInfo            = ($RECORD_NAME      => '',
                               $ELEMENT_NAME     => '',
                               $RECORD_TYPE      => '',
                               $PDB_LINE         => '',
                               $ACTION           => '',
                               $ref_FIELD_HASH   => '',
                               $KEY_COUNT        => '',
                               $ref_KEYS         => '',
                               $ref_CURR_KEYS    => '',
                               $ref_USED_KEYS    => '',
                               $PIVOT_INDEX      => '',
                               $PIVOT_KEY        => '',
                               $PIVOT_ENTRY      => '',
                               $MASTER_PIVOT_KEY => '',
                               $MULTIKEY_STATE   => '',
                               $MKEY1            => '',
                               $MKEY_FIELD_DATA1 => '',
                               $MKEY2            => '',
                               $MKEY_FIELD_DATA2 => '',
                               $MKEY3            => '',
                               $MKEY_FIELD_DATA3 => '',
                               $MKEY4            => '',
                               $MKEY_FIELD_DATA4 => '',
                               $MKEY5            => '',
                               $MKEY_FIELD_DATA5 => '',
                               $ENTRY_ID_COUNT   => '',
                               $LINE_STATUS      => ''); # we declare a LineInfo

    my @EmptyDTDAttributeNameList = (); 
    my @EmptyDTDAttributeList  = (); 
    my $FILE                = "";
    my $FileLenght          =  0;
    my $RunTime             =  0;
    my $TimeAdj             =  0;
    my $StatusResult        = ""; # of what failed
    my @StatusResultMsg     = ();
    my $ReturnStatus        = "";

    PrintVersion();

    if ($bRunTimeDebug|$bVerify|$bLineProcess|$bQStat){
        STDERR->print("\nRunTime Modes that have been enbled:\n");
        if ($bRunTimeDebug){STDERR->print("bRunTimeDebug\n");}
        if ($bVerify){STDERR->print("bVerify\n");}
        if ($bLineProcess){STDERR->print("bLineProcess\n");}
        if ($bQStat){STDERR->print("bQStat\n");}
    }#if
    #############################################
    ####  User Response Section
    #############################################

    STDERR->print("\nShould this run produce a XML file, a Converted Sequences, or phi,psi,Ramachandran?\n");
    my $UserResponse = GetUserResponse("Your response to the question is invalid.\n", 0, 1, ('XML','Sequence', 'phipsi'));
    if ($UserResponse eq "Sequence"){
        $FileNamePDB =  GetFileName($PDB_EXT);
        PDB1LetterSeqs(1, \$FileNamePDB);
        STDERR->print("\n**** PDB Parser has completed with Success.\n");
        $ReturnStatus = 1;
        return($ReturnStatus);
    }#if
    if ($UserResponse eq "phipsi"){
        $FileNamePDB =  GetFileName($PDB_EXT);
       ($StatusResult, @StatusResultMsg) = ReadPDBFile($FileNamePDB);
       if ( 0 == $StatusResult){
           $ReturnStatus = $StatusResult;
           STDERR->print("@StatusResultMsg\n");
           STDERR->print("PDB Parser has exited due to PDB errors.\n");
           return($ReturnStatus);
       }#if
        CalculatePhiPsiAngles(1);
        STDERR->print("\n**** PDB Parser has completed with Success.\n");
        $ReturnStatus = 1;
        return($ReturnStatus);
    }#if

    $FileNamePDB =  GetFileName($PDB_EXT);
    $FileNameDTD =  GetFileName($DTD_EXT);
    ($FileNameXML,$junk) = split( /\./,$FileNamePDB);
    $FileNameXML = "${FileNameXML}.xml";
    STDERR->print("\nThe generated XML file name will be named: $FileNameXML\n");
    STDERR->print("\nShould the XML file be printed to the screen as well?\n");
    if ( "y" eq GetUserResponse("Your response to the question is invalid.\n", 0, 1, ('y','n'))){
        $bPrintXMLToScreen = 1;
    }#if
#    STDERR->print("\nShould Converted Sequences be printed if found?\n");
#    if ( "y" eq GetUserResponse("Your response to the question is invalid.\n", 1, 1, ('y','n'))){
#        $bPrintConvertedSequence = 1;
#    }#if 
    STDERR->print("\nProcessing will start in two seconds...\n");
    sleep(2);
    #############################################
    ####  Process Section
    #############################################
    ($StatusResult, @StatusResultMsg) = ReadDTDFile($FileNameDTD); 
    if ( 0 == $StatusResult){
         $ReturnStatus = $StatusResult;
         ReviewDTDTreeForErrors($ERROR_DTD_READ, @StatusResultMsg);
         STDERR->print("PDB Parser has exited due to DTD errors.\n");
         return($ReturnStatus);
    }#if

    $DTDTree{$ELEMENT_NAME}       = $g_RootElement; # the first elem found in DTD is set a the ROOT (global)
    $DTDTree{$ELEMENT_LINE_NUM}   = $g_RootLineNum; # line number in the dtd file (where the root elem is)
    $DTDTree{$ref_MYNODE}         = \%DTDTree; # '\' is like & in C for referencing addresses; ref_MYNODE is like the 'this' pointer in C++, thus this variable contains the address of the current hash
    $DTDTree{$ref_PARENTNODE}     = \$g_TreeRoot; # the address of a string g_TreeRoot; Used this because the hash representing the root does not have a parent
###############
    $DTDTree{$ref_ATTRIBUTE_NAME_LIST} = \@EmptyDTDAttributeNameList; 
###############
    $DTDTree{$ref_ATTRIBUTE_LIST} = \@EmptyDTDAttributeList;
    $g_ProclaimedAssociatedElementCount++; # we 'proclaimed' the first element - the root
    STDERR->print("\n**** Building DTD Tree...\n");
    ($StatusResult, @StatusResultMsg) = BuildDTDTree(\%DTDTree);
    if ( 0 == $StatusResult){
         $ReturnStatus = $StatusResult;
         ReviewDTDTreeForErrors($ERROR_DTD_BUILD, @StatusResultMsg); #c?? called again? (see 17 lines above, and 7 lines below, and line 1757)
         STDERR->print("PDB Parser has exited due to DTD errors.\n");
         return($ReturnStatus);
    }else{
        STDERR->print("\n**** The DTD Tree has been built.\n");
    }#else

    if (0 == ($StatusResult = ReviewDTDTreeForErrors($ERROR_DTD_NOERROR, @StatusResultMsg))){
         STDERR->print("PDB Parser has exited due to DTD errors.\n");
         return($ReturnStatus = $StatusResult);
    }#if

    ($StatusResult, @StatusResultMsg) = ReadPDBFile($FileNamePDB);
    if ( 0 == $StatusResult){
         $ReturnStatus = $StatusResult;
         STDERR->print("@StatusResultMsg\n");
         STDERR->print("PDB Parser has exited due to PDB errors.\n");
         return($ReturnStatus);
    }#if

    CalculatePhiPsiAngles(0);
# instantiation of PDBInstanceTree elements:
    $PDBInstanceTree{$ELEMENT_NAME}            = $DTDTree{$ELEMENT_NAME};
    $PDBInstanceTree{$ELEMENT_CATEGORY}        = $DTDTree{$ELEMENT_CATEGORY};
    $PDBInstanceTree{$ELEMENT_LINE_NUM}        = $DTDTree{$ELEMENT_LINE_NUM};
    $PDBInstanceTree{$ref_MYNODE}              = \%PDBInstanceTree;
    $PDBInstanceTree{$ref_PARENTNODE}          = \$g_TreeRoot;
    my @tmpChildList                           = @{$DTDTree{$ref_CHILDNODE_LIST}}; 
    $PDBInstanceTree{$ref_CHILDNODE_LIST}      = \@tmpChildList;
    my @tmpAttributeNameList                   = @{$DTDTree{$ref_ATTRIBUTE_NAME_LIST}}; 
    $PDBInstanceTree{$ref_ATTRIBUTE_NAME_LIST} = \@tmpAttributeNameList;
    my @tmpAttributeList                       = @{$DTDTree{$ref_ATTRIBUTE_LIST}}; 
    $PDBInstanceTree{$ref_ATTRIBUTE_LIST}      = \@tmpAttributeList;
    $PDBInstanceTree{$BEGIN_TAG}               = $DTDTree{$BEGIN_TAG};
    $PDBInstanceTree{$PCDATA}                  = $DTDTree{$PCDATA};
    $PDBInstanceTree{$END_TAG}                 = $DTDTree{$END_TAG};
    $PDBInstanceTree{$NODE_VISIT_STATUS}       = $VISIT_STATUS_WHITE;
    $PDBInstanceTree{$NODE_STATUS}             = $NOT_SATISFIED;
    $LineInfo{$LINE_STATUS}                    = $NEED_LINE;


    STDERR->print("**** Building PDB Tree...\n");
    $FileLenght = scalar (@g_PDBMasterRecordFileList);
    if ($FileLenght > 5000){$g_bLongFile = 1;}
    if ($FileLenght < 1000){
        $TimeAdj = 250;
    }elsif($FileLenght < 1500){
        $TimeAdj = 125;
    }elsif($FileLenght < 2500){
        $TimeAdj = 110;
    }else{
        $TimeAdj = 100;
    }#else
    $RunTime = ConvertSecondsToTime(int($FileLenght/$TimeAdj));
    STDERR->print("**** Approximate build time: $RunTime\n");
    ($StatusResult, @StatusResultMsg) = BuildPDBTree(\%PDBInstanceTree,
                                                     \%DTDTree,
                                                     \%LineInfo);

    if ( 0 == $StatusResult){
         STDERR->print("\n");
         $ReturnStatus = $StatusResult;
         STDERR->print("MSG: @StatusResultMsg\n");
#        ReviewDTDTreeForErrors($ERROR_DTD_BUILD, @StatusResultMsg);
         STDERR->print("PDB Parser has exited due to PDB Instance errors.\n");
#        return($ReturnStatus);
    }else{
        STDERR->print("\n**** The PDB Instance Tree has been built.\n");
    }#else

    #############################################
    ####  Printing Seciton
    #############################################
    STDERR->print("\n**** Building printable XML File...\n");
    #BuildPrintableXMLFromPDBTree(\%PDBInstanceTree, \@g_PrintableXMLFile, $LINE_SPACE);
    #PrintXMLFile($FileNameXML, \@g_PrintableXMLFile);
    BuildPrintableXMLFromPDBTree(\%PDBInstanceTree, $LINE_SPACE);
    PrintXMLFile($FileNameXML);
    if (!$bPrintXMLToScreen){
        STDERR->print("\n**** Printable XML File has been built.\n");
    }#if
    STDERR->print("\n**** Printable XML File has been written to file named: $FileNameXML\n");

#    if ($bPrintConvertedSequence){
#        STDERR->print("\n**** Printing any found Converted Sequences.\n");
#        PDB1LetterSeqs($FileNamePDB);
#    }#if

#   PrintAllDTDGlobalList();
    STDERR->print("\n**** PDB Parser has completed with Success.\n");
    $ReturnStatus = !$StatusResult;
    return($ReturnStatus);
}# MainFunction()

    ################################################################################################
    ###########                                                                          ###########
    ###########                             Code Section                                 ###########
    ###########                             PDB Functions                                ###########
    ###########            Subsections:                                                  ###########
    ###########                           Divide And Conquer                             ###########
    ###########                           Node & Record State Functions                  ###########
    ###########                           PDB Creation and Access Functions              ###########
    ###########                           PDB DTD table access Functions                 ###########
    ###########                           Specialty Functions                            ###########
    ################################################################################################

    ############################################################################
    ###########                   Subsection                         ###########
    ###########        Divide And Conquer                            ###########
    ###########        Functions:                                    ###########
    ###########        ReadPDBFile()                                 ###########
    ###########        BuildPDBTree()                                ###########
    ###########        ReviewSingle()                                ###########
    ###########        ReviewSingleCont()                            ###########
    ###########        ReviewMultiple()                              ###########
    ###########        ReviewMultipleCont()                          ###########
    ###########        VisitPDBNode()                                ###########
    ###########        ProcessLine()                                 ###########
    ############################################################################

############################################################################
# FUNCTION:     ReadPDBFile()
# PURPOSE:      Reads the PDB file,
# PARAMETERS:   None.
#               
# RETURN:       TRUE for success, otherwise FALSE.
# REMARK:       '#' char
############################################################################
sub ReadPDBFile{
    my $FileName        = "";
    my $Line            = "";
    my @Lines           = "";
    my $ReturnStatus    =  0; #Must be True.
    my @returnStatusMsg = ();

    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function ReadPDPFile()\n");}

    ($FileName) = @_;

    if (open(FILE,"$FileName")){
        @Lines=<FILE>;
        close FILE;
        foreach $Line (@Lines){
            chomp($Line);
        }#foreach
        if ($bDBCommentsAllowedInPDBFile){
            foreach $Line (@Lines){
                if ((! grep /^\s*#/, $Line) && (! grep /^\s*$/, $Line)) {
                    push @g_PDBMasterRecordFileList, $Line;
                }#if
            }#foreach
        }else{
            @g_PDBMasterRecordFileList = @Lines;
        }#else
        @g_PDBRecordFileList       = @g_PDBMasterRecordFileList;
        $ReturnStatus = 1;
    }else{
        @returnStatusMsg = ("PDBParser failed to open file $FileName to read the PDB records.\n");
        $ReturnStatus = 0;
    }#else
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function ReadPDPFile()\n");}
    return ($ReturnStatus, @returnStatusMsg);
}#ReadPDBFile()

############################################################################
# FUNCTION:     BuildPDBTree()
# PURPOSE:      Build a tree of the PDB Instance tree.
# PARAMETERS:   $refPDBNode  - [IN] A hash reference containing the Current PDB Node hash.
#               $refDTDNode  - [IN] A hash reference containing the Current DTD Node hash.
#               $refLineInfo - [IN/OUT] A hash reference containing a LineInfo hash.
#               
# RETURN:       TRUE for success, otherwise FALSE.
############################################################################
sub BuildPDBTree{

    # Trees & Current Line
    my $refPDBNode       =  0;
    my $refDTDNode       =  0;
#    my %PDBNode          = [];
    my %DTDNode          = [];
    my $refLineInfo      =  0;
    my %LineInfo         = [];

    my $TmpChildNode     = "";
    my @ProcessedChildNodeNames = ();
    my @ChildNodeList    = ();
    my @NewChildNodeList = ();
    my @UnprocessedList  = ();
    my @TmpChildNodeList = ();
    my $ChildInstance    =  0;
    my $ProcessNewChild  =  0;
    my $bSameRecordType  =  1;
    my $bStopProcessing  =  0; #MUST BE FALSE
    my $bCreateMultiInstancesOfChildType =  0;

    my @TotalChildNodeNames = ();
    my $TmpNode = "";
    my $NextRecord = "";
    my $Token = "";
    my $DTDElementName = "";

    # Status information
    my $OccurrenceSign   =  0;
    my $FormatMsg        = "";
    my $StatusMsg        = ""; 
    my @StatusMsg        = ();
    my $StatusResult     =  0;
    my @StatusResultMsg  = ();
    my $returnStatus     =  0;
    my @returnStatusMsg  = ();

    #\%PDBInstanceTree \%DTDTree
    ($refPDBNode, $refDTDNode, $refLineInfo) = @_;

    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function BuildPDBTree()\n");}
#    %PDBNode = %{$refPDBNode};
    %DTDNode = %{$refDTDNode};
    %LineInfo = %{$refLineInfo};

    if (($bRunTimeDebug eq 0) && ($bVerify eq 0) && ($bLineProcess eq 0) && ($bQStat eq 0)){STDERR->print(".");}
#    if ($bVerify){STDERR->print("##*********** Entering: BuildPDBTree($PDBNode{$ELEMENT_NAME} Node) **********\n");}
    if ($bVerify){STDERR->print("##*********** Entering: BuildPDBTree(${%{$refPDBNode}}{$ELEMENT_NAME} Node) **********\n");}
    #Get a new line and build a LineInfo if no LineInfo was passed in.
    if (($LineInfo{$LINE_STATUS} eq $NEED_LINE) || ($LineInfo{$LINE_STATUS} eq $PROCESSED)){
        %LineInfo = [];
        GetNewRecordLine (\%LineInfo);
    }#if
    if ($bVerify){PrintNodeReport(\%DTDNode, "DTD");}
#    if ($bVerify){PrintNodeReport(\%PDBNode, "PDB");}
    if ($bVerify){PrintNodeReport($refPDBNode, "PDB");}
    if ($bVerify){PrintLineReport(\%LineInfo);}

#    $PDBNode{$NODE_VISIT_STATUS} = $VISIT_STATUS_GREY;
    ${%{$refPDBNode}}{$NODE_VISIT_STATUS} = $VISIT_STATUS_GREY;

#    ($StatusResult, @StatusResultMsg) = VisitPDBNode(\%PDBNode, \%LineInfo);########## VisitPDBNode ############
    ($StatusResult, @StatusResultMsg) = VisitPDBNode($refPDBNode, \%LineInfo);########## VisitPDBNode ############
    if ( $StatusResult eq 0){
        push @returnStatusMsg, @StatusResultMsg;
        return(0, @returnStatusMsg);
    }#if
    ###############################################################
    # Create new children Nodes on the PDB tree by traversing the DTD tree and reading PDB records.
    ###############################################################
    if ($DTDNode{$ELEMENT_CATEGORY} eq $ELEM_CAT_LIST){
#        @ChildNodeList = @{$PDBNode{$ref_CHILDNODE_LIST}};
        @ChildNodeList = @{${%{$refPDBNode}}{$ref_CHILDNODE_LIST}};

        if ($bVerify){STDERR->print ("##*********** Start Visiting Children ********\n");}
        #foreach $TmpChildNode (@ChildNodeList){
        while (($TmpChildNode = shift(@ChildNodeList)) && (! $bStopProcessing)){
            $TmpChildNode =~ s/^\s+//;
            $TmpChildNode =~ s/\s+$//;
            #$ChildInstance = 1;
            $ChildInstance = (grep /^${TmpChildNode}_\d+/, @NewChildNodeList) + 1; #New 20050213
            $ProcessNewChild = 1;
            ($OccurrenceSign, $bCreateMultiInstancesOfChildType) = RemoveOccurrenceSign(\$TmpChildNode);  # Output: Reversed for later use.
            #list of processed children in case a record type appears again after processing other record types.
            push @ProcessedChildNodeNames, $TmpChildNode;
            if ($bVerify){STDERR->print("##******** New child: \"$TmpChildNode\"\n");}
            while (($ProcessNewChild) || ($bSameRecordType)){
                $ProcessNewChild = 0;
                $bSameRecordType = 0; #Error in covering all pathways; if this is not reset infinate loop!!!!!!!!
                                      #REC_MULTIPLE, REC_MULTIPLE_CONT/PARSE,REC_MULTIPLE_CONT/SEARCH
                my %NewPDBNode = [];
#                CreatePDBNode(\%PDBNode, \%NewPDBNode, $DTDNode{$TmpChildNode});
                CreatePDBNode($refPDBNode, \%NewPDBNode, $DTDNode{$TmpChildNode});
                if (($LineInfo{$RECORD_TYPE} eq $REC_OTHER) && ($NewPDBNode{$ELEMENT_NAME} eq $LineInfo{$ELEMENT_NAME})){
                    if ($bVerify){STDERR->print ("##******** Calling: BuildOTHERTree(PDBNode{${TmpChildNode}_${ChildInstance}})\n");}
                    ($StatusResult, @StatusResultMsg) = BuildOTHERTree(\%NewPDBNode, $DTDNode{$TmpChildNode}, \%LineInfo);
#                    if ($bVerify){STDERR->print ("##******** Returning To: BuildPDBTree($PDBNode{$ELEMENT_NAME} Node) **********\n");}
                    if ($bVerify){STDERR->print ("##******** Returning To: BuildPDBTree(${%{$refPDBNode}}{$ELEMENT_NAME} Node) **********\n");}
                }else{
                    if ($bVerify){STDERR->print ("##******** Calling: BuildPDBTree(PDBNode{${TmpChildNode}_${ChildInstance}})\n");}
                    ($StatusResult, @StatusResultMsg) = BuildPDBTree(\%NewPDBNode, $DTDNode{$TmpChildNode}, \%LineInfo);
#                    if ($bVerify){STDERR->print ("##******** Returning To: BuildPDBTree($PDBNode{$ELEMENT_NAME} Node) **********\n");}
                    if ($bVerify){STDERR->print ("##******** Returning To: BuildPDBTree(${%{$refPDBNode}}{$ELEMENT_NAME} Node) **********\n");}
                }#else
                if ( $StatusResult eq 0){
                    push @returnStatusMsg, @StatusResultMsg;
                    return(0, @returnStatusMsg);
                }#if
                # If the child node didn't get data or is not BLACK by its dedescendants then toss it away.
                if ($NewPDBNode{$NODE_VISIT_STATUS} eq $VISIT_STATUS_BLACK){
#                    if (($PDBNode{$NODE_VISIT_STATUS} eq $VISIT_STATUS_GREY) && (grep(/^$PDB_ID$/, @{$PDBNode{$ref_ATTRIBUTE_NAME_LIST}}))){
#                        $PDBNode{$BEGIN_TAG} =~ s/$PDB_ID/$PDB_ID=\"$g_pdb_id\"/;
                    if ((${%{$refPDBNode}}{$NODE_VISIT_STATUS} eq $VISIT_STATUS_GREY) && 
                          (grep(/^$PDB_ID$/, @{${%{$refPDBNode}}{$ref_ATTRIBUTE_NAME_LIST}}))){
                         ${%{$refPDBNode}}{$BEGIN_TAG} =~ s/$PDB_ID/$PDB_ID=\"$g_pdb_id\"/;
                    }#if
#                    if ($bVerify){STDERR->print ("##** $PDBNode{$ELEMENT_NAME} made BLACK by child $NewPDBNode{$ELEMENT_NAME}\n");}
#                    $PDBNode{$NODE_VISIT_STATUS} = $VISIT_STATUS_BLACK;
                    if ($bVerify){STDERR->print ("##** ${%{$refPDBNode}}{$ELEMENT_NAME} made BLACK by child $NewPDBNode{$ELEMENT_NAME}\n");}
                     ${%{$refPDBNode}}{$NODE_VISIT_STATUS} = $VISIT_STATUS_BLACK;
                    # Create a 
                    push @NewChildNodeList, "${TmpChildNode}_${ChildInstance}";#Children instance names to attached to parent, once all are processed.
#                    $PDBNode{"${TmpChildNode}_${ChildInstance}"} = \%NewPDBNode;
                    ${%{$refPDBNode}}{"${TmpChildNode}_${ChildInstance}"} = \%NewPDBNode;
                    $ChildInstance++;
                }#if
                SWITCH: {
                    #May appear only once, otherwise duplicate error.
                    if ($LineInfo{$RECORD_TYPE} eq $REC_SINGLE){ 
                        $returnStatus = ReviewSingle($refPDBNode, \%LineInfo, \$bSameRecordType);
                        last SWITCH;
                    }#if
                    #May logically appear once over multiple lines otherwise duplicate error.
                    #Subsequent lines contain a continuation field an incrementing counter.
                    if ($LineInfo{$RECORD_TYPE} eq $REC_SINGLE_CONT){
                        $returnStatus = ReviewSingleCont($refPDBNode, \%LineInfo, \$bSameRecordType);
                        last SWITCH;
                    }#if
                    #May appear multiple times, often the information is in list form and is not logically concatenated. These record  
                    #types usually have a custom serialization to denote order and connect to other record types. 
                    if ($LineInfo{$RECORD_TYPE} eq $REC_MULTIPLE){
                        $returnStatus = ReviewMultiple($refPDBNode, \%LineInfo, \%NewPDBNode, \$bSameRecordType);
                        if ((!$bSameRecordType) && ($LineInfo{$ACTION} eq $SEARCH)){
                            @TotalChildNodeNames = ();
                            push @TotalChildNodeNames, @ProcessedChildNodeNames;
                            push @TotalChildNodeNames, @ChildNodeList;
                            foreach $TmpNode (@TotalChildNodeNames){
                                RemoveOccurrenceSign(\$TmpNode);
                            }#foreach
                             # One Matrixn set if not code below. $LineInfo{$LINE_STATUS} eq $PROCESSED
                          SWITCH: {
                            if ($LineInfo{$LINE_STATUS} eq $PROCESSED){ #MATRIXn only uses this!! ATOM
                                $NextRecord = PeekAtNextRecordName();
                                if ($NextRecord){
                                    ($StatusResult, $DTDElementName, @StatusMsg) = GetPDBToDTDField($NextRecord, $REF_FIELD, $DTD_ELEM_NAME_FIELD);
                                    if ($bVerify){
                                        my $tmptmp = GetRecordField($LineInfo{$PDB_LINE}, $LineInfo{$PIVOT_KEY});
#                                        STDERR->print ("\n PDB Element: $PDBNode{$ELEMENT_NAME} ");
                                        STDERR->print ("\n PDB Element: ${%{$refPDBNode}}{$ELEMENT_NAME} ");
                                        STDERR->print ("Line Data: $tmptmp ");
                                        STDERR->print (" Curr Record: $LineInfo{$RECORD_NAME} NextRecord: $NextRecord\n");
                                        QuickStat($refPDBNode,\%LineInfo,"PDBTree()","LINE_STATUS eq PROCESSED");
                                        STDERR->print ("Next Records Element: $DTDElementName\n");
                                        STDERR->print ("List of Children: @TotalChildNodeNames\n");
                                    }#if
                                    ($StatusResult, $Token, @StatusMsg) = GetPDBToDTDField($LineInfo{$RECORD_NAME}, $REF_ACTION, $TOKEN);
                                    if ($Token eq 'SPECIAL'){
                                        ($StatusResult, $Token, @StatusMsg) = GetPDBToDTDField($LineInfo{$RECORD_NAME}, $REF_SPECIAL, $DTDElementName);
                                        if ($StatusResult == 0){
                                            if ($bVerify){STDERR->print("WARN INFO: @StatusMsg\n");}
                                        }else{
                                            $DTDElementName = $Token;
                                        }#else
                                    }#if
                                    if (grep /^$DTDElementName$/,  @TotalChildNodeNames){
                         ##########               MoveChildToProcessedList($DTDElementName,\@ProcessedChildNodeNames, \@ChildNodeList);
                                        $ChildInstance = (grep /^${DTDElementName}_\d+/, @NewChildNodeList) + 1;
                                        $bSameRecordType = 1;
                                        $TmpChildNode = $DTDElementName;
                                    }else{
                                        $bStopProcessing = 1; #H!!!!!!!!!!!!!
                                        $bSameRecordType = 0;
                                    }#else
                                }#if
                                last SWITCH;
                            }#if
                        }#SWITCH
                        }#if
                        last SWITCH;
                    }#if
                    #May appear multiple times and logically over multiple lines. Subsequent lines contain a continuation field an 
                    #incrementing counter.
                    if ($LineInfo{$RECORD_TYPE} eq $REC_MULTIPLE_CONT){
#                        $returnStatus = ReviewMultipleCont(\%PDBNode, \%LineInfo, \%NewPDBNode, \$bSameRecordType);
                        $returnStatus = ReviewMultipleCont($refPDBNode, \%LineInfo, \%NewPDBNode, \$bSameRecordType);
                        if ((!$bSameRecordType) && ($LineInfo{$ACTION} eq $SEARCH)){
                            @TotalChildNodeNames = ();
                            push @TotalChildNodeNames, @ProcessedChildNodeNames;
                            push @TotalChildNodeNames, @ChildNodeList;
                            foreach $TmpNode (@TotalChildNodeNames){
                                RemoveOccurrenceSign(\$TmpNode);
                            }#foreach
                             # One Matrixn set if not code below. $LineInfo{$LINE_STATUS} eq $PROCESSED
                          SWITCH: {
                            if ($LineInfo{$LINE_STATUS} eq $PROCESSED){ #MATRIXn only uses this!! ATOM
                                $NextRecord = PeekAtNextRecordName();
                                if ($NextRecord){
                                    ($StatusResult, $DTDElementName, @StatusMsg) = GetPDBToDTDField($NextRecord, $REF_FIELD, $DTD_ELEM_NAME_FIELD);
                                    if ($bVerify){
                                        my $tmptmp = GetRecordField($LineInfo{$PDB_LINE}, $LineInfo{$PIVOT_KEY});
                                        STDERR->print ("\n PDB Element: ${%{$refPDBNode}}{$ELEMENT_NAME} ");
                                        STDERR->print ("Line Data: $tmptmp ");
                                        STDERR->print (" Curr Record: $LineInfo{$RECORD_NAME} NextRecord: $NextRecord\n");
#                                        QuickStat(\%PDBNode,\%LineInfo,"PDBTree()","LINE_STATUS eq PROCESSED");
                                        QuickStat($refPDBNode,\%LineInfo,"PDBTree()","LINE_STATUS eq PROCESSED");
                                        STDERR->print ("Next Records Element: $DTDElementName\n");
                                        STDERR->print ("List of Children: @TotalChildNodeNames\n");
                                    }#if
                                    if (grep /^$DTDElementName$/,  @TotalChildNodeNames){
                                     ##########   MoveChildToProcessedList($DTDElementName,\@ProcessedChildNodeNames, \@ChildNodeList);
                                        $ChildInstance = (grep /^${DTDElementName}_\d+/, @NewChildNodeList) + 1;
                                        $bSameRecordType = 1;
                                        $TmpChildNode = $DTDElementName;
                                    }else{
                                        $bStopProcessing = 1; #Hack Why does atom need this to escape; comm out make test5 work!!!
                                        $bSameRecordType = 0;
###########################################################################
                                        my $tmp1 =  GetRecordField($LineInfo{$PDB_LINE}, $DTD_ELEM_NAME_FIELD);
                                        $tmp1 =~ s/\s+$//;
                                        my $tmp2 = $NextRecord;
                                    #    STDERR->print ("Curr tmp1 Element: \"$tmp1\"\n");
                                    #    STDERR->print ("Next tmp2 Element: \"$tmp2\"\n");
                                        if (((grep /^MTRIX/, $tmp1) && ($tmp2 eq 'MODEL'))||
                                           ((grep /^MTRIX/, $tmp1) && ($tmp2 eq 'ATOM'))||
                                           ((grep /^MTRIX/, $tmp1) && ($tmp2 eq 'HETATM'))){
                                            %LineInfo = [];                    #New 20050322
                                    #    STDERR->print ("Getting New LINE!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
                                            GetNewRecordLine (\%LineInfo);     #New 20050322
                                            $bStopProcessing = 0;
                                        }#if
###########################################################################

                                    }#else
                                }#if  #priceprice
                                last SWITCH;
                            }#if
                        }#SWITCH
                        }#if
                        last SWITCH;
                    }#if
##########$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
                    # There are three record types used to group other records. The MODEL/ENDMDL records surround groups of ATOM, HETATM, SIGATM,
                    # ANISOU, SIGUIJ, and TER records. TER records indicate the end of a chain.
                    if ($LineInfo{$RECORD_TYPE} eq $REC_GROUP){
                        #$returnStatus = ReviewGrouping(\%PDBNode, \%LineInfo, \$bSameRecordType);
                        last SWITCH;
                    }#if ($LineInfo{$RECORD_TYPE} eq $REC_GROUP)
                    if ($LineInfo{$RECORD_TYPE} eq $REC_OTHER){ #The remaining record types have a detailed inner structure. 
#STDERR->print ("##*********** ReviewOther ReviewOther ReviewOther *************************************************\n");
#                        $returnStatus = ReviewOther(\%PDBNode, \%LineInfo, \$bSameRecordType);
                        $returnStatus = ReviewOther($refPDBNode, \%LineInfo, \$bSameRecordType);
                        last SWITCH;
                    }#if 
                    default:{#Content must occur once, and only once.
#                        if ($bQStat){QuickStat(\%PDBNode,\%LineInfo,"PDBTree()"," No switch case caught this pass;Chk was: SC.");}
                        if ($bQStat){QuickStat($refPDBNode,\%LineInfo,"PDBTree()"," No switch case caught this pass;Chk was: SC.");}
                        last SWITCH;
                    }#default
                }#SWITCH
            }#while (($ProcessNewChild) || ($bSameRecordType))
        }#while (($TmpChildNode = shift(@ChildNodeList)) && (! $bStopProcessing))
#        @{$PDBNode{$ref_CHILDNODE_LIST}} = @NewChildNodeList;
        @{${%{$refPDBNode}}{$ref_CHILDNODE_LIST}} = @NewChildNodeList;
        if ($bVerify){STDERR->print ("##*********** Finished Visiting Children *****\n");}
    }#if ($DTDNode{$ELEMENT_CATEGORY} eq $ELEM_CAT_LIST)
#    %{$refPDBNode} = %PDBNode;
    %{$refDTDNode} = %DTDNode;
    %{$refLineInfo} = %LineInfo;
#    if ($bVerify){ PrintNodeReport(\%PDBNode, "PDB"); PrintLineReport(\%LineInfo); }
#    if ($bVerify){STDERR->print ("##*********** Leaving: BuildPDBTree($PDBNode{$ELEMENT_NAME} Node) **********\n");}
    if ($bVerify){ PrintNodeReport($refPDBNode, "PDB"); PrintLineReport(\%LineInfo); }
    if ($bVerify){STDERR->print ("##*********** Leaving: BuildPDBTree(${%{$refPDBNode}}{$ELEMENT_NAME} Node) **********\n");}
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function BuildPDBTree()\n");}
    $returnStatus = 1;
    return ($returnStatus, @returnStatusMsg);
}#BuildPDBTree()

#############################################################################
## FUNCTION:     ReviewSingle()
## PURPOSE:      May appear only once, otherwise duplicate error.
## PARAMETERS:   $refPDBNode   - [IN/OUT] A hash reference containing the Current PDB Node hash.
##               $refLineInfo  - [IN/OUT] A hash reference containing a LineInfo hash.
##               $refbSameRecordType - [IN/OUT]
## RETURN:       
#############################################################################
sub ReviewSingle{
    my $refPDBNode          =  0;
    my $refLineInfo         =  0;
    my $refbSameRecordType  =  0;
    my %PDBNode             = [];
    my %LineInfo            = [];
    my $bSameRecordType     =  0;
    my $NextRecordName      = "";
    my $returnStatus        = "";

    ($refPDBNode, $refLineInfo, $refbSameRecordType)  = @_;
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function ReviewSingle()\n");}
    %PDBNode  = %{$refPDBNode};
    %LineInfo = %{$refLineInfo};
    $bSameRecordType = $$refbSameRecordType;   # removed the outer $
    # Do nothing at this time
    $bSameRecordType = 0;
    %{$refPDBNode}  = %PDBNode;
    %{$refLineInfo} = %LineInfo;
    $$refbSameRecordType = $bSameRecordType;
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function ReviewSingle()\n");}
    $returnStatus = 1;
    return ($returnStatus);
}#ReviewSingle()

#############################################################################
## FUNCTION:     ReviewSingleCont()
## PURPOSE:      Processes one to many LineInfo lines needed to satify the PDB node.
## PARAMETERS:   $refPDBNode   - [IN/OUT] A hash reference containing the Current PDB Node hash.
##               $refLineInfo  - [IN/OUT] A hash reference containing a LineInfo hash.
##               $refbSameRecordType - [IN/OUT]
## RETURN:       
#############################################################################
sub ReviewSingleCont{
    my $refPDBNode          =  0;
    my $refLineInfo         =  0;
    my $refbSameRecordType  =  0;
    my %PDBNode             = [];
    my %LineInfo            = [];
    my $bSameRecordType     =  0;
    my $EntryIDCount        =  0;
    my $NextRecordName      = "";
    my $StatusResult        =  0;
    my @StatusMsg           = ();
    my $returnStatus        = "";

    ($refPDBNode, $refLineInfo, $refbSameRecordType)  = @_;
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function ReviewSingleCont()\n");}
    %PDBNode  = %{$refPDBNode};
    %LineInfo = %{$refLineInfo};
    $bSameRecordType = $$refbSameRecordType;

    SWITCH: {
       # if ($LineInfo{$LINE_STATUS} eq $PROCESSED){
        if  (($LineInfo{$LINE_STATUS} eq $NEED_LINE) || ($LineInfo{$LINE_STATUS} eq $PROCESSED)){
            if ($bQStat){QuickStat(\%PDBNode,\%LineInfo,"PDBTree()"," Chk: SC & Processed.");}
            SWITCH: {
                if ($LineInfo{$ACTION} eq $PARSE){  #Note this is new!!!!!! 
                    $NextRecordName = PeekAtNextRecordName();
                    #if ($PDBNode{$ELEMENT_NAME} eq $LineInfo{$PIVOT_ENTRY}){
                    #MultiKey record will need this expanded
                    #If same record type then get and adjust new record to the record's defined MultiPivot to cont. the parse.
                    if ($NextRecordName eq $LineInfo{$RECORD_NAME}){
                        $bSameRecordType = 1;                                ########  Imp:  Global returned info
                        $EntryIDCount = $LineInfo{$ENTRY_ID_COUNT};
                        GetNewRecordLine(\%LineInfo);                        ########  Imp:  Global returned info
                        $LineInfo{$ENTRY_ID_COUNT} = $EntryIDCount;
                        ($StatusResult, $LineInfo{$MASTER_PIVOT_KEY}, @StatusMsg) =  GetPDBToDTDField($LineInfo{$RECORD_NAME}, $REF_ACTION, $TOKEN);
                        if ($LineInfo{$MASTER_PIVOT_KEY} ne 0){
                            AdjustLineToMasterPivot(\%LineInfo);
                            if ($bQStat){QuickStat(\%PDBNode,\%LineInfo,"PDBTree()"," SameRecordType=1; Parse more Childs with next Rec");}
                            if ($bVerify){ PrintNodeReport(\%PDBNode, "PDB"); PrintLineReport(\%LineInfo);}
                        }#if
                    }#if
                    last SWITCH;
                }#if
            }#SWITCH
            last SWITCH;
        }#if PROCESSED
        if ($LineInfo{$LINE_STATUS} eq $PROCESSING){ #Note This has not been confirm to ever happen.!!!!!!!!!!!!!!!!!!!!!!!!!
            SWITCH: {                                #did not happen with TEST4
                if ($LineInfo{$ACTION} eq $PARSE){
                    $bSameRecordType = 1;
                    last SWITCH;
                }#if
            }#SWITCH
            last SWITCH;
        }#if PROCESSING
    }#SWITCH
    %{$refPDBNode}  = %PDBNode;
    %{$refLineInfo} = %LineInfo;
    $$refbSameRecordType = $bSameRecordType;
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function ReviewSingleCont()\n");}
    $returnStatus = 1;
    return ($returnStatus);
}#ReviewSingleCont()

#############################################################################
## FUNCTION:     ReviewMultiple()
## PURPOSE:      
## PARAMETERS:   $refPDBNode   - [IN/OUT] A hash reference containing the Current PDB Node hash.
##               $refLineInfo  - [IN/OUT] A hash reference containing a LineInfo hash.
##               $refbSameRecordType - [IN/OUT]
## RETURN:       
#############################################################################
sub ReviewMultiple{
    my $refPDBNode          =  0;
    my $refLineInfo         =  0;
    my $refNewPDBNode       =  0;
    my $refbSameRecordType  =  0;
    my %PDBNode             = [];
    my %LineInfo            = [];
    my %NewPDBNode          = [];
    my $bSameRecordType     =  0;
    my $EntryIDCount        =  0;
    my $NextRecordName      = "";
    my $MultiKeyLevelForNode = 0;
    my $SharedMultiKeyLevel =  0;
    my $NewMasterPivot      =  0;
    my $returnStatus        = "";
    my $EntryIDCount        =  0;
    my $StatusResult        =  0;
    my @StatusMsg           = ();

    ($refPDBNode, $refLineInfo, $refNewPDBNode, $refbSameRecordType)  = @_;
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function ReviewMultiple()\n");}
    %PDBNode  = %{$refPDBNode};
    %LineInfo = %{$refLineInfo};
    %NewPDBNode = %{$refNewPDBNode};
    $bSameRecordType = $$refbSameRecordType;
    SWITCH: {
        if ($LineInfo{$LINE_STATUS} eq $PROCESSED){# Process next simular record on child at M. Rec: $LineInfo{$RECORD_NAME} Type:MC Action:PARSE
            if ($bQStat){QuickStat(\%PDBNode,\%LineInfo,"PDBTree()"," Chk: MC & Processed.");}
            #Ensure the current line is using a MultiKey
            if ($LineInfo{$MULTIKEY_STATE}){
                $MultiKeyLevelForNode = GetMultiKeyOfLineMatchingPDBNode(\%PDBNode, \%LineInfo);
                $SharedMultiKeyLevel = CompareFieldsOfLineToNextBasedOnMKeys(\%LineInfo,0);
                # Node > 0 Prevents the 0 = 0 case where neither match, but would be allow to do code for actual matching
                if (($MultiKeyLevelForNode > 0) && ($MultiKeyLevelForNode eq $SharedMultiKeyLevel)){#Determine if current and next line's greatest common
                    $bSameRecordType = 1;                            #shared key, match the current nodes MultiKey.
                    $EntryIDCount = $LineInfo{$ENTRY_ID_COUNT}; #NEW JUST ADDED ON 20041205
                    GetNewRecordLine(\%LineInfo);
                    $LineInfo{$ENTRY_ID_COUNT} = $EntryIDCount;#NEW JUST ADDED ON 20041205
                    $LineInfo{$MASTER_PIVOT_KEY} = GetNewMasterPivot(\%PDBNode, \%LineInfo);#Read REC info; Next mKey if exist otherwise default M.P.
                    AdjustLineToMasterPivot(\%LineInfo);
                }#if
            }#if ($LineInfo{$MULTIKEY_STATE}){
            last SWITCH;
        }#if
    }#SWITCH
    %{$refPDBNode}    = %PDBNode;
    %{$refLineInfo}   = %LineInfo;
    %{$refNewPDBNode} = %NewPDBNode;
    $$refbSameRecordType = $bSameRecordType;
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function ReviewMultiple()\n");}
    $returnStatus = 1;
    return ($returnStatus);
}#ReviewMultiple()

#############################################################################
## FUNCTION:     ReviewMultipleCont()
## PURPOSE:      P
## PARAMETERS:   $refPDBNode   - [IN/OUT] A hash reference containing the Current PDB Node hash.
##               $refLineInfo  - [IN/OUT] A hash reference containing a LineInfo hash.
##               $refbSameRecordType - [IN/OUT]
## RETURN:       
#############################################################################
sub ReviewMultipleCont{
    my $refPDBNode          =  0;
    my $refLineInfo         =  0;
    my $refNewPDBNode       =  0;
    my $refbSameRecordType  =  0;
    my %PDBNode             = [];
    my %LineInfo            = [];
    my %NewPDBNode          = [];
    my $bSameRecordType     =  0;
    my $NextRecordName      = "";
    my $MultiKeyLevelForNode = 0;
    my $SharedMultiKeyLevel =  0;
    my $NewMasterPivot      =  0;
    my $returnStatus        = "";

    my $EntryIDCount        =  0;
    my $StatusResult        =  0;
    my @StatusMsg           = ();

    ($refPDBNode, $refLineInfo, $refNewPDBNode, $refbSameRecordType)  = @_;
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function ReviewMultipleCont()\n");}
    %PDBNode  = %{$refPDBNode};
    %LineInfo = %{$refLineInfo};
    %NewPDBNode = %{$refNewPDBNode};
    $bSameRecordType = $$refbSameRecordType;


#REC_MULTIPLE_CONT, PARSE
#==============================
#IS:PROCESSED
#     In buildPDBTree MULTIPLE will cause this error: $bSameRecordType = 0; #Error in covering all pathways; if this is not reset infinate loop!!!!!!!!
# NOTE 
# IS not:($LineInfo{$ACTION} eq $SEARCH){
# IS:  else statement LineInfo != SEARCH
#     IS:  LineInfo{MULTIKEY_STATE};
#         IS :  MultiKeyLevelForNode not equal 0  ->   MultiKey is used. Greatest number is "2".
#             IS : ( MultiKeyLevelForNode equal  SharedMultiKeyLevel )
#                 IS : NewPDBNode{$ELEMENT_CATEGORY} eq $ELEM_CAT_PND_PCDATA          If
#                 IS      : NewPDBNode{$ELEMENT_CATEGORY} not equal $ELEM_CAT_PND_PCDATA   Else
#             IS:  $MultiKeyLevelForNode not equal $SharedMultiKeyLevel\n");
#         IS:   $MultiKeyLevelForNode equal  0\n");
# IS NOT:  NOT A $LineInfo{$MULTIKEY_STATE

#IS: PROCESSING
#IS:  IF ($LineInfo{$ACTION} eq $PARSE)\n");


#REC_MULTIPLE_CONT, SEARCH   testing record "SHEET" 
#==============================
#IS:PROCESSED
#     In buildPDBTree MULTIPLE will cause this error: $bSameRecordType = 0; #Error in covering all pathways; if this is not reset infinate loop!!!!!!!!
# NOTE 
# IS:  if ($LineInfo{$MULTIKEY_STATE}){
# IS :($LineInfo{$ACTION} eq $SEARCH){
# IS NOT:  else statement LineInfo != SEARCH
#         IS :  MultiKeyLevelForNode not equal 0  ->   MultiKey is used. for SHEET = 1 ALL MCs seem to be 1.
#             IS : ( MultiKeyLevelForNode equal  SharedMultiKeyLevel )
#                 IS NOT: NewPDBNode{$ELEMENT_CATEGORY} eq $ELEM_CAT_PND_PCDATA          If
#                 IS      : NewPDBNode{$ELEMENT_CATEGORY} not equal $ELEM_CAT_PND_PCDATA   Else
#             IS:  $MultiKeyLevelForNode not equal $SharedMultiKeyLevel\n");  once
#         IS:   $MultiKeyLevelForNode equal  0\n");
# IS NOT:  NOT A $LineInfo{$MULTIKEY_STATE



#IS: PROCESSING
# IS:  ($LineInfo{$ACTION} eq $SEARCH){
#     IS:  LineInfo{MULTIKEY_STATE}
#         IS NOT:  $MultiKeyLevelForNode not equal 0 \n"); for all the MC Searches I tried this is not needed.
#             IS NOT: ( MultiKeyLevelForNode equal  SharedMultiKeyLevel )
#                 IS NOT: NewPDBNode{$ELEMENT_CATEGORY} eq $ELEM_CAT_PND_PCDATA          If
#                 IS NOT     : NewPDBNode{$ELEMENT_CATEGORY} not equal $ELEM_CAT_PND_PCDATA   Else
#             IS NOT:  $MultiKeyLevelForNode not equal $SharedMultiKeyLevel\n");
#         IS: $MultiKeyLevelForNode EQUAL 0 \n");
#     IS NOT:   NOT A $LineInfo{$MULTIKEY_STATE}\n");


    SWITCH: {
        if ($LineInfo{$LINE_STATUS} eq $PROCESSED){# Process next simular record on child at M. Rec: $LineInfo{$RECORD_NAME} Type:MC Action:PARSE
           if ($bQStat){QuickStat(\%PDBNode,\%LineInfo,"PDBTree()"," Chk: MC & Processed.");}
           #Ensure the current line is using a MultiKey
           if ($LineInfo{$MULTIKEY_STATE}){
               # Does PDBNode element match the data of one of the keys? Yes return the key number.
               $MultiKeyLevelForNode = GetMultiKeyOfLineMatchingPDBNode(\%PDBNode, \%LineInfo);
               $SharedMultiKeyLevel = CompareFieldsOfLineToNextBasedOnMKeys(\%LineInfo, 0);
               #If Node is not referenced in the MultiKey, no need to compare.
               if ( $MultiKeyLevelForNode > 0){#Prevents the 0=0 case where neither match, but would be allow to do code for actual matching
#                  #Determine if the current and next line's greatest common shared key, match the current nodes MultiKey.
                   if ( $MultiKeyLevelForNode eq $SharedMultiKeyLevel ){
#QuickStat(\%PDBNode,\%LineInfo,"PDBTree()","MultiKeyLevelForNode eq SharedMultiKeyLevel:: $MultiKeyLevelForNode eq $SharedMultiKeyLevel !!!!!");
                       $bSameRecordType = 1;
                       $EntryIDCount = $LineInfo{$ENTRY_ID_COUNT};
                       GetNewRecordLine(\%LineInfo);  
                       if ( $NewPDBNode{$ELEMENT_CATEGORY} eq $ELEM_CAT_PND_PCDATA){  
                           $LineInfo{$ENTRY_ID_COUNT} = $EntryIDCount;
                           if ($LineInfo{$ACTION} eq $CONCAT){ #New we have to reuse the CON field in ftnote to mark the record
                               #Either the next multikey (after MultiKeyLevelForNode) or the Master Pivot defined in ACTION TOKEN.
                               $LineInfo{$MASTER_PIVOT_KEY} = GetNewMasterPivot(\%PDBNode, \%LineInfo);
                           }else{
                               ($StatusResult, $LineInfo{$MASTER_PIVOT_KEY}, @StatusMsg) = GetPDBToDTDField($LineInfo{$RECORD_NAME}, $REF_ACTION, $TOKEN);
                           }#else
                       }else{
                           if ($LineInfo{$ACTION} eq $PARSE_TO_MULTI_CHILDREN){$LineInfo{$ENTRY_ID_COUNT} = $EntryIDCount;}#for SHEET/strand
                           #Either the next multikey (after MultiKeyLevelForNode) or the Master Pivot defined in ACTION TOKEN.
                           $LineInfo{$MASTER_PIVOT_KEY} = GetNewMasterPivot(\%PDBNode, \%LineInfo);
                       }#else
                       AdjustLineToMasterPivot(\%LineInfo);
                   }else{
                       if ($LineInfo{$ACTION} eq $PARSE_TO_MULTI_CHILDREN){$LineInfo{$ENTRY_ID_COUNT} = 0;}#for SHEET/strand
                   }#else  if ( $MultiKeyLevelForNode eq $SharedMultiKeyLevel )
               }#if ( $MultiKeyLevelForNode > 0)
           }# if ($LineInfo{$MULTIKEY_STATE})
           last SWITCH;
        }#if ($LineInfo{$LINE_STATUS} eq $PROCESSED)

###################################################################
###################################################################
###################################################################
###################################################################

        if ($LineInfo{$LINE_STATUS} eq $PROCESSING){
            SWITCH: {
#                if ($LineInfo{$ACTION} eq $SEARCH){
#                    if ($LineInfo{$MULTIKEY_STATE}){
#                        #Either the next multikey (after MultiKeyLevelForNode) or the Master Pivot defined in ACTION TOKEN.
#                        $MultiKeyLevelForNode = GetMultiKeyOfLineMatchingPDBNode(\%PDBNode, \%LineInfo);
#                        #If Node is not reference in the MultiKey, no need to compare.
#                        if ( $MultiKeyLevelForNode ne 0){
#                        }else{
#                            if ($bQStat){QuickStat(\%PDBNode,\%LineInfo,"PDBTree()"," MKey now at zero for Node; SameRecType=0.");}
#                            $bSameRecordType = 0;
#                        }#else  if ($MultiKeyLevelForNode ne 0)
#                    }else{
#                        #$bSameRecordType = 1;  # 1 or 0 seems to work.
#                        $bSameRecordType = 0;
#                    }#else if ($LineInfo{$MULTIKEY_STATE})
#                    last SWITCH;
#                }#if($LineInfo{$ACTION} eq $SEARCH)

                #Continue processing current record on child at Current Pivot of line since  REC_MULTIPLE_CONT Action:PARSE 
                if ($LineInfo{$ACTION} eq $PARSE){
                    $bSameRecordType = 1;  if ($bQStat){QuickStat(\%PDBNode,\%LineInfo,"PDBTree()"," Chk: Processing & Parse. SameRecType=1");}
                    last SWITCH;
                }#if
                #Continue processing current record on other children of parent at Current Pivot of line since  REC_MULTIPLE_CONT Action:PARSE_*
                if ($LineInfo{$ACTION} eq $PARSE_TO_MULTI_CHILDREN){
                    if ($bQStat){QuickStat(\%PDBNode,\%LineInfo,"PDBTree()"," Chk: MC&P'ing. PARSE_TO_MULTI_CHILDREN");}
                    #Ensure the current line is using a MultiKey
                    if ($LineInfo{$MULTIKEY_STATE}){
                        $MultiKeyLevelForNode = GetMultiKeyOfLineMatchingPDBNode(\%PDBNode, \%LineInfo);
                        if ($MultiKeyLevelForNode){  #Determine if there is a multi key of the LineInfo matching the current node.
                            $bSameRecordType = 1;
                        }#if
                    }#if
                    if ($bVerify){STDERR->print("#### Cont process current record on child at  C. Pivot  REC_MULTIPLE_CONT Action:PARSE  ###\n");}
                    last SWITCH;
                }#if

                default:{#Content must occur once, and only once.
                    if ($bQStat){QuickStat(\%PDBNode,\%LineInfo,"PDBTree()"," No switch case caught this pass;Chk was: SC or MC.");}
#STDERR->print (" PROCESSED: default: \n");
                    last SWITCH;
                }#default
            }#SWITCH
        }#if ($LineInfo{$LINE_STATUS} eq $PROCESSING)
    }#SWITCH
    %{$refPDBNode}    = %PDBNode;
    %{$refLineInfo}   = %LineInfo;
    %{$refNewPDBNode} = %NewPDBNode;
    $$refbSameRecordType = $bSameRecordType;
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function ReviewMultipleCont()\n");}
    $returnStatus = 1;
    return ($returnStatus);
}#ReviewMultipleCont()

#############################################################################
## FUNCTION:     ReviewOther()
## PURPOSE:      Processes one to many LineInfo lines needed to satify the PDB node.
## PARAMETERS:   $refPDBNode   - [IN]     A hash reference containing the Current PDB Node hash.
##               $refLineInfo  - [IN/OUT] A hash reference containing a LineInfo hash.
## RETURN:       
#############################################################################
sub ReviewOther{
    my $refPDBNode          =  0;
    my $refLineInfo         =  0;
    my $refbSameRecordType  =  0;
    my %PDBNode             = [];
    my %LineInfo            = [];
    my $bSameRecordType     =  0;
    my $EntryIDCount        =  0;
    my $NextRecordName      = "";
    my $MultiKeyLevelForNode = 0;
    my $SharedMultiKeyLevel =  0;
    my $NewMasterPivot      =  0;
    my $returnStatus        = "";
    my $EntryIDCount        =  0;
    my $StatusResult        =  0;
    my @StatusMsg           = ();

    ($refPDBNode, $refLineInfo, $refbSameRecordType)  = @_;
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function ReviewOther()\n");}
    %PDBNode  = %{$refPDBNode};
    %LineInfo = %{$refLineInfo};
    $bSameRecordType = $$refbSameRecordType;

#    PrintNodeReport(\%PDBNode, "PDB");
#    PrintLineReport(\%LineInfo);

    SWITCH: {
        if ($LineInfo{$LINE_STATUS} eq $PROCESSED){# Process next simular record on child at M. Rec: $LineInfo{$RECORD_NAME} Type:MC Action:PARSE
            if ($bQStat){QuickStat(\%PDBNode,\%LineInfo,"PDBTree()"," Chk: MC & Processed.");}
            #Ensure the current line is using a MultiKey
            if ($LineInfo{$MULTIKEY_STATE}){
                $MultiKeyLevelForNode = GetMultiKeyOfLineMatchingPDBNode(\%PDBNode, \%LineInfo);
                $SharedMultiKeyLevel = CompareFieldsOfLineToNextBasedOnMKeys(\%LineInfo,0);
                # Node > 0 Prevents the 0 = 0 case where neither match, but would be allow to do code for actual matching
                if (($MultiKeyLevelForNode > 0) && ($MultiKeyLevelForNode eq $SharedMultiKeyLevel)){#Determine if current and next line's
                    $bSameRecordType = 1;                            #greatest common shared key, match the current nodes MultiKey.
                    GetNewRecordLine(\%LineInfo);
                }else{
                    GetNewRecordLine(\%LineInfo);
                }#else
            }else{
                GetNewRecordLine(\%LineInfo);
            }#else ($LineInfo{$MULTIKEY_STATE}){
            last SWITCH;
        }#if
    }#SWITCH
    %{$refPDBNode}    = %PDBNode;
    %{$refLineInfo}   = %LineInfo;
    $$refbSameRecordType = $bSameRecordType;
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function ReviewOther()\n");}
    $returnStatus = 1;
    return ($returnStatus);
}#ReviewOther()

############################################################################################################################
############################################################################################################################
############################################################################################################################
############################################################################################################################

#############################################################################
## FUNCTION:     BuildOTHERTree()
## PURPOSE:      Processes one to many LineInfo lines needed to satify the PDB node.
## PARAMETERS:   $refPDBNode   - [IN]     A hash reference containing the Current PDB Node hash.
##               $refLineInfo  - [IN/OUT] A hash reference containing a LineInfo hash.
## RETURN:       
#############################################################################
sub BuildOTHERTree{
    # Trees & Current Line
    my $refPDBNode          =  0;
    my $refDTDNode          =  0;
    my $refLineInfo         =  0;
    my %PDBNode             = [];
    my %DTDNode             = [];
    my %LineInfo            = [];

    my $FunctionName        =  0;
    my $FunctionCall        =  0;
    my $returnStatus        = "";
    my @StatusMsg           = ();
    my $StatusResult        =  0;
    my @StatusResultMsg     = ();

    ($refPDBNode, $refDTDNode, $refLineInfo) = @_;

    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function BuildOTHERTree()\n");}
    %PDBNode  = %{$refPDBNode};
    %DTDNode  = %{$refDTDNode};
    %LineInfo = %{$refLineInfo};
    if (($bRunTimeDebug eq 0) && ($bVerify eq 0) && ($bLineProcess eq 0) && ($bQStat eq 0)){STDERR->print(".");}
    if ($bVerify){STDERR->print("##*********** Entering: BuildOTHERTree($PDBNode{$ELEMENT_NAME} Node) **********\n");}
    if ($bVerify){PrintNodeReport(\%DTDNode, "DTD");}
    if ($bVerify){PrintNodeReport(\%PDBNode, "PDB");}
    if ($bVerify){PrintLineReport(\%LineInfo);}

    $PDBNode{$NODE_VISIT_STATUS} = $VISIT_STATUS_GREY;
    ($StatusResult, @StatusResultMsg) = VisitPDBNode(\%PDBNode, \%LineInfo);
    if ($LineInfo{$LINE_STATUS} eq $PROCESSING){
        ($StatusResult, $FunctionName, @StatusMsg) = GetPDBToDTDField($LineInfo{$RECORD_NAME}, $FUNCTION_NAME, "");
        $FunctionCall = \&$FunctionName;
        &$FunctionCall(\%PDBNode, \%DTDNode, \%LineInfo);
    }#if
    %{$refPDBNode}    = %PDBNode;
    %{$refDTDNode}    = %DTDNode;
    %{$refLineInfo}   = %LineInfo;
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function BuildOTHERTree()\n");}
    $returnStatus = 1;
    return ($returnStatus);
}#BuildOTHERTree()

############################################################################################################
############################################################################################################
####
####
####
####
####
############################################################################################################
############################################################################################################


##############################################################################
### FUNCTION:     ProcessSEQRES()
### PURPOSE:      Processes one to many LineInfo lines needed to satify the PDB node.
### PARAMETERS:   $refPDBNode   - [IN]     A hash reference containing the Current PDB Node hash.
###               $refLineInfo  - [IN/OUT] A hash reference containing a LineInfo hash.
### RETURN:       
##############################################################################
sub ProcessSEQRES{
    # Trees & Current Line
    my $refPDBNode          =  0;
    my $refLineInfo         =  0;
    my $refNewPDBNode       =  0;
    my $refDTDNode          =  0;
    my $refbSameRecordType  =  0;
    my %PDBNode             = [];
    my %LineInfo            = [];
    my %NewPDBNode          = [];
    my %DTDNode             = [];

    my $PDBLine             = "";
    my $RecordName          = "";
    my $FormatStr           = "";
    my $SeqID               = "";
    my $ResidueNumber       = "";
    my $CurrentLine         = "";
    my $CurrName            = "";
    my $CurrSeqID           = "";
    my $CurrResidueNumber   = "";
    my $PrevLine            = "";
    my $PrevResidueName     = "";
    my $PrevFormatStr       = "";
    my $NextResidueName     = "";
    my $NextFormatStr       = "";

    my @NewChain            = ();
    my @SeqResidueList      = ();
    my $ChainLine           = "";
    my @ChainList           = ();

    my @ChildNodeList       = ();
    my @NewChildNodeList    = ();
    my $TmpChildNode        = "";
    my $ChildInstance       = "";
    my $OccurrenceSign      =  0;
    my $ResidueName         = "";
    my $Header              = "";
    my $NewLine             = "";
    my $bStopProcessing     =  0;#MUST BE FALSE

    my $refChainList        = ();
    my %Residue             = [];
    my @PhiPsiChainList     = ();
    my$RedidueCount         =  0;

    my $StatusResult        =  0;
    my @StatusResultMsg     = ();
    my $returnStatus        = "";
    my @returnStatusMsg     = ();


    ($refPDBNode, $refDTDNode, $refLineInfo)  = @_;
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function ProcessSEQRES()\n");}
    %PDBNode    = %{$refPDBNode};
    %DTDNode    = %{$refDTDNode};
    %LineInfo   = %{$refLineInfo};

    if ($bVerify){STDERR->print("##*********** Entering: ProcessSEQRES($PDBNode{$ELEMENT_NAME} Node) **********\n");}
    if ($bVerify){PrintNodeReport(\%DTDNode, "DTD"); PrintNodeReport(\%PDBNode, "PDB"); PrintLineReport(\%LineInfo);}
	$PDBLine   = $LineInfo{$PDB_LINE};
    $RecordName    = GetRecordField($PDBLine, '1_6');
    $SeqID         = GetRecordField($PDBLine, '12_12');
    $ResidueNumber = GetRecordField($PDBLine, '14_17');
    $ResidueNumber =~ s/^\s+//;
    $ResidueNumber =~ s/\s+$//;
    @ChildNodeList = @{$PDBNode{$ref_CHILDNODE_LIST}};

    #Process First child
    $TmpChildNode = shift(@ChildNodeList);
    $TmpChildNode =~ s/^\s+//;
    $TmpChildNode =~ s/\s+$//;
    $ChildInstance = 1;
    ($OccurrenceSign) = RemoveOccurrenceSign(\$TmpChildNode);  # Output: Reversed for later use.
    my %NewPDBNode = [];
    CreatePDBNode(\%PDBNode, \%NewPDBNode, $DTDNode{$TmpChildNode});
    if ($bVerify){STDERR->print ("##******** Calling: BuildSEQRESTree(PDBNode{${TmpChildNode}_${ChildInstance}})\n");}
    ($StatusResult, @StatusResultMsg) = BuildSEQRESTree(\%NewPDBNode, $DTDNode{$TmpChildNode}, \%LineInfo);
    if ($bVerify){STDERR->print ("##******** Returning To: ProcessSEQRES($PDBNode{$ELEMENT_NAME} Node) **********\n");}
    # If the child node didn't get data or is not BLACK by its dedescendants then toss it away.
    if ($NewPDBNode{$NODE_VISIT_STATUS} eq $VISIT_STATUS_BLACK){
        if (($PDBNode{$NODE_VISIT_STATUS} eq $VISIT_STATUS_GREY) && (grep(/^$PDB_ID$/, @{$PDBNode{$ref_ATTRIBUTE_NAME_LIST}}))){
            $PDBNode{$BEGIN_TAG} =~ s/$PDB_ID/$PDB_ID=\"$g_pdb_id\"/;
        }#if
        if ($bVerify){STDERR->print ("##** $PDBNode{$ELEMENT_NAME} made BLACK by child $NewPDBNode{$ELEMENT_NAME}\n");}
        $PDBNode{$NODE_VISIT_STATUS} = $VISIT_STATUS_BLACK;
        push @NewChildNodeList, "${TmpChildNode}_${ChildInstance}";#Children instance names to attached to parent, once all are processed.
        $PDBNode{"${TmpChildNode}_${ChildInstance}"} = \%NewPDBNode;
    }#if

    #Process Second child
    $TmpChildNode = shift(@ChildNodeList);
    $TmpChildNode =~ s/^\s+//;
    $TmpChildNode =~ s/\s+$//;
    $ChildInstance = 1;
    ($OccurrenceSign) = RemoveOccurrenceSign(\$TmpChildNode);  # Output: Reversed for later use.
    @NewChain = ();
    @SeqResidueList = grep /^SEQRES/, @g_PDBRecordFileList;
    unshift @SeqResidueList, $PDBLine;
    while ($CurrentLine = shift(@SeqResidueList)){
        $CurrSeqID         = GetRecordField($CurrentLine, '12_12');
        $CurrResidueNumber = GetRecordField($CurrentLine, '14_17');
        $CurrResidueNumber =~ s/^\s+//;
        $CurrResidueNumber =~ s/\s+$//;
        if (($CurrSeqID eq $SeqID) && ($CurrResidueNumber eq $ResidueNumber)){
            $ChainLine = GetRecordField($CurrentLine, '20_70');
            @ChainList = split(/\s+/,$ChainLine);
            push @NewChain, @ChainList;
        }#if
    }#while

    if (defined $g_PhiPsiChainHash{$SeqID}){
        $refChainList = $g_PhiPsiChainHash{$SeqID};
        @PhiPsiChainList = @{$refChainList};
    }#if
    $RedidueCount = 0;
    while ($ResidueName = shift(@NewChain)){
        if ( defined $PhiPsiChainList[$RedidueCount]){
            %Residue = %{$PhiPsiChainList[$RedidueCount]};
            ${%{$SEQRES_TABLE{$ResidueName}}}{$PHI_ANGLE} = $Residue{$PHI};
            ${%{$SEQRES_TABLE{$ResidueName}}}{$PSI_ANGLE} = $Residue{$PSI};
            ${%{$SEQRES_TABLE{$ResidueName}}}{$RAMACHANDRAN} = $Residue{$RAMACHANDRAN};
        }#if
        $Header    = GetRecordField($PDBLine, '1_17');
        $FormatStr = sprintf ("%-4s", $ResidueName);
        $NewLine   = "$Header  $FormatStr";
        $LineInfo{$PDB_LINE} = $NewLine;
        $LineInfo{$ENTRY_ID_COUNT} = $RedidueCount+1;
        my %NewPDBNode = [];
        CreatePDBNode(\%PDBNode, \%NewPDBNode, $DTDNode{$TmpChildNode});#!!!!!!!!!!!!!!!!!!!!!!!!!
        if ($bVerify){STDERR->print ("##******** Calling: BuildSEQRESTree(PDBNode{${TmpChildNode}_${ChildInstance}})\n");}
        ($StatusResult, @StatusResultMsg) = BuildSEQRESTree(\%NewPDBNode, $DTDNode{$TmpChildNode}, \%LineInfo);
        if ($bVerify){STDERR->print ("##******** Returning To: ProcessSEQRES($PDBNode{$ELEMENT_NAME} Node) **********\n");}
        # If the child node didn't get data or is not BLACK by its dedescendants then toss it away.
        if ($NewPDBNode{$NODE_VISIT_STATUS} eq $VISIT_STATUS_BLACK){
            if (($PDBNode{$NODE_VISIT_STATUS} eq $VISIT_STATUS_GREY) && (grep(/^$PDB_ID$/, @{$PDBNode{$ref_ATTRIBUTE_NAME_LIST}}))){
                $PDBNode{$BEGIN_TAG} =~ s/$PDB_ID/$PDB_ID=\"$g_pdb_id\"/;
            }#if
            if ($bVerify){STDERR->print ("##** $PDBNode{$ELEMENT_NAME} made BLACK by child $NewPDBNode{$ELEMENT_NAME}\n");}
            $PDBNode{$NODE_VISIT_STATUS} = $VISIT_STATUS_BLACK;
            push @NewChildNodeList, "${TmpChildNode}_${ChildInstance}";#Children instance names to attached to parent, once all are processed.
            $PDBNode{"${TmpChildNode}_${ChildInstance}"} = \%NewPDBNode;
            $ChildInstance++;
        }#if
        $RedidueCount = $RedidueCount + 1;
    }#while


    @{$PDBNode{$ref_CHILDNODE_LIST}} = @NewChildNodeList;
    while (!$bStopProcessing){
        my $TmpLine = $g_PDBRecordFileList[0];
        $CurrName          = GetRecordField($TmpLine, '1_6');
        $CurrSeqID         = GetRecordField($TmpLine, '12_12');
        $CurrResidueNumber = GetRecordField($TmpLine, '14_17');
        $CurrResidueNumber =~ s/^\s+//;
        $CurrResidueNumber =~ s/\s+$//;
        if (($RecordName eq $CurrName) && ($SeqID eq $CurrSeqID) && ($ResidueNumber eq $CurrResidueNumber)){
            $PrevLine = shift(@g_PDBRecordFileList);
        }else{
            $bStopProcessing = 1;
        }#else
    }#while
    if ( $PrevLine ne ""){$LineInfo{$PDB_LINE} = $PrevLine;}
    push @{$LineInfo{$ref_USED_KEYS}},  shift(@{$LineInfo{$ref_CURR_KEYS}});
    UpdatePivotPoint(\%LineInfo);
    $LineInfo{$LINE_STATUS} = $PROCESSED;
    if ($bVerify){PrintNodeReport(\%DTDNode, "DTD"); PrintNodeReport(\%PDBNode, "PDB"); PrintLineReport(\%LineInfo);}
    if ($bVerify){STDERR->print("##*********** Leaving: ProcessSEQRES($PDBNode{$ELEMENT_NAME} Node) **********\n");}
    %{$refPDBNode}    = %PDBNode;
    %{$refLineInfo}   = %LineInfo;
    %{$refDTDNode}    = %DTDNode;
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function ProcessSEQRES()\n");}
    $returnStatus = 1;
    return ($returnStatus, @returnStatusMsg);
}#ProcessSEQRES()

############################################################################
# FUNCTION:     BuildSEQRESTree()
# PURPOSE:      Build a tree of the PDB Instance tree.
# PARAMETERS:   $refPDBNode  - [IN] A hash reference containing the Current PDB Node hash.
#               $refDTDNode  - [IN] A hash reference containing the Current DTD Node hash.
#               $refLineInfo - [IN/OUT] A hash reference containing a LineInfo hash.
#               
# RETURN:       TRUE for success, otherwise FALSE.
############################################################################
sub BuildSEQRESTree{

    # Trees & Current Line
    my $refPDBNode       =  0;
    my $refDTDNode       =  0;
    my %PDBNode          = [];
    my %DTDNode          = [];
    my $refLineInfo      =  0;
    my %LineInfo         = [];

    my $TmpChildNode     = "";
    my @ProcessedChildNodeNames = ();
    my @ChildNodeList    = ();
    my @NewChildNodeList = ();
    my @UnprocessedList  = ();
    my @TmpChildNodeList = ();
    my $ChildInstance    =  0;
    my $ProcessNewChild  =  0;
    my $bSameRecordType  =  1;
    my $bStopProcessing  =  0; #MUST BE FALSE
    my $bCreateMultiInstancesOfChildType =  0;

    my @TotalChildNodeNames = ();
    my $TmpNode = "";
    my $NextRecord = "";
    my $Token = "";
    my $DTDElementName = "";

    # Status information
    my $OccurrenceSign   =  0;
    my $FormatMsg        = "";
    my $StatusMsg        = ""; 
    my @StatusMsg        = ();
    my $StatusResult     =  0;
    my @StatusResultMsg  = ();
    my $returnStatus     =  0;
    my @returnStatusMsg  = ();

    #\%PDBInstanceTree \%DTDTree
    ($refPDBNode, $refDTDNode, $refLineInfo) = @_;

    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function BuildSEQRESTree()\n");}
    %PDBNode = %{$refPDBNode};
    %DTDNode = %{$refDTDNode};
    %LineInfo = %{$refLineInfo};

    if (($bRunTimeDebug eq 0) && ($bVerify eq 0) && ($bLineProcess eq 0) && ($bQStat eq 0)){STDERR->print(".");}
    if ($bVerify){STDERR->print("##*********** Entering: BuildSEQRESTree($PDBNode{$ELEMENT_NAME} Node) **********\n");}
    if ($bVerify){PrintNodeReport(\%DTDNode, "DTD");}
    if ($bVerify){PrintNodeReport(\%PDBNode, "PDB");}
    if ($bVerify){PrintLineReport(\%LineInfo);}
    $PDBNode{$NODE_VISIT_STATUS} = $VISIT_STATUS_GREY;
    ($StatusResult, @StatusResultMsg) = VisitSEQRESNode(\%PDBNode, \%LineInfo);########## VisitPDBNode ############
    if ( $StatusResult eq 0){
        push @returnStatusMsg, @StatusResultMsg;
        return(0, @returnStatusMsg);
    }#if

    ###############################################################
    # Create new children Nodes on the PDB tree by traversing the DTD tree and reading PDB records.
    ###############################################################
    if ($DTDNode{$ELEMENT_CATEGORY} eq $ELEM_CAT_LIST){
        @ChildNodeList = @{$PDBNode{$ref_CHILDNODE_LIST}};
        if ($bVerify){STDERR->print ("##*********** Start Visiting Children ********\n");}
        #foreach $TmpChildNode (@ChildNodeList){
        while (($TmpChildNode = shift(@ChildNodeList)) && (! $bStopProcessing)){
            $TmpChildNode =~ s/^\s+//;
            $TmpChildNode =~ s/\s+$//;
            $ChildInstance = (grep /^${TmpChildNode}_\d+/, @NewChildNodeList) + 1; #New 20050213
            $ProcessNewChild = 1;
            ($OccurrenceSign, $bCreateMultiInstancesOfChildType) = RemoveOccurrenceSign(\$TmpChildNode);  # Output: Reversed for later use.
            #list of processed children in case a record type appears again after processing other record types.
            push @ProcessedChildNodeNames, $TmpChildNode;
            if ($bVerify){STDERR->print("##******** New child: \"$TmpChildNode\"\n");}
            my %NewPDBNode = [];
            CreatePDBNode(\%PDBNode, \%NewPDBNode, $DTDNode{$TmpChildNode});
            if ($bVerify){STDERR->print ("##******** Calling: BuildSEQRESTree(PDBNode{${TmpChildNode}_${ChildInstance}})\n");}
            ($StatusResult, @StatusResultMsg) = BuildSEQRESTree(\%NewPDBNode, $DTDNode{$TmpChildNode}, \%LineInfo);
            if ($bVerify){STDERR->print ("##******** Returning To: BuildSEQRESTree($PDBNode{$ELEMENT_NAME} Node) **********\n");}
            if ( $StatusResult eq 0){
                push @returnStatusMsg, @StatusResultMsg;
                return(0, @returnStatusMsg);
            }#if
            # If the child node didn't get data or is not BLACK by its dedescendants then toss it away.
            if ($NewPDBNode{$NODE_VISIT_STATUS} eq $VISIT_STATUS_BLACK){
                if (($PDBNode{$NODE_VISIT_STATUS} eq $VISIT_STATUS_GREY) && (grep(/^$PDB_ID$/, @{$PDBNode{$ref_ATTRIBUTE_NAME_LIST}}))){
                    $PDBNode{$BEGIN_TAG} =~ s/$PDB_ID/$PDB_ID=\"$g_pdb_id\"/;
                }#if
                if ($bVerify){STDERR->print ("##** $PDBNode{$ELEMENT_NAME} made BLACK by child $NewPDBNode{$ELEMENT_NAME}\n");}
                $PDBNode{$NODE_VISIT_STATUS} = $VISIT_STATUS_BLACK;
                push @NewChildNodeList, "${TmpChildNode}_${ChildInstance}";#Children instance names to attached to parent, once all are processed.
                $PDBNode{"${TmpChildNode}_${ChildInstance}"} = \%NewPDBNode;
                $ChildInstance++;
            }#if
        }#while (($TmpChildNode = shift(@ChildNodeList)) && (! $bStopProcessing))
        @{$PDBNode{$ref_CHILDNODE_LIST}} = @NewChildNodeList;
        if ($bVerify){STDERR->print ("##*********** Finished Visiting Children *****\n");}
    }#if
    %{$refPDBNode} = %PDBNode;
    %{$refDTDNode} = %DTDNode;
    %{$refLineInfo} = %LineInfo;
    if ($bVerify){ PrintNodeReport(\%PDBNode, "PDB"); PrintLineReport(\%LineInfo); }
    if ($bVerify){STDERR->print ("##*********** Leaving: BuildSEQRESTree($PDBNode{$ELEMENT_NAME} Node) **********\n");}
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function BuildSEQRESTree()\n");}
    $returnStatus = 1;
    return ($returnStatus, @returnStatusMsg);
}#BuildSEQRESTree()

############################################################################
# FUNCTION:     VisitSEQRESNode()
# PURPOSE:      Processes one to many LineInfo lines needed to satify the PDB node.
# PARAMETERS:   $refPDBNode - [IN] A hash reference containing the Current PDB Node hash.
#               $refLineInfo  - [IN/OUT] A hash reference containing a LineInfo hash.
# RETURN:       TRUE for success, otherwise FALSE.
############################################################################
sub VisitSEQRESNode{

    my $refPDBNode            =  0;
    my $refLineInfo           =  0;
    my %PDBNode               =  0;
    my %LineInfo              = [];

    my $CurrentLine           = "";
    my $SeqID                 = "";
    my $DTDFieldName          = "";
    my $ResidueNumber         = "";
    my $Residue               = "";
    my $PDBRecordName         = "";
    my @ResidueList           = ();
    my $Data                  = "";
    my $bSatistfied           =  0;#MUST BE FALSE

    my $StatusResult          =  0;
    my @StatusResultMsg       = ();
    my $returnStatus          = "";
    my @returnStatusMsg       = ();
    my $FormatMsg             = "";

    ($refPDBNode, $refLineInfo)  = @_;

    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function VisitSEQRESNode()\n");}
    %PDBNode= %{$refPDBNode};
    %LineInfo= %{$refLineInfo};
    if ($bVerify){STDERR->print ("##*********** Start    Visiting Node \"$PDBNode{$ELEMENT_NAME}\"\n");}

    $CurrentLine = $LineInfo{$PDB_LINE};
    $PDBRecordName = $LineInfo{$RECORD_NAME};
    $SeqID = GetRecordField($CurrentLine, '12_12');
    $ResidueNumber = GetRecordField($CurrentLine, '14_17');
    $ResidueNumber =~ s/^\s+//;
    $ResidueNumber =~ s/\s+$//;
    SWITCH: {
        if ($PDBNode{$ELEMENT_NAME} eq "whole_sequence"){
            $PDBNode{$BEGIN_TAG} =~ s/$PDB_ID/$PDB_ID=\"$g_pdb_id\"/;
            ($StatusResult, $DTDFieldName, @StatusResultMsg) = GetPDBToDTDField($PDBRecordName, $REF_FIELD, '12_12');
            if (grep /$DTDFieldName=\"\w+\"/, $PDBNode{$BEGIN_TAG}){
                $PDBNode{$BEGIN_TAG} =~ s/$DTDFieldName=\"\w+\"/$DTDFieldName=\"$SeqID\"/;
            }else{
                $PDBNode{$BEGIN_TAG} =~ s/$DTDFieldName/$DTDFieldName=\"$SeqID\"/;
            }#else
            ($StatusResult, $DTDFieldName, @StatusResultMsg) = GetPDBToDTDField($PDBRecordName, $REF_FIELD, '14_17');
            if (grep /$DTDFieldName=\"\w+\"/, $PDBNode{$BEGIN_TAG}){
                $PDBNode{$BEGIN_TAG} =~ s/$DTDFieldName=\"\w+\"/$DTDFieldName=\"$ResidueNumber\"/;
            }else{
                $PDBNode{$BEGIN_TAG} =~ s/$DTDFieldName/$DTDFieldName=\"$ResidueNumber\"/;
            }#else
            #If the element actually received data mark black.
            if (($SeqID ne "") && ($ResidueNumber ne "")){
                $PDBNode{$NODE_VISIT_STATUS} = $VISIT_STATUS_BLACK;
                $PDBNode{$NODE_STATUS} = $SATISFIED;
            }#if
            if (0){PrintNodeReport(\%PDBNode, "PDB"); PrintLineReport(\%LineInfo);}
            last SWITCH;
        }#if
        if ($PDBNode{$ELEMENT_NAME} eq "sequence_residues"){
            $PDBNode{$BEGIN_TAG} =~ s/$PDB_ID/$PDB_ID=\"$g_pdb_id\"/;
            ($StatusResult, $DTDFieldName, @StatusResultMsg) = GetPDBToDTDField($PDBRecordName, $REF_FIELD, '12_12');
            if (grep /$DTDFieldName=\"\w+\"/, $PDBNode{$BEGIN_TAG}){
                $PDBNode{$BEGIN_TAG} =~ s/$DTDFieldName=\"\w+\"/$DTDFieldName=\"$SeqID\"/;
            }else{
                $PDBNode{$BEGIN_TAG} =~ s/$DTDFieldName/$DTDFieldName=\"$SeqID\"/;
            }#else
            ($StatusResult, $DTDFieldName, @StatusResultMsg) = GetPDBToDTDField($PDBRecordName, $REF_FIELD, '14_17');
            if (grep /$DTDFieldName=\"\w+\"/, $PDBNode{$BEGIN_TAG}){
                $PDBNode{$BEGIN_TAG} =~ s/$DTDFieldName=\"\w+\"/$DTDFieldName=\"$ResidueNumber\"/;
            }else{
                $PDBNode{$BEGIN_TAG} =~ s/$DTDFieldName/$DTDFieldName=\"$ResidueNumber\"/;
            }#else
            ($StatusResult, $DTDFieldName, @StatusResultMsg) = GetPDBToDTDField($PDBRecordName, $LOGICAL_REC_COUNT, '');
            my $ResidueCount = $LineInfo{$ENTRY_ID_COUNT};
            if (grep /$DTDFieldName=\"\w+\"/, $PDBNode{$BEGIN_TAG}){
                $PDBNode{$BEGIN_TAG} =~ s/$DTDFieldName=\"\w+\"/$DTDFieldName=\"$ResidueCount\"/;
            }else{
                $PDBNode{$BEGIN_TAG} =~ s/$DTDFieldName/$DTDFieldName=\"$ResidueCount\"/;
            }#else
            #If the element actually received data mark black.
            if (($SeqID ne "") && ($ResidueNumber ne "")){
                $PDBNode{$NODE_VISIT_STATUS} = $VISIT_STATUS_BLACK;
                $PDBNode{$NODE_STATUS} = $SATISFIED;
            }#if
            if (0){PrintNodeReport(\%PDBNode, "PDB"); PrintLineReport(\%LineInfo);}
            last SWITCH;
        }#if

        if ($PDBNode{$ELEMENT_NAME} eq "sequence_residue"){
             $PDBNode{$BEGIN_TAG} =~ s/$PDB_ID/$PDB_ID=\"$g_pdb_id\"/;
            ($StatusResult, $DTDFieldName, @StatusResultMsg) = GetPDBToDTDField($PDBRecordName, $REF_FIELD, '12_12');
            if (grep /$DTDFieldName=\"\w+\"/, $PDBNode{$BEGIN_TAG}){
                $PDBNode{$BEGIN_TAG} =~ s/$DTDFieldName=\"\w+\"/$DTDFieldName=\"$SeqID\"/;
            }else{
                $PDBNode{$BEGIN_TAG} =~ s/$DTDFieldName/$DTDFieldName=\"$SeqID\"/;
            }#else
            #If the element actually received data mark black.
            if ($SeqID ne ""){
                $PDBNode{$NODE_VISIT_STATUS} = $VISIT_STATUS_BLACK;
                $PDBNode{$NODE_STATUS} = $SATISFIED;
            }#if
            if (0){PrintNodeReport(\%PDBNode, "PDB"); PrintLineReport(\%LineInfo);}
            last SWITCH;
        }#if

        if ($PDBNode{$ELEMENT_NAME} eq "one_letter_seq"){
            my @SeqResidueList = grep /^SEQRES/, @g_PDBRecordFileList;
            unshift @SeqResidueList, $CurrentLine;
            while ($CurrentLine = shift(@SeqResidueList)){
                my $CurrSeqID         = GetRecordField($CurrentLine, '12_12');
                my $CurrResidueNumber = GetRecordField($CurrentLine, '14_17');
                $CurrResidueNumber =~ s/^\s+//;
                $CurrResidueNumber =~ s/\s+$//;
                if (($CurrSeqID eq $SeqID) && ($CurrResidueNumber eq $ResidueNumber)){
                    push @ResidueList, $CurrentLine;
                }#if
            }#while
            my $OneLetterSeq = PDB1LetterSeqs(0, \@ResidueList);
            $PDBNode{$PCDATA} = $OneLetterSeq;
            if ($PDBNode{$PCDATA} ne ""){$bSatistfied = 1;}
            last SWITCH;
        }#if

        if ($PDBNode{$ELEMENT_NAME} eq "three_letter_seq"){
            my @NewChain = "";
            my @SeqResidueList = grep /^SEQRES/, @g_PDBRecordFileList;
            unshift @SeqResidueList, $CurrentLine;
            while ($CurrentLine = shift(@SeqResidueList)){
                my $CurrSeqID         = GetRecordField($CurrentLine, '12_12');
                my $CurrResidueNumber = GetRecordField($CurrentLine, '14_17');
                $CurrResidueNumber =~ s/^\s+//;
                $CurrResidueNumber =~ s/\s+$//;
                if (($CurrSeqID eq $SeqID) && ($CurrResidueNumber eq $ResidueNumber)){
                    my $ChainLine = GetRecordField($CurrentLine, '20_70');
                    my @ChainList = split(/\s+/,$ChainLine);
                    push @NewChain, @ChainList;
                }#if
            }#while
            $PDBNode{$PCDATA} = join ' ', @NewChain;
            $PDBNode{$PCDATA} =~ s/^\s+//;
            $PDBNode{$PCDATA} =~ s/\s+$//;
            if ($PDBNode{$PCDATA} ne ""){$bSatistfied = 1;}
            last SWITCH;
        }#if

        if ($PDBNode{$ELEMENT_NAME} eq "residue_name"){
            $Residue = GetRecordField($CurrentLine, '20_23');
            $Residue =~ s/^\s+//;
            $Residue =~ s/\s+$//;
            $Data = ${%{$SEQRES_TABLE{$Residue}}}{$RESIDUE_NAME};
            $PDBNode{$PCDATA} = $Data;
            if ($PDBNode{$PCDATA} ne ""){$bSatistfied = 1;}
            if (0){PrintNodeReport(\%PDBNode, "PDB"); PrintLineReport(\%LineInfo);}
            last SWITCH;
        }#if
        if ($PDBNode{$ELEMENT_NAME} eq "one_letter_name"){
            $Residue = GetRecordField($CurrentLine, '20_23');
            $Residue =~ s/^\s+//;
            $Residue =~ s/\s+$//;
            $Data = ${%{$SEQRES_TABLE{$Residue}}}{$ONE_LETTER_RESIDUE};
            $PDBNode{$PCDATA} = $Data;
            if ($PDBNode{$PCDATA} ne ""){$bSatistfied = 1;}
            if (0){PrintNodeReport(\%PDBNode, "PDB"); PrintLineReport(\%LineInfo);}
            last SWITCH;
        }#if
        if ($PDBNode{$ELEMENT_NAME} eq "three_letter_name"){
            $Residue = GetRecordField($CurrentLine, '20_23');
            $Residue =~ s/^\s+//;
            $Residue =~ s/\s+$//;
            $Data = ${%{$SEQRES_TABLE{$Residue}}}{$THREE_LETTER_RESIDUE};
            $PDBNode{$PCDATA} = $Data;
            if ($PDBNode{$PCDATA} ne ""){$bSatistfied = 1;}
            if (0){PrintNodeReport(\%PDBNode, "PDB"); PrintLineReport(\%LineInfo);}
            last SWITCH;
        }#if
        if ($PDBNode{$ELEMENT_NAME} eq "phi_angle"){
            $Residue = GetRecordField($CurrentLine, '20_23');
            $Residue =~ s/^\s+//;
            $Residue =~ s/\s+$//;
            $Data = ${%{$SEQRES_TABLE{$Residue}}}{$PHI_ANGLE};
            $PDBNode{$PCDATA} = $Data;
            if ($PDBNode{$PCDATA} ne ""){$bSatistfied = 1;}
            ${%{$SEQRES_TABLE{$Residue}}}{$PHI_ANGLE} = '';
            if (0){PrintNodeReport(\%PDBNode, "PDB"); PrintLineReport(\%LineInfo);}
            last SWITCH;
        }#if
        if ($PDBNode{$ELEMENT_NAME} eq "psi_angle"){
            $Residue = GetRecordField($CurrentLine, '20_23');
            $Residue =~ s/^\s+//;
            $Residue =~ s/\s+$//;
            $Data = ${%{$SEQRES_TABLE{$Residue}}}{$PSI_ANGLE};
            $PDBNode{$PCDATA} = $Data;
            if ($PDBNode{$PCDATA} ne ""){$bSatistfied = 1;}
            ${%{$SEQRES_TABLE{$Residue}}}{$PSI_ANGLE} = '';
            if (0){PrintNodeReport(\%PDBNode, "PDB"); PrintLineReport(\%LineInfo);}
            last SWITCH;
        }#if
        if ($PDBNode{$ELEMENT_NAME} eq "ramachandran"){
            $Residue = GetRecordField($CurrentLine, '20_23');
            $Residue =~ s/^\s+//;
            $Residue =~ s/\s+$//;
            $Data = ${%{$SEQRES_TABLE{$Residue}}}{$RAMACHANDRAN};
            $PDBNode{$PCDATA} = $Data;
            if ($PDBNode{$PCDATA} ne ""){$bSatistfied = 1;}
            ${%{$SEQRES_TABLE{$Residue}}}{$RAMACHANDRAN} = '';
            if (0){PrintNodeReport(\%PDBNode, "PDB"); PrintLineReport(\%LineInfo);}
            last SWITCH;
        }#if
        if ($PDBNode{$ELEMENT_NAME} eq "residue_weight"){
            $Residue = GetRecordField($CurrentLine, '20_23');
            $Residue =~ s/^\s+//;
            $Residue =~ s/\s+$//;
            $Data = ${%{$SEQRES_TABLE{$Residue}}}{$RESIDUE_WEIGHT};
            $PDBNode{$PCDATA} = $Data;
            if ($PDBNode{$PCDATA} ne ""){$bSatistfied = 1;}
            if (0){PrintNodeReport(\%PDBNode, "PDB"); PrintLineReport(\%LineInfo);}
            last SWITCH;
        }#if
        if ($PDBNode{$ELEMENT_NAME} eq "residue_formula"){
            $Residue = GetRecordField($CurrentLine, '20_23');
            $Residue =~ s/^\s+//;
            $Residue =~ s/\s+$//;
            $Data = ${%{$SEQRES_TABLE{$Residue}}}{$RESIDUE_FORMULA};
            $PDBNode{$PCDATA} = $Data;
            if ($PDBNode{$PCDATA} ne ""){$bSatistfied = 1;}
            if (0){PrintNodeReport(\%PDBNode, "PDB"); PrintLineReport(\%LineInfo);}
            last SWITCH;
        }#if
        if ($PDBNode{$ELEMENT_NAME} eq "hydrophobicity_Hopp_Woods"){
            $Residue = GetRecordField($CurrentLine, '20_23');
            $Residue =~ s/^\s+//;
            $Residue =~ s/\s+$//;
            $Data = ${%{$SEQRES_TABLE{$Residue}}}{$HYDROPHOBICITY_HOPP_WOODS};
            $PDBNode{$PCDATA} = $Data;
            if ($PDBNode{$PCDATA} ne ""){$bSatistfied = 1;}
            if (0){PrintNodeReport(\%PDBNode, "PDB"); PrintLineReport(\%LineInfo);}
            last SWITCH;
        }#if
        if ($PDBNode{$ELEMENT_NAME} eq "hydrophobicity_Kyte_Doolittle"){
            $Residue = GetRecordField($CurrentLine, '20_23');
            $Residue =~ s/^\s+//;
            $Residue =~ s/\s+$//;
            $Data = ${%{$SEQRES_TABLE{$Residue}}}{$HYDROPHOBICITY_KYTE_DOOLITTLE};
            $PDBNode{$PCDATA} = $Data;
            if ($PDBNode{$PCDATA} ne ""){$bSatistfied = 1;}
            if (0){PrintNodeReport(\%PDBNode, "PDB"); PrintLineReport(\%LineInfo);}
            last SWITCH;
        }#if
    }#SWITCH

    if ($bSatistfied){
        $PDBNode{$NODE_VISIT_STATUS} = $VISIT_STATUS_BLACK;
        $PDBNode{$NODE_STATUS} = $SATISFIED;
    }#if
    if ($bVerify){PrintNodeReport(\%PDBNode, "SEQRES Finished Visiting Node");}
    if ($bVerify){PrintLineReport(\%LineInfo);}
    if ($bVerify){STDERR->print ("##*********** Finished Visiting Node \"$PDBNode{$ELEMENT_NAME}\"\n");}
    %{$refPDBNode}  = %PDBNode;
    %{$refLineInfo} = %LineInfo;
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function VisitSEQRESNode()\n");}
    $returnStatus = 1;
    return ($returnStatus, @returnStatusMsg);
}#VisitSEQRESNode()

############################################################################################################
############################################################################################################
####
####
####
####
####
############################################################################################################
############################################################################################################


##############################################################################
### FUNCTION:     ()
### PURPOSE:      Processes one to many LineInfo lines needed to satify the PDB node.
### PARAMETERS:   $refPDBNode   - [IN]     A hash reference containing the Current PDB Node hash.
###               $refLineInfo  - [IN/OUT] A hash reference containing a LineInfo hash.
### RETURN:       
##############################################################################
#sub {
#    my $refPDBNode            =  0;
#    my $refLineInfo           =  0;
#    my %PDBNode               =  0;
#    my %LineInfo              = [];
#    my $NextRecordName        = "";
#    my $returnStatus          = "";

#    ($refPDBNode, $refLineInfo)  = @_;
#    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function ReviewRecord()\n");}
#    %PDBNode= %{$refPDBNode};
#    %LineInfo= %{$refLineInfo};

#    %{$refPDBNode}  = %PDBNode;
#    %{$refLineInfo} = %LineInfo;
#    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function ReviewRecord()\n");}
#    $returnStatus = 1;
#    return ($returnStatus, @returnStatusMsg);
#}#ReviewRecord()

############################################################################
# FUNCTION:     VisitPDBNode()
# PURPOSE:      Processes one to many LineInfo lines needed to satify the PDB node.
# PARAMETERS:   $refPDBNode - [IN] A hash reference containing the Current PDB Node hash.
#               $refLineInfo  - [IN/OUT] A hash reference containing a LineInfo hash.
# RETURN:       TRUE for success, otherwise FALSE.
############################################################################
sub VisitPDBNode{

    my $refPDBNode            =  0;
    my $refLineInfo           =  0;
    my %PDBNode               =  0;
    my %LineInfo              = [];
    my $NextRecordName        = "";
    my $bProcessAnotherRecord =  1;#MUST BE TRUE
    my $bDoVisitNode          =  0;#MUST BE FALSE

    my $StatusResult          =  0;
    my @StatusResultMsg       = ();
    my $returnStatus          = "";
    my @returnStatusMsg       = ();
    my $FormatMsg             = "";

    ($refPDBNode, $refLineInfo)  = @_;

    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function VisitPDBNode()\n");}
    %PDBNode= %{$refPDBNode};
    %LineInfo= %{$refLineInfo};
    if ($bVerify){STDERR->print ("##*********** Start    Visiting Node \"$PDBNode{$ELEMENT_NAME}\"\n");}
    ######################################### Determine if Visiting should be done #######################
#PrintNodeReport(\%PDBNode, "PDB Test"); PrintLineReport(\%LineInfo); #priceprice
    SWITCH: {
        if ($LineInfo{$PIVOT_ENTRY} eq $PDBNode{$ELEMENT_NAME}){
            $bDoVisitNode = 1;
            last SWITCH;
        }#if 
        if (($LineInfo{$LINE_STATUS} eq $PROCESSING) &&
            (($LineInfo{$RECORD_TYPE} eq $REC_MULTIPLE_CONT) || ($LineInfo{$RECORD_TYPE} eq $REC_MULTIPLE)) &&
            (($LineInfo{$PIVOT_ENTRY} eq $PDBNode{$ELEMENT_NAME}) || (grep /^$LineInfo{$PIVOT_ENTRY}$/, @{$PDBNode{$ref_ATTRIBUTE_NAME_LIST}}))){
            $bDoVisitNode = 1;
            last SWITCH;
        }#if 
        if ((grep /:/, $LineInfo{$PIVOT_ENTRY}) && (grep /$PDBNode{$ELEMENT_NAME}/, $LineInfo{$PIVOT_ENTRY})){#"atom_ter:het_ter";"atom_ter"||"het_ter"
            $bDoVisitNode = 1;
            last SWITCH;
        }#if 
        # If the line is has status of processing then the line is at the correct record, therefore to auto update the count is OK.
        # Note: the PROCESSING prevents other "branches" that do have id_count in them but the record is for a branch further down.
        if (($LineInfo{$LINE_STATUS} eq $PROCESSING) && (grep/id_count$/, @{$PDBNode{$ref_ATTRIBUTE_NAME_LIST}})){
            $bDoVisitNode = 1;
            last SWITCH;
        }#if
        default:{#Content must occur once, and only once.
            $bDoVisitNode = 0;
            last SWITCH;
        }#default
    }#SWITCH
    if ($bVerify){PrintNodeReport(\%PDBNode, "PDB"); PrintLineReport(\%LineInfo);STDERR->print ("bDoVisitNode = $bDoVisitNode\n");}
    if ($bDoVisitNode){
        while ($bProcessAnotherRecord){
            ProcessLine(\%PDBNode, \%LineInfo); ######################################### Process another Line #######################
            $bProcessAnotherRecord = 0;
            if ($bVerify){PrintNodeReport(\%PDBNode, "PDB Processed Node and Line"); PrintLineReport(\%LineInfo);}
            ######################################### Review for CONCAT #######################
            SWITCH: {
                #logically appears once over multiple lines otherwise dup. error. Subsequent lines contain a continuation field an incrementing counter.
                if ($LineInfo{$RECORD_TYPE} eq $REC_SINGLE_CONT){
                     ReviewSingleContVisit(\%PDBNode, \%LineInfo, \$bProcessAnotherRecord);
                    last SWITCH;
                }#if
                #May appear multiple times and logically over multiple lines. Subsequent lines contain a continuation field an 
                #incrementing counter.
                if ($LineInfo{$RECORD_TYPE} eq $REC_MULTIPLE_CONT){
                     ReviewMultipleContVisit(\%PDBNode, \%LineInfo, \$bProcessAnotherRecord);
                    last SWITCH;
                }#if
                #May appear multiple times, often the information is in list form and is not logically concatenated. These record  
                #types usually have a custom serialization to denote order and connect to other record types. 
                if ($LineInfo{$RECORD_TYPE} eq $REC_MULTIPLE){
                    last SWITCH;
                }#if
                #May appear only once, otherwise duplicate error.
                if ($LineInfo{$RECORD_TYPE} eq $REC_SINGLE){
                    last SWITCH;
                }#if
                # There are three record types used to group other records. The MODEL/ENDMDL records surround groups of ATOM, HETATM, SIGATM,
                # ANISOU, SIGUIJ, and TER records. TER records indicate the end of a chain.
                if ($LineInfo{$RECORD_TYPE} eq $REC_GROUP){
                    last SWITCH;
                }#if ($LineInfo{$RECORD_TYPE} eq $REC_GROUP)

                if ($LineInfo{$RECORD_TYPE} eq $REC_OTHER){ #The remaining record types have a detailed inner structure. 
                    last SWITCH;
                }#if 
                default:{#Content must occur once, and only once.
                    QuickStat(\%PDBNode,\%LineInfo,"PDBTree()","VisitPDBNode():  Default switch case caught this pass!");
                    last SWITCH;
                }#default
            }#SWITCH
        }#while ($bProcessAnotherRecord)
        if ($bVerify){PrintNodeReport(\%PDBNode, "PDB Finished Visiting Node"); PrintLineReport(\%LineInfo);}
#PrintNodeReport(\%PDBNode, "PDB Finished Visiting Node"); PrintLineReport(\%LineInfo);
    }else{
        if ($bVerify){STDERR->print ("##*********** Finished Visiting Node \"$PDBNode{$ELEMENT_NAME}\"\n");}
    }#else  if ($bDoVisitNode)

    %{$refPDBNode}  = %PDBNode;
    %{$refLineInfo} = %LineInfo;
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function VisitPDBNode()\n");}
    $returnStatus = 1;
    return ($returnStatus, @returnStatusMsg);
}#VisitPDBNode()

#############################################################################
## FUNCTION:     ReviewSingleContVisit()
## PURPOSE:     
## PARAMETERS:   $refPDBNode   - [IN]     A hash reference containing the Current PDB Node hash.
##               $refLineInfo  - [IN/OUT] A hash reference containing a LineInfo hash.
## RETURN:       
#############################################################################
sub ReviewSingleContVisit{
    my $refPDBNode            =  0;
    my $refLineInfo           =  0;
    my $refbProcessAnotherRecord =  0;
    my %PDBNode               =  0;
    my %LineInfo              = [];
    my $bProcessAnotherRecord = 0;
    my $NextRecordName        = "";
    my $StatusResult          =  0;
    my @StatusResultMsg       = ();
    my $returnStatus          = "";
    ($refPDBNode, $refLineInfo, $refbProcessAnotherRecord)  = @_;
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function ReviewSingleContVisit()\n");}
    %PDBNode= %{$refPDBNode};
    %LineInfo= %{$refLineInfo};
    $bProcessAnotherRecord = $$refbProcessAnotherRecord;

    #Process next simular record on same Node M.Pivot point. REC_SINGLE_CONT Act:CONCAT
    $NextRecordName = PeekAtNextRecordName();
    if (($LineInfo{$LINE_STATUS} eq $PROCESSED) && ($NextRecordName eq $LineInfo{$RECORD_NAME}) && ($LineInfo{$ACTION} eq $CONCAT)){
        $bProcessAnotherRecord = 1;
        GetNewRecordLine (\%LineInfo);
        ($StatusResult, $LineInfo{$MASTER_PIVOT_KEY}, @StatusResultMsg) = GetPDBToDTDField($LineInfo{$RECORD_NAME}, $REF_ACTION, $TOKEN);
        if ($StatusResult == 0){STDERR->print("WARN INFO: @StatusResultMsg\n");}
        if ($LineInfo{$MASTER_PIVOT_KEY} ne 0){AdjustLineToMasterPivot(\%LineInfo);}
        if ($bVerify){PrintNodeReport(\%PDBNode, "PDB"); PrintLineReport(\%LineInfo);}
    }#if
    %{$refPDBNode}  = %PDBNode;
    %{$refLineInfo} = %LineInfo;
    $$refbProcessAnotherRecord = $bProcessAnotherRecord;
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function ReviewSingleContVisit()\n");}
    $returnStatus = 1;
    return ($returnStatus);
}#ReviewSingleContVisit()

#############################################################################
## FUNCTION:     ReviewMultipleContVisit()
## PURPOSE:      Processes one to many LineInfo lines needed to satify the PDB node.
## PARAMETERS:   $refPDBNode   - [IN]     A hash reference containing the Current PDB Node hash.
##               $refLineInfo  - [IN/OUT] A hash reference containing a LineInfo hash.
## RETURN:       
#############################################################################
sub ReviewMultipleContVisit{
    my $refPDBNode               =  0;
    my $refLineInfo              =  0;
    my $refbProcessAnotherRecord =  0;
    my %PDBNode                  =  0;
    my %LineInfo                 = [];
    my $bProcessAnotherRecord    =  0;
    my $MultiKeyLevelForNode     =  0;
    my $SharedMultiKeyLevel      =  0;

    my $StatusResult             =  0;
    my @StatusResultMsg          = ();
    my $returnStatus             = "";

    ($refPDBNode, $refLineInfo, $refbProcessAnotherRecord)  = @_;
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function ReviewMultipleContVisit()\n");}
    %PDBNode= %{$refPDBNode};
    %LineInfo= %{$refLineInfo};
    $bProcessAnotherRecord = $$refbProcessAnotherRecord;

    if (($LineInfo{$LINE_STATUS} eq $PROCESSED) && ($LineInfo{$ACTION} eq $CONCAT)){
        if ($LineInfo{$MULTIKEY_STATE}){
            $MultiKeyLevelForNode = GetMultiKeyOfLineMatchingPDBNode(\%PDBNode, \%LineInfo);
            $SharedMultiKeyLevel = CompareFieldsOfLineToNextBasedOnMKeys(\%LineInfo,0);
            if (($MultiKeyLevelForNode > 0) && ($MultiKeyLevelForNode eq $SharedMultiKeyLevel)){ #Determine if current and next line's greatest common
                $bProcessAnotherRecord = 1;                              #shared key, match the current nodes MultiKey.
                GetNewRecordLine(\%LineInfo);
                $LineInfo{$MASTER_PIVOT_KEY} = GetNewMasterPivot(\%PDBNode, \%LineInfo);#Read REC info; Next mKey if exist otherwise default M.P.
                AdjustLineToMasterPivot(\%LineInfo);
            }#if
        }#if
    }#if
    %{$refPDBNode}  = %PDBNode;
    %{$refLineInfo} = %LineInfo;
    $$refbProcessAnotherRecord = $bProcessAnotherRecord;
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function ReviewMultipleContVisit()\n");}
    $returnStatus = 1;
    return ($returnStatus);
}#ReviewMultipleContVisit()

    ############################################################################
    ###########                End Of Subsection                     ###########
    ###########                Divide And Conquer                    ###########
    ############################################################################

    ############################################################################
    ###########                   Subsection                         ###########
    ###########                ProcessLine Functions                 ###########
    ###########  ProcessLine()                                       ###########
    ###########  UpdatePivotPoint()                                  ###########
    ###########  GetMultiKeyOfLineMatchingPDBNode()                  ###########
    ###########  GetNewMasterPivot()                                 ###########
    ###########  GetMultiKeyAndMasterPivotForNode()  old             ###########
    ###########  CompareFieldsOfLineToNextBasedOnMKeys()             ###########
    ############################################################################

############################################################################
# FUNCTION:     ProcessLine()
# PURPOSE:      Creates a new  PDB node.
# PARAMETERS:   $refPDBNode - [IN] A hash reference containing the Current PDB Node hash.
#               $refLineInfo  - [IN/OUT] A hash reference containing a LineInfo hash.
# RETURN:       TRUE for success, otherwise FALSE.
############################################################################
sub ProcessLine{

    my $refPDBNode        =  0;
    my $refLineInfo       =  0;
    my %PDBNode           =  0;
    my %LineInfo          = [];
    my $Data              = "";
    my $ContData          = "";
    my @AttributeNameList = ();
    my @NewAttributeNameList = ();
    my @ProcessedNameList = ();
    my $tmpAttribute      = "";


    my @KeyList            = ();
    my @UnprocessedKeys    = ();
    my $tmpKey             = "";
    my $CurKeyCount        =  0;
    my $CurKey             = "";
    my $NodeSatisfiedCount =  0;
    my $numAtr             =  0;
    my $j                  =  0;
    my $bNodeSatisfied     =  0;#MUST BE FALSE
    my $bKeyProcessedAsAtr =  0;
    my $bSetAtBeginOfRecord = 0;
    my $bUpdatedEntryIDCount = 0;

    ($refPDBNode, $refLineInfo)  = @_;

    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function ProcessLine()\n");}
    %PDBNode= %{$refPDBNode};
    %LineInfo= %{$refLineInfo};

    #DEBUG DEBUG DEBUG 
#    if (($PDBNode{$ELEMENT_CATEGORY} eq $ELEM_CAT_PND_PCDATA)) { 
#        $bLineProcess = 1;
#        PrintNodeReport(\%PDBNode, "PDB Test"); PrintLineReport(\%LineInfo);
#    }
# $bLineProcess = 1;
# PrintNodeReport(\%PDBNode, "PDB");
# PrintLineReport(\%LineInfo);
#sleep 3;


    # Set numAtr count and the NodeSatisfiedCount count.
    if (0 != @{$PDBNode{$ref_ATTRIBUTE_NAME_LIST}}){
        @AttributeNameList = @{$PDBNode{$ref_ATTRIBUTE_NAME_LIST}};
        $numAtr = scalar (@AttributeNameList);
        $NodeSatisfiedCount = $numAtr;
    }#if
    if ($PDBNode{$ELEMENT_CATEGORY} eq $ELEM_CAT_PND_PCDATA){
        $NodeSatisfiedCount++;
    }#if
    #If nothing to do return
#    if ($NodeSatisfiedCount == 0){
#        $PDBNode{$NODE_STATUS} = $SATISTFIED;
#        %{$refPDBNode} = %PDBNode;
#        %{$refLineInfo} = %LineInfo;
#        return (1);
#    }#if
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function ProcessLine()\n");}

    # Determine if the PDB Node has a special Attribute denoted by *_id_count. If so, then Update its count (by 1) with the count 
    # carried in the LineInfo and decrement the NodeSatisfiedCount.
    foreach $tmpAttribute (@AttributeNameList){
        if (grep(/id_count$/, $tmpAttribute)){
            if ($bLineProcess){
                STDERR->print ("Special Attribute with no Key: $tmpAttribute SatisfiedCount: $NodeSatisfiedCount\n");
                STDERR->print ("KeyList: @{$LineInfo{$ref_CURR_KEYS}} Used: @{$LineInfo{$ref_USED_KEYS}}\n");
            }#if
            $bUpdatedEntryIDCount = 1;
            $LineInfo{$ENTRY_ID_COUNT} = $LineInfo{$ENTRY_ID_COUNT} + 1;
            $PDBNode{$BEGIN_TAG} =~ s/$tmpAttribute/$tmpAttribute=\"$LineInfo{$ENTRY_ID_COUNT}\"/;
            push @ProcessedNameList, $tmpAttribute;
            $NodeSatisfiedCount--;
        }else{
            push @NewAttributeNameList, $tmpAttribute;
        }#else
    }#foreach
    @AttributeNameList = @NewAttributeNameList;
    @NewAttributeNameList = ();

    #Review every defined field for the record and assign the record fields to the Node. If the field does not match the Node
    #then save the unprocessed fields and place them back on the line.  The Node should have the Status of Satisfied upon reviewing
    #all fields, on the otherhand, the Line may still have the status of PROCESSING once the review is complete.
    while ((!$bNodeSatisfied) && ($CurKey = shift(@{$LineInfo{$ref_CURR_KEYS}}))){
        if ($bLineProcess){
            STDERR->print ("---\n");
            STDERR->print ("Key To Process: $CurKey Entry: $LineInfo{$PIVOT_ENTRY} SatisfiedCount: $NodeSatisfiedCount\n");
            STDERR->print ("KeyList: @{$LineInfo{$ref_CURR_KEYS}} Used: @{$LineInfo{$ref_USED_KEYS}}\n");
        }#if
        SWITCH: {
            # START processing an UNPROCESSED line.
            if ($LineInfo{$PIVOT_KEY} eq $DTD_ELEM_NAME_FIELD){
                #No assignment needed since the pivot point equals the Nodes name which is already in the tags.
                if ($bLineProcess){STDERR->print ("PROCESSING: Line: $LineInfo{$PDB_LINE}\n");}
                $bSetAtBeginOfRecord = 1;
                $LineInfo{$LINE_STATUS} = $PROCESSING;
                push @{$LineInfo{$ref_USED_KEYS}}, $CurKey;
                UpdatePivotPoint(\%LineInfo);
                last SWITCH;
            }#if

            # ASSIGN data to the element's PCDATA, UpdatePivotPoint, decrement NodeSatisfiedCount if
            # 1. Node is a PCData and Pivot is equal to the Node's element name.
            # 2. Node is a PCData and Pivot has special char ":" for  TER being used in ATOM and HETNAM
            # 3. 1 or 2 is true, and not a MultCont parse record that has already put data in the PDBNode.
            if (($PDBNode{$ELEMENT_CATEGORY} eq $ELEM_CAT_PND_PCDATA) &&
                (($PDBNode{$ELEMENT_NAME} eq $LineInfo{$PIVOT_ENTRY}) 
                  || ((grep /:/, $LineInfo{$PIVOT_ENTRY}) && (grep /$PDBNode{$ELEMENT_NAME}/, $LineInfo{$PIVOT_ENTRY}))) &&
                (!(($LineInfo{$RECORD_TYPE} eq $REC_MULTIPLE_CONT) && ($LineInfo{$ACTION} eq $PARSE) && ($PDBNode{$PCDATA} ne "")))){
                if ($bLineProcess){STDERR->print("PIVOT_ENTRY \"$LineInfo{$PIVOT_ENTRY}\" == ELEMENT_NAME \"$PDBNode{$ELEMENT_NAME}\"\n");}
                $Data = GetRecordField($LineInfo{$PDB_LINE}, $LineInfo{$PIVOT_KEY});
                #An UNPROCESSED line that we start processing at the current PIVOT_ENTRY.
                if (($LineInfo{$ACTION} eq $CONCAT) && (!$bSetAtBeginOfRecord)){
                   $LineInfo{$LINE_STATUS} = $PROCESSING;
                }#if

                if (! grep /^\s+$/, $Data){ # If the field has chars and not SPACES.
                    if ($bLineProcess){STDERR->print("The Data: \"$Data\"\n");}
                    $Data =~ s/^\s+//;
                    $Data =~ s/\s+$//;
                    $Data =~ s/\s+/ /g; #price new as of 20050222
                    $Data =~ s/&/&amp;/g; #This is to handle special characters in the PDB that are keyword characters in xml.
                    $Data =~ s/</&lt;/g;  #This is to handle special characters in the PDB that are keyword characters in xml.
                    $Data =~ s/>/&gt;/g;  #This is to handle special characters in the PDB that are keyword characters in xml.
                    if ($PDBNode{$PCDATA} eq ""){
                        $PDBNode{$PCDATA} = $Data;
                    }else{
                        $PDBNode{$PCDATA} = "$PDBNode{$PCDATA} $Data";
                    }#else
                    #If the element actually received data mark black.
                    if ($Data ne ""){
                        $PDBNode{$NODE_VISIT_STATUS} = $VISIT_STATUS_BLACK;
                    }#if
                }#if
                push @{$LineInfo{$ref_USED_KEYS}}, $CurKey;
                UpdatePivotPoint(\%LineInfo);
                $NodeSatisfiedCount--;
                if ($NodeSatisfiedCount == 0){$bNodeSatisfied = 1;}
                last SWITCH;
            }#if (($PDBNode{$ELEMENT_CATEGORY} eq $ELEM_CAT_PND_PCDATA) &&

            # DISGARD the REC_CONT field, NOTE we may need this at some point !!!!!
            if ($LineInfo{$PIVOT_ENTRY} eq $REC_CONT){
                $ContData = GetRecordField($LineInfo{$PDB_LINE}, $LineInfo{$PIVOT_KEY});
                if ($bLineProcess){STDERR->print ("DEBUG INFO: ContData = \"$ContData\"\n");}
                $ContData =~ s/\s+$//;
                push @{$LineInfo{$ref_USED_KEYS}}, $CurKey;
                UpdatePivotPoint(\%LineInfo);
                #$NodeSatisfiedCount--; NOT USED AT THIS POINT 
                #if ($NodeSatisfiedCount == 0){$bNodeSatisfied = 1;} NOT USED AT THIS POINT 
                last SWITCH;
            }#if ($LineInfo{$PIVOT_ENTRY} eq $REC_CONT)
            # Since the CurKey has not been used, see if it is actually matches an attribute, otherwise push it onto the UnprocessedKeys list.
            if ( 0 < $numAtr){
                $bKeyProcessedAsAtr = 0;
                for ($j = 0 ; $j <= $numAtr-1; $j++){ #Number of Attributes
                    if ($LineInfo{$PIVOT_ENTRY} eq $AttributeNameList[$j] && (!$bKeyProcessedAsAtr)){
                        $bKeyProcessedAsAtr = 1;
                        push @ProcessedNameList, $AttributeNameList[$j];
                        $Data = GetRecordField($LineInfo{$PDB_LINE}, $LineInfo{$PIVOT_KEY});
                        $Data =~ s/^\s+//;
                        $Data =~ s/\s+$//;
                        if (($LineInfo{$PIVOT_ENTRY} eq $PDB_ID) && ($g_pdb_id eq "")){$g_pdb_id = $Data; }
######################
                        if (grep /$LineInfo{$PIVOT_ENTRY}=\"\w+\"/, $PDBNode{$BEGIN_TAG}){
                            $PDBNode{$BEGIN_TAG} =~ s/$LineInfo{$PIVOT_ENTRY}=\"\w+\"/$LineInfo{$PIVOT_ENTRY}=\"$Data\"/;
                        }else{
                            $PDBNode{$BEGIN_TAG} =~ s/$LineInfo{$PIVOT_ENTRY}/$LineInfo{$PIVOT_ENTRY}=\"$Data\"/;
                        }#else
#                        $PDBNode{$BEGIN_TAG} =~ s/$LineInfo{$PIVOT_ENTRY}/$LineInfo{$PIVOT_ENTRY}=\"$Data\"/;
                        #If the element actually received data mark black.
########################################################
#### ????? need to comment out and run test run
                        if ($Data ne ""){
                            $PDBNode{$NODE_VISIT_STATUS} = $VISIT_STATUS_BLACK;
                        }#if
#######################################################
                        push @{$LineInfo{$ref_USED_KEYS}}, $CurKey;
                        UpdatePivotPoint(\%LineInfo);
                        $NodeSatisfiedCount--;
                        if ($NodeSatisfiedCount == 0){$bNodeSatisfied = 1;}
                    }#if
                }#for
                if (!$bKeyProcessedAsAtr){
                    if ($bLineProcess){STDERR->print ("WARNING INFO: CurKey:\"$CurKey\" not processed pushing back onto list\n");}
                    push @UnprocessedKeys, $CurKey;
                }#if
               last SWITCH;
            }#if
            default:{
                if ($bLineProcess){STDERR->print ("WARNING INFO: CurKey:\"$CurKey\" not processed pushing back onto list\n");}
                push @UnprocessedKeys, $CurKey;
                last SWITCH;
            }#default
        }#SWITCH
    }#while
    if ($bLineProcess){
        STDERR->print ("---\n");
        STDERR->print ("Next Key To Process:$LineInfo{$PIVOT_KEY} Entry: $LineInfo{$PIVOT_ENTRY} SatisfiedCount: $NodeSatisfiedCount\n");
        STDERR->print ("KeyList: @{$LineInfo{$ref_CURR_KEYS}} Used: @{$LineInfo{$ref_USED_KEYS}}\n");
        STDERR->print ("---\n");
    }#if
    if ((scalar( @{$LineInfo{$ref_USED_KEYS}})) eq  $LineInfo{$KEY_COUNT}){
        $LineInfo{$LINE_STATUS} = $PROCESSED;
    }else{
         @KeyList = @{$LineInfo{$ref_CURR_KEYS}};
         push @UnprocessedKeys, @KeyList; 
         @{$LineInfo{$ref_CURR_KEYS}} = @UnprocessedKeys;
    }#else

    #Special case to update the PDB_ID
    foreach $tmpAttribute (@AttributeNameList){
        if (! grep /^$tmpAttribute$/, @ProcessedNameList){
            SWITCH: {
                if ($tmpAttribute eq $PDB_ID){
                    $PDBNode{$BEGIN_TAG} =~ s/$PDB_ID/$PDB_ID=\"$g_pdb_id\"/;
                    $NodeSatisfiedCount--;
                    if ($bLineProcess){
                        STDERR->print ("Special Attribute with no Key: $PDB_ID SatisfiedCount: $NodeSatisfiedCount\n");
                        STDERR->print ("KeyList: @{$LineInfo{$ref_CURR_KEYS}} Used: @{$LineInfo{$ref_USED_KEYS}}\n");
                    }#if
                    last SWITCH;
                }#if
                default:{
                    push @NewAttributeNameList, $tmpAttribute;
                    last SWITCH;
                }#default
            }#SWITCH
        }#if
    }#foreach
    @{$PDBNode{$ref_ATTRIBUTE_NAME_LIST}} = @NewAttributeNameList;


     #This is for REC_MULTIPLE_CONT ACTION= PARSE (REVDAT) where spliting of the multi lines to children whom are to have same parentis
     # will have a count jump due to unwinding of the requersive calls to the next greatest MultiKey.
     #         <revision pdb_id="1MCP" revision_id="3" revision_date="15-OCT-89" revision_pdb_id="1MCPB" revision_type="1">
     #           <revision_record_name ... *_id_count="4">BLA003</revision_record_name>
     #           <revision_record_name ... *_id_count="5">SOURCE</revision_record_name>
     #           <revision_record_name ... *_id_count="6">BLABLA</revision_record_name>
     #   vs
     #           <revision_record_name ... *_id_count="4">BLA003</revision_record_name>
     #           <revision_record_name ... *_id_count="5">SOURCE</revision_record_name>
     #           <revision_record_name ... *_id_count="8">BLABLA</revision_record_name>
     # Note: the negative impact was on PARSE_TO_MULTI_CHILDREN so a negation could be used to allow all but PARSE_TO_MULTI_CHILDREN to use this
     #        if ($LineInfo{$ACTION} ne $PARSE_TO_MULTI_CHILDREN){ #Hack for SHEET!!!!!!

    if (($bUpdatedEntryIDCount eq 1) && ($PDBNode{$NODE_VISIT_STATUS} ne $VISIT_STATUS_BLACK)){
        if (($LineInfo{$RECORD_TYPE} eq $REC_MULTIPLE_CONT) && ($LineInfo{$ACTION} eq $PARSE)){ #Hack for SHEET!!!!!! Maybe not really a hack (:
            $LineInfo{$ENTRY_ID_COUNT} = $LineInfo{$ENTRY_ID_COUNT} - 1;
        }#if
    }#if
    if ($NodeSatisfiedCount == 0){$PDBNode{$NODE_STATUS} = $SATISFIED;}

    ###### DEBUG DEBUG 
#    if (($PDBNode{$ELEMENT_CATEGORY} eq $ELEM_CAT_PND_PCDATA)) { 
#        PrintNodeReport(\%PDBNode, "PDB AFTER!!!!!!!!!!!!!!!!");;
#    }
    %{$refPDBNode} = %PDBNode;
    %{$refLineInfo} = %LineInfo;
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function ProcessLine()\n");}
    return (1);
}#ProcessLine()

#############################################################################
## FUNCTION:     UpdatePivotPoint()
## PURPOSE:      
## PARAMETERS:   $refPDBNode   - [IN]     A hash reference containing the Current PDB Node hash.
##               
## RETURN:       
#############################################################################
sub UpdatePivotPoint{
    my $refLineInfo           =  0;
    my %LineInfo              = [];
    my $returnStatus          = "";

    ($refLineInfo)  = @_;
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function UpdatePivotPoint()\n");}
    %LineInfo= %{$refLineInfo};
    $LineInfo{$PIVOT_INDEX}++;
    $LineInfo{$PIVOT_KEY} = ${$LineInfo{$ref_KEYS}}[$LineInfo{$PIVOT_INDEX}];
    $LineInfo{$PIVOT_ENTRY} = ${%{$LineInfo{$ref_FIELD_HASH}}}{$LineInfo{$PIVOT_KEY}};
    %{$refLineInfo} = %LineInfo;
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function UpdatePivotPoint()\n");}
    $returnStatus = 1;
    return ($returnStatus);
}#UpdatePivotPoint()

    ############################################################################
    ###########                End Of Subsection                     ###########
    ###########                Divide And Conquer                    ###########
    ############################################################################

    ############################################################################
    ###########                   Subsection                         ###########
    ###########        Node & Record State Functions                 ###########
    ###########  AdjustLineToMasterPivot()                           ###########
    ###########  GetPrevFieldToMasterPivot()                         ###########
    ###########  GetMultiKeyOfLineMatchingPDBNode()                  ###########
    ###########  GetNewMasterPivot()                                 ###########
    ###########  GetMultiKeyAndMasterPivotForNode()  old             ###########
    ###########  CompareFieldsOfLineToNextBasedOnMKeys()             ###########
    ############################################################################

############################################################################
# FUNCTION:     AdjustLineToMasterPivot()
# PURPOSE:      To adjust the Line to the master pivot - the next location to process.
# PARAMETERS:   $refLineInfo  - [IN/OUT] A hash reference containing a LineInfo hash.
# RETURN:       The Record name, otherwise FALSE.
############################################################################
sub AdjustLineToMasterPivot{
    my $refLineInfo       =  0;
    my %LineInfo          = [];
    my $CurKey            =  0;

    ($refLineInfo)  = @_;

    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function AdjustLineToMasterPivot()\n");}
    %LineInfo = %{$refLineInfo};
    if ($LineInfo{$MASTER_PIVOT_KEY} ne 0){
        if ($bVerify){
            STDERR->print ("AdjustLineToMasterPivot\n");
            STDERR->print ("Set new line to Master Pivot: \"$LineInfo{$MASTER_PIVOT_KEY}\"\n");
        }#if
        while ( $LineInfo{$MASTER_PIVOT_KEY} ne ($CurKey = shift(@{$LineInfo{$ref_CURR_KEYS}}))) {
            if ($bVerify){
                STDERR->print ("Key: $CurKey Entry: $LineInfo{$PIVOT_ENTRY}\n");
                STDERR->print ("KeyList: @{$LineInfo{$ref_CURR_KEYS}} Used: @{$LineInfo{$ref_USED_KEYS}}\n");
            }#if
            $LineInfo{$LINE_STATUS} = $PROCESSING;
            push @{$LineInfo{$ref_USED_KEYS}}, $CurKey;
            $LineInfo{$PIVOT_INDEX}++;
            $LineInfo{$PIVOT_KEY} = ${$LineInfo{$ref_KEYS}}[$LineInfo{$PIVOT_INDEX}];
            $LineInfo{$PIVOT_ENTRY} = ${%{$LineInfo{$ref_FIELD_HASH}}}{$LineInfo{$PIVOT_KEY}};
        }#while
        unshift @{$LineInfo{$ref_CURR_KEYS}}, $CurKey;
        if ($bVerify){
            STDERR->print ("Key: $CurKey Entry: $LineInfo{$PIVOT_ENTRY}\n");
            STDERR->print ("KeyList: @{$LineInfo{$ref_CURR_KEYS}} Used: @{$LineInfo{$ref_USED_KEYS}}\n");
        }#if
    }#if

    %{$refLineInfo} = %LineInfo;
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function AdjustLineToMasterPivot()\n");}
    return(1);
}#AdjustLineToMasterPivot()

############################################################################
# FUNCTION:     GetPrevFieldToMasterPivot()
# PURPOSE:      To get the previous key to the Master Pivot if found in the REF_FIELD list.
# PARAMETERS:   $refLineInfo  - [IN] A hash reference containing a LineInfo hash.
# RETURN:       The previous key to the Master Pivot, otherwise the Master Pivot.
############################################################################
sub GetPrevFieldToMasterPivot{

    my $refLineInfo       =  0;
    my %LineInfo          = [];
    my $MasterPivot       =  0;
    my $NewMasterPivot    =  0;
    my $i                 =  0;
    my $PrevKey           = "";
    my $bFoundMatch       =  0;#Must be FALSE
    my $StatusResult      =  0;
    my @StatusMsg         = ();

    ($refLineInfo)  = @_;

    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function GetPrevFieldToMasterPivot()\n");}
    if ($bRunTimeDebug){STDERR->print("DEBUG: INFO: Arg: refLineInfo  = $refLineInfo\n");}

    %LineInfo = %{$refLineInfo};
    ($StatusResult, $MasterPivot, @StatusMsg) = GetPDBToDTDField($LineInfo{$RECORD_NAME}, $REF_ACTION, $TOKEN);
    for ($i = 0; (($i < $LineInfo{$KEY_COUNT}) && (!$bFoundMatch)); $i++){
        if ($MasterPivot eq @{$LineInfo{$ref_KEYS}}[$i]){
            $NewMasterPivot = $PrevKey;
            $bFoundMatch = 1;
        }else{
             $PrevKey = @{$LineInfo{$ref_KEYS}}[$i];
        }#else
    }#for
    if (!$bFoundMatch){
        STDERR->print("WARN INFO: Did not find Master Pivot listed in REF_FIELDs, returning current Master Pivot\n");
        $NewMasterPivot = $MasterPivot;
    }#if
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Return: NewMasterPivot = $NewMasterPivot\n");}
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function GetPrevFieldToMasterPivot()\n");}
    return($NewMasterPivot);
}#GetPrevFieldToMasterPivot()

############################################################################
# FUNCTION:     GetMultiKeyOfLineMatchingPDBNode()
# PURPOSE:      To determine the proper Key, if any, for the current tree depth.
# REMARK:       Determine if the PDBMode is listed in the LineInfo's MultiKey and at what level 
#               there is a match i.e.1,2,3. NewMasterPivot is set two ways 1. If exist a MultiKey 
#               greater than the current then set NewMasterPivot to this key "8_10" else lookup 
#               the records default master pivot via it ACTION -> TOKEN. for processing the rest 
#               of the line.  Therefore, the Master Pivot like like they should always be greater 
#               than a MultiKey's field.
#               if a record is using a multikey.
# PARAMETERS:   $refPDBNode  - [IN] A hash reference containing the Current PDB Node hash.
#               $refLineInfo - [IN] A hash reference containing a LineInfo hash.
# RETURN:       The $MultiKeyLevel and $NewMasterPivot, otherwise zero for both.
############################################################################
sub GetMultiKeyOfLineMatchingPDBNode{

    my $refPDBNode        =  0;
    my $refLineInfo       =  0;
    my %PDBNode           =  0;
    my %LineInfo          = [];
    my $MultiKey          =  0;
    my $i                 =  0;
    my $j                 =  0;
    my $bFoundMatch       =  0;
#    my $StatusResult      =  0;
#    my @StatusMsg         = ();

    ($refPDBNode, $refLineInfo)  = @_;

    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function GetMultiKeyOfLineMatchingPDBNode()\n");}
    if ($bRunTimeDebug){STDERR->print("DEBUG: INFO: Arg: refPDBNode   = $refPDBNode\n");}
    if ($bRunTimeDebug){STDERR->print("DEBUG: INFO: Arg: refLineInfo  = $refLineInfo\n");}
    %PDBNode= %{$refPDBNode};
    %LineInfo= %{$refLineInfo};
    for ( $i = $LineInfo{$MULTIKEY_STATE}; 0 < $i; $i--){
        if ($bVerify){
            my $x = $PDBNode{$ELEMENT_NAME};
            my $y = $LineInfo{"${GEN_MKEY_FIELD_DATA}$i"};
            STDERR->print("(PDB Element Name): \"$x\" == \"$y\" (LineInfo{GEN_MKEY_FIELD_DATA$i}) \n");
        }#if
        if ((!$bFoundMatch) &&  $PDBNode{$ELEMENT_NAME} eq  $LineInfo{"${GEN_MKEY_FIELD_DATA}$i"}){
            $bFoundMatch = 1;
            $MultiKey = $i;
        }#if
    }#for
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Return: MultiKey = $MultiKey\n");}
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function GetMultiKeyOfLineMatchingPDBNode()\n");}
    return($MultiKey);
}#GetMultiKeyOfLineMatchingPDBNode()

############################################################################
# FUNCTION:     GetNewMasterPivot()
# PURPOSE:      To determine the proper Key, if any, for the current tree depth.
# REMARK:       Determine if the PDBMode is listed in the LineInfo's MultiKey and at what level 
#               there is a match i.e.1,2,3. NewMasterPivot is set two ways 1. If exist a MultiKey 
#               greater than the current then set NewMasterPivot to this key "8_10" else lookup 
#               the records default master pivot via it ACTION -> TOKEN. for processing the rest 
#               of the line.  Therefore, the Master Pivot like like they should always be greater 
#               than a MultiKey's field.
#               if a record is using a multikey.
# PARAMETERS:   $refPDBNode  - [IN] A hash reference containing the Current PDB Node hash.
#               $refLineInfo - [IN] A hash reference containing a LineInfo hash.
# RETURN:       The $MultiKeyLevel and $NewMasterPivot, otherwise zero for both.
############################################################################
sub GetNewMasterPivot{

    my $refPDBNode        =  0;
    my $refLineInfo       =  0;
    my %PDBNode           =  0;
    my %LineInfo          = [];
    my $MultiKeyLevel     =  0;
    my $NewMasterPivot    =  0;
    my $i                 =  0;
    my $j                 =  0;
    my $bFoundMatch       =  0;
    my $StatusResult      =  0;
    my @StatusMsg         = ();

    ($refPDBNode, $refLineInfo)  = @_;

    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function GetNewMasterPivot()\n");}
    if ($bRunTimeDebug){STDERR->print("DEBUG: INFO: Arg: refPDBNode   = $refPDBNode\n");}
    if ($bRunTimeDebug){STDERR->print("DEBUG: INFO: Arg: refLineInfo  = $refLineInfo\n");}
    %PDBNode= %{$refPDBNode};
    %LineInfo= %{$refLineInfo};
    for ( $i = $LineInfo{$MULTIKEY_STATE}; 0 < $i; $i--){
        if ($bVerify){
            my $x =  $PDBNode{$ELEMENT_NAME};
            my $y =  $LineInfo{"${GEN_MKEY_FIELD_DATA}$i"};
            STDERR->print("PDB Element Name: \"$x\" = LineInfo{GEN_MKEY_FIELD_DATA$i}: \"$y\"\n");
        }#if
        if ((!$bFoundMatch) &&  $PDBNode{$ELEMENT_NAME} eq  $LineInfo{"${GEN_MKEY_FIELD_DATA}$i"}){
            $bFoundMatch = 1;
            my $j =$i + 1;
            if ( $j <= $LineInfo{$MULTIKEY_STATE}){
                $NewMasterPivot =  $LineInfo{"${GEN_MKEY}$j"};
            }else{
                ($StatusResult, $NewMasterPivot, @StatusMsg) =
                          GetPDBToDTDField($LineInfo{$RECORD_NAME}, $REF_ACTION, $TOKEN);
                if ($StatusResult == 0){STDERR->print("WARN INFO: @StatusMsg\n");}
            }#else
            #process next line so to group the field data of the line (after master pivot) with the rest of 
            #the children.  TRUE CONTINUE PROCESSING AT THIS TREE DEPTH.
            $MultiKeyLevel = $i;
        }#if
    }#for
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Return: NewMasterPivot = $NewMasterPivot\n");}
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function GetNewMasterPivot()\n");}
    return($NewMasterPivot);
}#GetNewMasterPivot()

#Org.
############################################################################
# FUNCTION:     GetMultiKeyAndMasterPivotForNode()
# PURPOSE:      To determine the proper Key, if any, for the current tree depth.
# REMARK:       Determine if the PDBMode is listed in the LineInfo's MultiKey and at what level 
#               there is a match i.e.1,2,3. NewMasterPivot is set two ways 1. If exist a MultiKey 
#               greater than the current then set NewMasterPivot to this key "8_10" else lookup 
#               the records default master pivot via it ACTION -> TOKEN. for processing the rest 
#               of the line.  Therefore, the Master Pivot like like they should always be greater 
#               than a MultiKey's field.
#               if a record is using a multikey.
# PARAMETERS:   $refPDBNode  - [IN] A hash reference containing the Current PDB Node hash.
#               $refLineInfo - [IN] A hash reference containing a LineInfo hash.
# RETURN:       The $MultiKeyLevel and $NewMasterPivot, otherwise zero for both.
############################################################################
sub GetMultiKeyAndMasterPivotForNode{

    my $refPDBNode        =  0;
    my $refLineInfo       =  0;
    my %PDBNode           =  0;
    my %LineInfo          = [];
    my $MultiKeyLevel     =  0;
    my $NewMasterPivot    =  0;
    my $i                 =  0;
    my $j                 =  0;
    my $bFoundMatch       =  0;
    my $StatusResult      =  0;
    my @StatusMsg         = ();

    ($refPDBNode, $refLineInfo)  = @_;

    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function GetMultiKeyAndMasterPivotForNode()\n");}
    if ($bRunTimeDebug){STDERR->print("DEBUG: INFO: Arg: refPDBNode   = $refPDBNode\n");}
    if ($bRunTimeDebug){STDERR->print("DEBUG: INFO: Arg: refLineInfo  = $refLineInfo\n");}
    %PDBNode= %{$refPDBNode};
    %LineInfo= %{$refLineInfo};
    for ( $i = $LineInfo{$MULTIKEY_STATE}; 0 < $i; $i--){
        if ($bVerify){
            my $x =  $PDBNode{$ELEMENT_NAME};
            my $y =  $LineInfo{"${GEN_MKEY_FIELD_DATA}$i"};
            STDERR->print("PDB Element Name: \"$x\" = LineInfo{GEN_MKEY_FIELD_DATA$i}: \"$y\"\n");
        }#if
        if ((!$bFoundMatch) &&  $PDBNode{$ELEMENT_NAME} eq  $LineInfo{"${GEN_MKEY_FIELD_DATA}$i"}){
            $bFoundMatch = 1;
            my $j =$i + 1;
            if ( $j <= $LineInfo{$MULTIKEY_STATE}){
                $NewMasterPivot =  $LineInfo{"${GEN_MKEY}$j"};
            }else{
                ($StatusResult, $NewMasterPivot, @StatusMsg) =
                          GetPDBToDTDField($LineInfo{$RECORD_NAME}, $REF_ACTION, $TOKEN);
                if ($StatusResult == 0){STDERR->print("WARN INFO: @StatusMsg\n");}
            }#else
            #process next line so to group the field data of the line (after master pivot) with the rest of 
            #the children.  TRUE CONTINUE PROCESSING AT THIS TREE DEPTH.
            $MultiKeyLevel = $i;
        }#if
    }#for
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Return: MultiKeyLevel = $MultiKeyLevel\n");}
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function GetMultiKeyAndMasterPivotForNode()\n");}
    return($MultiKeyLevel,$NewMasterPivot);
}#GetMultiKeyAndMasterPivotForNode()

############################################################################
# FUNCTION:     CompareFieldsOfLineToNextBasedOnMKeys()
# PURPOSE:      Gets the Record name of the next line to be processed..
# PARAMETERS:   $refLineInfo    - [IN] A hash reference containing the LineInfo hash.
#               $SpecialReview  - [IN] Flag.
# RETURN:       0 for no match.
#               1 match at 1st location.
#               2 match at 1st and 2nd location.
#               3 match at 1st, 2nd and 3rd location. 
############################################################################
sub CompareFieldsOfLineToNextBasedOnMKeys{

    my $refLineInfo          =  0;
    my %LineInfo             = [];
    my $NextRecord           = "";
    my $MultiKeyState        =  0;
    my $i                    =  0;
    my $KeyToTest            = "";
    my $NumSerialKeysMatched =  0;
    my $bNeverNotMatched     =  1; #MUST BE TRUE
    my $SpecialReview        =  0;

    my $CurrentLine          =  0;
    my $PDBRecordName        = "";

#    my $bVerify = 1; #price
#    my $bRunTimeDebug = 1; #price

    ($refLineInfo, $SpecialReview)  = @_;
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function CompareFieldsOfLineToNextBasedOnMKeys()\n");}
    if ($bRunTimeDebug){STDERR->print("DEBUG: INFO: Arg: refLineInfo   = $refLineInfo\n");}
    if ($bRunTimeDebug){STDERR->print("DEBUG: INFO: Arg: SpecialReview = $SpecialReview\n");}

    %LineInfo = %{$refLineInfo};
    $NextRecord = GetCopyOfNextRecord();
    if ($bVerify){STDERR->print("Cur  Line: $LineInfo{$PDB_LINE}\n");}
    if ($bVerify){STDERR->print("Next Line: $NextRecord\n");}
    $MultiKeyState = $LineInfo{$MULTIKEY_STATE};
    if ($bVerify){STDERR->print("LineInfo\'s MultiKeyState Count: $MultiKeyState\n");}
    #Match the number equal Record field data denoted by the MultiKey field information.
    #This will denote when two similar Records become dissimilar
    if ($MultiKeyState){
        for ($i = 1; $i <= $MultiKeyState; $i++){
            $KeyToTest   = "${GEN_MKEY}$i";
            if ($bVerify){
                STDERR->print("LineInfo's MutliKey to test: \"$LineInfo{$KeyToTest}\"\n");
                my $x =  GetRecordField( $LineInfo{$PDB_LINE}, $LineInfo{$KeyToTest});
                my $y =  GetRecordField($NextRecord, $LineInfo{$KeyToTest});
                STDERR->print("GetRecordField(): Cur: \"$x\" == Next: \"$y\"\n");
            }#if
            if (GetRecordField( $LineInfo{$PDB_LINE}, $LineInfo{$KeyToTest}) eq  GetRecordField($NextRecord, $LineInfo{$KeyToTest})){
                if ($bNeverNotMatched){
                    $NumSerialKeysMatched++;
                    if ($bVerify){STDERR->print("NumSerialKeysMatched = $NumSerialKeysMatched\n");}
                }#if
            }else{
                $bNeverNotMatched = 0;
            }#else
        }#for
    }#if
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Return: NumSerialKeysMatched = $NumSerialKeysMatched\n");}
    if ($bRunTimeDebug){STDERR->print("DEBUG INFO: Exiting function CompareFieldsOfLineToNextBasedOnMKeys()\n");}
    return ($NumSerialKeysMatched);
}#CompareFieldsOfLineToNextBasedOnMKeys()


    ############################################################################
    ###########                End Of Subsection                     ###########
    ###########           Node & Record State Functions              ###########
    ############################################################################

    ############################################################################
    ###########                   Subsection                         ###########
    ###########         PDB Creation and Access Functions            ###########
    ###########  CreatePDBNode()                                     ###########
    ###########  GetNewRecordLine()                                  ###########
    ###########  GetCopyOfNextRecord()                               ###########
    ###########  PeekAtNextRecordName()                              ###########
    ############################################################################

############################################################################
# FUNCTION:     CreatePDBNode()
# PURPOSE:      Creates a new  PDB node.
# PARAMETERS:   $refCurPDBNode  - [IN] A hash reference containing the Current PDB Node hash.
#               $refNewPDBNode  - [IN] A hash reference containing the New PDB Node hash.
#               $refCurDTDNode  - [IN] A hash reference containing the Current DTD Node hash.
# RETURN:       TRUE for success, otherwise FALSE.
############################################################################
sub CreatePDBNode{

    my $refCurPDBNode    =  0;
    my $refCurDTDNode    =  0;
    my $refNewPDBNode    =  0;
    my %CurPDBNode       =  0;
    my %CurDTDNode       =  0;
    my %NewPDBNode       =  0;
    my @tmpChildList     = ();
    my @tmpAttributeNameList = (); 
    my @tmpAttributeList = ();

    ($refCurPDBNode, $refNewPDBNode, $refCurDTDNode)  = @_;

    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function CreatePDBNode()\n");}
    %CurPDBNode = %{$refCurPDBNode};
    %NewPDBNode = %{$refNewPDBNode};
    %CurDTDNode = %{$refCurDTDNode};

    $NewPDBNode{$ELEMENT_NAME}            = $CurDTDNode{$ELEMENT_NAME};
    $NewPDBNode{$ELEMENT_CATEGORY}        = $CurDTDNode{$ELEMENT_CATEGORY};
    $NewPDBNode{$ELEMENT_LINE_NUM}        = $CurDTDNode{$ELEMENT_LINE_NUM};
    $NewPDBNode{$ref_MYNODE}              = $refNewPDBNode;

    $NewPDBNode{$ref_PARENTNODE}          = $CurPDBNode{$ref_MYNODE};

    if ( $CurDTDNode{$ELEMENT_CATEGORY} eq $ELEM_CAT_LIST){
       @tmpChildList                      = @{$CurDTDNode{$ref_CHILDNODE_LIST}};
       $NewPDBNode{$ref_CHILDNODE_LIST}      = \@tmpChildList;
    }#if
    @tmpAttributeNameList                 = @{$CurDTDNode{$ref_ATTRIBUTE_NAME_LIST}};
    $NewPDBNode{$ref_ATTRIBUTE_NAME_LIST} = \@tmpAttributeNameList;
    @tmpAttributeList                     = @{$CurDTDNode{$ref_ATTRIBUTE_LIST}};
    $NewPDBNode{$ref_ATTRIBUTE_LIST}      = \@tmpAttributeList;
    $NewPDBNode{$BEGIN_TAG}               = $CurDTDNode{$BEGIN_TAG};
    $NewPDBNode{$PCDATA}                  = $CurDTDNode{$PCDATA};
    $NewPDBNode{$END_TAG}                 = $CurDTDNode{$END_TAG};
    $NewPDBNode{$NODE_VISIT_STATUS}       = $VISIT_STATUS_WHITE;
    $NewPDBNode{$NODE_STATUS}             = $NOT_SATISFIED;
    %{$refNewPDBNode} = %NewPDBNode;

    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function CreatePDBNode()\n");}
    return (1);
}#CreatePDBNode()

############################################################################
# FUNCTION:     GetNewRecordLine()
# PURPOSE:      To read a new line from the PDB file and populate a LineInfo hash.
# PARAMETERS:   $refLineInfo  - [IN/OUT] A hash reference containing a LineInfo hash.
# RETURN:       TRUE for success, otherwise FALSE.
############################################################################
sub GetNewRecordLine{
    # Line & Hash
    my $refLineInfo      =  0;
    my %LineInfo         = [];
    my $CurrentLine      =  0;
    # Line Variables
    my $PDBRecordName    = "";
    my $PDBRecordType    = "";
    my $DTDElementName   = "";
    my $refField         = "";
    my %FieldHash        = [];
    my @FieldKeys        = ();
    # Status information
    my $StatusResult     =  0;
    my @StatusMsg        = ();
    my $returnStatus     =  0;
    my @returnStatusMsg  = ();
    my $FormatMsg        = "";

    ($refLineInfo) = @_;

    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function GetNewRecordLine()\n");}
    #Get a line
    if ( "" eq ($CurrentLine = shift(@g_PDBRecordFileList))){
        return (0);
    }#if
    if ($bRunTimeDebug){STDERR->print("\n\nDEBUG INFO: New Line: $CurrentLine\n\n");}
    #Get Record Name
    $PDBRecordName = GetRecordField($CurrentLine, $PDB_REC_NAME_FIELD);
    $PDBRecordName =~ s/\s+$//;
    if ($PDBRecordName eq ""){
        STDERR->print("ERROR INFO(Get()): No Record Field format exist for record name: \"$PDB_REC_NAME_FIELD\" Line:\"$CurrentLine\"\n");
        return ($PDBRecordName);
    }#if
    $PDBRecordName = AdjustRecordNameForGroupType($PDBRecordName, $CurrentLine);#priceprice #price new as of 20050222

    ($StatusResult, $PDBRecordType, @StatusMsg) = GetPDBToDTDField($PDBRecordName, $REC_TYPE, "");
    if ($StatusResult == 0){STDERR->print("WARN INFO: @StatusMsg\n");}
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: RecordType: $PDBRecordType = \n");}

    ($StatusResult, $DTDElementName, @StatusMsg) = GetPDBToDTDField($PDBRecordName, $REF_FIELD, $DTD_ELEM_NAME_FIELD);
    if ($StatusResult == 0){STDERR->print("WARN INFO: @StatusMsg\n");}

    ($StatusResult, $refField, @StatusMsg) = GetPDBToDTDField($PDBRecordName, $REF_FIELD, "");
    if ($StatusResult == 0){STDERR->print("WARN INFO: @StatusMsg\n");}
    %FieldHash = %{$refField};
    @FieldKeys =  keys %FieldHash;
    @FieldKeys =  SortRecordFormatFields(@FieldKeys);

    #Assign the record 
    $LineInfo{$RECORD_NAME}     = $PDBRecordName;
    $LineInfo{$ELEMENT_NAME}    = $DTDElementName;
    $LineInfo{$RECORD_TYPE}     = $PDBRecordType;
    $LineInfo{$PDB_LINE}        = $CurrentLine;

    ($StatusResult, $LineInfo{$ACTION}, @StatusMsg) = GetPDBToDTDField($PDBRecordName, $REF_ACTION, $ACTION);
    if ($bRunTimeDebug){STDERR->print("DEBUG INFO: Action:  $LineInfo{$ACTION}\n");}
    if ($StatusResult == 0){STDERR->print("WARN INFO: @StatusMsg\n");}
    %{$LineInfo{$ref_FIELD_HASH}} = %FieldHash;
    $LineInfo{$KEY_COUNT}       = scalar(@FieldKeys);
    @{$LineInfo{$ref_KEYS}}     = @FieldKeys;
    @{$LineInfo{$ref_CURR_KEYS}}= @FieldKeys;
    @{$LineInfo{$ref_USED_KEYS}}= ();
    $LineInfo{$PIVOT_INDEX}     = 0;
    $LineInfo{$PIVOT_KEY}       = $FieldKeys[$LineInfo{$PIVOT_INDEX}];
    $LineInfo{$PIVOT_ENTRY}     = $FieldHash{$FieldKeys[$LineInfo{$PIVOT_INDEX}]};
    $LineInfo{$MASTER_PIVOT_KEY}= 0;
    SWITCH: {
        if (($PDBRecordType eq $REC_SINGLE) ||($PDBRecordType eq $REC_SINGLE_CONT) ||
            ($PDBRecordType eq $REC_GROUP)){
            $LineInfo{$MULTIKEY_STATE}  = 0;
            $LineInfo{$MKEY1}           = 0;
            $LineInfo{$MKEY_FIELD_DATA1}= 0;
            $LineInfo{$MKEY2}           = 0;
            $LineInfo{$MKEY_FIELD_DATA2}= 0;
            $LineInfo{$MKEY3}           = 0;
            $LineInfo{$MKEY_FIELD_DATA3}= 0;
            $LineInfo{$MKEY4}           = 0;
            $LineInfo{$MKEY_FIELD_DATA4}= 0;
            $LineInfo{$MKEY5}           = 0;
            $LineInfo{$MKEY_FIELD_DATA5}= 0;
            last SWITCH;
        }#if
        if (($PDBRecordType eq $REC_MULTIPLE_CONT) ||($PDBRecordType eq $REC_MULTIPLE) || ($PDBRecordType eq $REC_OTHER)){
            ($StatusResult, $refField, @StatusMsg) = GetPDBToDTDField($PDBRecordName, "", "");
            if ($StatusResult == 0){STDERR->print("WARN INFO: @StatusMsg\n");}

            #Ensure there is a Key for REF_MULTI_KEY before retrieving.
            if (grep(/^$REF_MULTI_KEY$/, keys %{$refField})){
                #Retrieve the list containing the list of Multi Keys.
                ($StatusResult, $refField, @StatusMsg) = GetPDBToDTDField($PDBRecordName, $REF_MULTI_KEY, $REF_KEY_ORDER);
                if ($StatusResult == 0){STDERR->print("WARN INFO: @StatusMsg\n");}
                my @KeyOrderList = @{$refField};
                #Count the number of keys in the list.
                $LineInfo{$MULTIKEY_STATE} = scalar(@KeyOrderList);
                my $i = 0;
                #Copy the PDTD_DTD_TABLE definistion to the LineInfo.
                for ($i = 1; $i <= ($LineInfo{$MULTIKEY_STATE}); $i++){
                    $LineInfo{"${GEN_MKEY}$i"} = $KeyOrderList[$i-1];
                    ($StatusResult, $refField, @StatusMsg) = GetPDBToDTDField($PDBRecordName, $REF_MULTI_KEY, $KeyOrderList[$i-1]);
                    if ($StatusResult == 0){STDERR->print("WARN INFO: @StatusMsg\n");}
                    $LineInfo{"${GEN_MKEY_FIELD_DATA}$i"} = $refField;
                }#for
                # Zero out any MultiKeys not being used.
                for ($i = 5; $LineInfo{$MULTIKEY_STATE} < $i; $i--) {
                    $LineInfo{"${GEN_MKEY}$i"}            = 0;
                    $LineInfo{"${GEN_MKEY_FIELD_DATA}$i"} = 0;
                }#for
            }else{
                $LineInfo{$MULTIKEY_STATE}  = 0;
                $LineInfo{$MKEY1}           = 0;
                $LineInfo{$MKEY_FIELD_DATA1}= 0;
                $LineInfo{$MKEY2}           = 0;
                $LineInfo{$MKEY_FIELD_DATA2}= 0;
                $LineInfo{$MKEY3}           = 0;
                $LineInfo{$MKEY_FIELD_DATA3}= 0;
                $LineInfo{$MKEY4}           = 0;
                $LineInfo{$MKEY_FIELD_DATA4}= 0;
                $LineInfo{$MKEY5}           = 0;
                $LineInfo{$MKEY_FIELD_DATA5}= 0;
            }#else
            last SWITCH;
        }#if
        default:{
            STDERR->print("\nWARN INFO: RecordType: \"$PDBRecordType\" does not have a handler for its record type\n");
            last SWITCH;
        }#default
    }#SWITCH
    $LineInfo{$ENTRY_ID_COUNT}  = 0;
    $LineInfo{$LINE_STATUS}     = $UNPROCESSED;
    %{$refLineInfo} = %LineInfo;
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function GetNewRecordLine()\n");}
    return(1, ());
}#GetNewRecordLine()

############################################################################
# FUNCTION:     GetCopyOfNextRecord()
# PURPOSE:      Create a copy of the next Record line to be processed..
# PARAMETERS:   None.
# RETURN:       The Record, otherwise FALSE.
############################################################################
sub GetCopyOfNextRecord{
    my $CurrentLine      =  "";
    my $CopiedLine       =  "";
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function GetCopyOfNextRecord()\n");}
    $CurrentLine = shift(@g_PDBRecordFileList);
    $CopiedLine  = $CurrentLine;
    unshift @g_PDBRecordFileList, $CurrentLine;
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function GetCopyOfNextRecord()\n");}
    return ($CopiedLine);
}#GetCopyOfNextRecord()

############################################################################
# FUNCTION:     PeekAtNextRecordName()
# PURPOSE:      Gets the Record name of the next line to be processed..
# PARAMETERS:   None.
# RETURN:       The Record name, otherwise FALSE.
############################################################################
sub PeekAtNextRecordName{
    my $CurrentLine      =  0;
    my $PDBRecordName    = "";

    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function PeekAtNextRecordName()\n");}
    #Get a line 
    if ( "" eq ($CurrentLine = shift(@g_PDBRecordFileList))){
        return (0);
    }#if
    unshift @g_PDBRecordFileList, $CurrentLine;
    #Get Record Name
    $PDBRecordName = GetRecordField($CurrentLine, $PDB_REC_NAME_FIELD);
    $PDBRecordName =~ s/\s+$//;
    if ($PDBRecordName eq ""){
        STDERR->print("ERROR INFO(Peek()): No Record Field format exist for record name: \"$PDB_REC_NAME_FIELD\" Line:\"$CurrentLine\"\n");
        return (0);
    }#if
    $PDBRecordName = AdjustRecordNameForGroupType($PDBRecordName, $CurrentLine);#priceprice #price new as of 20050222
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function PeekAtNextRecordName()\n");}
    return ($PDBRecordName);
}#PeekAtNextRecordName()

############################################################################
# FUNCTION:     AdjustRecordNameForGroupType()
# PURPOSE:      Adjust the record name for records of type GROUP.
# PARAMETERS:   None.
# REMARK:       Records of type GROUP are dynamic records needing to have 
#               different record definition depending on what catagory of 
#               the group they are a part of.
# RETURN:       The Record name, otherwise FALSE.
############################################################################
sub AdjustRecordNameForGroupType{
    my $PDBRecordName    = "";
    my $CurrentLine      =  0;
    my $PDBRecordType    =  0;
    my $refField         =  0;
    my @RecordNames      = ();
    my $RecordName       = "";
    my $Size             =  0;
    my $i                =  0;
    my $KeyValue         =  0;
    my $RecordEntryField = "";
    my $LineValue        =  0;
    my $bFoundType       =  0;#MUST BE FALSE
    my $StatusResult     =  0;
    my @StatusMsg        = ();

    ($PDBRecordName, $CurrentLine)  = @_;

    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function AdjustRecordNameForGroupType()\n");}
    ($StatusResult, $PDBRecordType, @StatusMsg) = GetPDBToDTDField($PDBRecordName, $REC_TYPE, "");
    if ($StatusResult == 0){STDERR->print("WARN INFO1: @StatusMsg\n");}
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: RecordType: $PDBRecordType = \n");}
    if ($PDBRecordType eq $REC_GROUP){
        ($StatusResult, $refField, @StatusMsg) = GetPDBToDTDField($PDBRecordName, $REF_GROUP_KEY, $REF_KEY_ORDER);
        if ($StatusResult == 0){STDERR->print("WARN INFO: @StatusMsg\n");}
        my @RecordNames = @{$refField};
        $Size = scalar(@RecordNames);
        #Copy the PDTD_DTD_TABLE definistion to the LineInfo.
        for ($i = 0; ($i < $Size-1) && (!$bFoundType); $i++){
            $RecordName =  $RecordNames[$i];
            ($StatusResult, $KeyValue, @StatusMsg) = GetPDBToDTDField($PDBRecordName, $REF_GROUP_KEY, $RecordName);
            ($StatusResult, $RecordEntryField, @StatusMsg) = GetPDBToDTDField($PDBRecordName, $REF_FIELD, $RecordName);
            $LineValue = GetRecordField($CurrentLine, $RecordEntryField);
            if ($KeyValue == $LineValue){
                $PDBRecordName = $RecordName;
                $bFoundType = 1;
            }#if
        }#for
        if (!$bFoundType){
            $PDBRecordName = $RecordNames[$Size-1];
        }#if
    }#if
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function AdjustRecordNameForGroupType()\n");}
    return ($PDBRecordName);
}#AdjustRecordNameForGroupType()

#############################################################################
## FUNCTION:     AdjustRecordNameForGroupType()
## PURPOSE:      Adjust the record name for records of type GROUP.
## PARAMETERS:   None.
## REMARK:       Records of type GROUP are dynamic records needing to have 
##               different record definition depending on what catagory of 
##               the group they are a part of.
## RETURN:       The Record name, otherwise FALSE.
#############################################################################
#sub AdjustRecordNameForGroupType{
#    my $PDBRecordName    = "";
#    my $CurrentLine      =  0;
#    my $PDBRecordType    =  0;
#    my $refField         =  0;
#    my $i                =  0;
#    my $KeyValue         =  0;
#    my $LineValue        =  0;
#    my $bFoundType       =  0;#MUST BE FALSE
#    my $StatusResult     =  0;
#    my @StatusMsg        = ();

#    ($PDBRecordName, $CurrentLine)  = @_;

#    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function AdjustRecordNameForGroupType()\n");}
#    ($StatusResult, $PDBRecordType, @StatusMsg) = GetPDBToDTDField($PDBRecordName, $REC_TYPE, "");
#    if ($StatusResult == 0){STDERR->print("WARN INFO: @StatusMsg\n");}
#    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: RecordType: $PDBRecordType = \n");}
#    if ($PDBRecordType eq $REC_GROUP){
#        ($StatusResult, $refField, @StatusMsg) = GetPDBToDTDField($PDBRecordName, $REF_GROUP_KEY, $REF_KEY_ORDER);
#        if ($StatusResult == 0){STDERR->print("WARN INFO: @StatusMsg\n");}
#        my @KeyOrderList = @{$refField};
#        my $Size = scalar(@KeyOrderList);
#        #Copy the PDTD_DTD_TABLE definistion to the LineInfo.
#        my $gKey = "";
#        for ($i = 0; ($i < $Size-1) && (!$bFoundType); $i++){
#            $gKey =  $KeyOrderList[$i];
#            ($StatusResult, $KeyValue, @StatusMsg) = GetPDBToDTDField($PDBRecordName, $REF_FIELD, $gKey);
#            $LineValue = GetRecordField($CurrentLine, $gKey);
#            if ($KeyValue == $LineValue){
#                ($StatusResult, $PDBRecordName, @StatusMsg) = GetPDBToDTDField($PDBRecordName, $REF_GROUP_KEY, $gKey);
#                $bFoundType = 1;
#            }#if
#        }#for
#        if (!$bFoundType){
#            ($StatusResult, $PDBRecordName, @StatusMsg) = GetPDBToDTDField($PDBRecordName, $REF_GROUP_KEY, $KeyOrderList[$Size-1]);
#        }#if
#    }#if
#    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function AdjustRecordNameForGroupType()\n");}
#    return ($PDBRecordName);
#}#AdjustRecordNameForGroupType()

    ############################################################################
    ###########                End Of Subsection                     ###########
    ###########        PDB Creation and Access Functions             ###########
    ############################################################################

    ############################################################################
    ###########                   Subsection                         ###########
    ###########           PDB DTD table access Functions             ###########
    ###########  GetRecordField()                                    ###########
    ###########  GetPDBToDTDField()                                  ###########
    ############################################################################

############################################################################
# FUNCTION:     GetRecordField()
# PURPOSE:      To get a particular field from a record. 
# PARAMETERS:   $Line      - [IN] The line to be queried.
#               $FieldKey  - [IN] The field limits denoted by {x,y: x_y}.
# RETURN:       A token comprised of the inclusive elements denoted by x,y.
############################################################################
sub GetRecordField{
    my $Line       = "";
    my @LineList   = ();
    my $FieldKey  = "";
    my $LowerLimit =  0;
    my $UpperLimit =  0;
    my $Token      = "";
    my @TokenList  = ();
    my $i          =  0;

    ($Line, $FieldKey) = @_;

    if ($bRunTimeDebug){STDERR->print("\nDEBUG: INFO: Entering function GetRecordField()\n");}
	($LowerLimit, $UpperLimit) = split(/_/, $FieldKey);
	(@LineList) = split(//,$Line);
    for ($i = ($LowerLimit - 1); $i <= ($UpperLimit - 1); $i++){
        if ($bRunTimeDebug){STDERR->print("DEBUG: FIELD: $LineList[$i]\n");}
        push @TokenList, $LineList[$i];
    }#for
    $Token = join '', @TokenList;
    if ($bRunTimeDebug){STDERR->print("\nDEBUG: INFO: Exiting function GetRecordField()\n");}
    return ($Token);
}#GetRecordField()

############################################################################
# FUNCTION:     GetPDBToDTDField()
# PURPOSE:      To get a particular attribute of a PDB Record or a DTD 
#               declaration name associated with the PDB Record field
#               from the %PDB_DTD_TABLE table.
# PARAMETERS:   $PDBRecordName       - [IN] The name of the PDB Record.
#               $PDBRecordEntry      - [IN] The PDB Record Entry to be queried.
#               $PDBRecordEntryField - [IN] The field limits denoted by {x,y: x_y} or NULL.
# RETURN:       A PDB Record attribute value or a DTD declaration name,
#               otherwise false for failure.
# REMARK:       When querying for a PDB Record attribute $PDBRecordEntryField
#               must be NULL
############################################################################
sub GetPDBToDTDField{

    my $PDBRecordName       =  "";
    my $PDBRecordEntry      =  "";
    my $PDBRecordEntryField =  "";
    my %FieldHash           = ();
    my %RecHash             = ();
    my %TmpHash             = ();

    my $FormatMsg           = "";
    my $StatusMsg           = "";
    my $returnStatus        =  1; #MUST BE TRUE
    my @returnStatusMsg     = ();
    my $FieldValue          =  0;

    ($PDBRecordName, $PDBRecordEntry, $PDBRecordEntryField) = @_;

    if ($bRunTimeDebug){STDERR->print("\nDEBUG: INFO: Entering function GetPDBToDTDField()\n");}
    if ($bRunTimeDebug){STDERR->print("DEBUG: INFO: Arg: PDBRecordName       = $PDBRecordName\n");}
    if ($bRunTimeDebug){STDERR->print("DEBUG: INFO: Arg: PDBRecordEntry      = $PDBRecordEntry\n");}
    if ($bRunTimeDebug){STDERR->print("DEBUG: INFO: Arg: PDBRecordEntryField = $PDBRecordEntryField\n");}
    ## Search for a particular PDB record.

    ## Search for a particular PDB record.
    if (!(grep(/^$PDBRecordName$/, keys %PDB_DTD_TABLE))){
        $returnStatus = 0;
        $StatusMsg = "The record \"$PDBRecordName\" does not exist in the PDB table\n";
        push @returnStatusMsg, $StatusMsg;
    }else{
        ## Found the particular PDB record. If the $PDBRecordEntry is set to NULL 
        ## then return the value otherwise query using the Entry.
        $FormatMsg = \%PDB_DTD_TABLE;
        if ($bRunTimeDebug){STDERR->print("\nDEBUG: Found the PDB record key in the table: $FormatMsg\n");}
        if ($PDBRecordEntry eq ""){
            if ($bRunTimeDebug){STDERR->print("\nDEBUG: The PDBRecordEntryField is set to NULL string.\n");}
            $FieldValue = $PDB_DTD_TABLE{$PDBRecordName};
        }else{
            %RecHash = %{$PDB_DTD_TABLE{$PDBRecordName}};
            if ($bRunTimeDebug){STDERR->print("Searching for the Entry in the PDB record....\n");}
            if (!(grep(/^$PDBRecordEntry$/, keys %RecHash))){
                $returnStatus = 0;
                $StatusMsg = "The record entry \"$PDBRecordEntry\" does not exist in the PDB record: $PDBRecordName.\n";
                push @returnStatusMsg, $StatusMsg;
            }else{
                ## Found the particular Entry of PDB record. If the $PDBRecordEntryField is set to NULL 
                ## then return the value otherwise query using the Entry's Field
                $FormatMsg = \%RecHash;
                if ($bRunTimeDebug){STDERR->print("Found the Entry key in the PDB record: $FormatMsg\n");}
                if ($PDBRecordEntryField eq ""){
                    if ($bRunTimeDebug){STDERR->print("\nDEBUG: The PDBRecordEntryField is set to NULL string.\n");}
                    $FieldValue = ${%{$PDB_DTD_TABLE{$PDBRecordName}}}{$PDBRecordEntry};
                }else{
                    %TmpHash = %{$RecHash{$PDBRecordEntry}};
                    ## Search for the particular Field of the Record Entry.
                    if ($bRunTimeDebug){STDERR->print("Searching for EntryField in the PDB record....\n");}
                    if (!(grep(/^$PDBRecordEntryField$/, keys %TmpHash))){
                        $returnStatus = 0;
                        $StatusMsg = "The entry field  \"$PDBRecordEntryField\" does not exist in the Record Entry: $PDBRecordName\n";
                        push @returnStatusMsg, $StatusMsg;
                    }else{
                        $FormatMsg = \%TmpHash;
                        if ($bRunTimeDebug){STDERR->print("Found the EntryField key in the PDB record: $FormatMsg\n");}
                        $FieldValue = ${${%{$PDB_DTD_TABLE{$PDBRecordName}}}{$PDBRecordEntry}}{$PDBRecordEntryField};
                    }#else if (!(grep(/^$PDBRecordEntryField$/, keys %TmpHash)))
                }#else if ($PDBRecordEntryField eq "")
            }#else if (!(grep(/^$PDBRecordEntry$/, keys %RecHash)))
        }#else if ($PDBRecordEntry eq "")
    }#else if (!(grep(/^$PDBRecordName$/, keys %PDB_DTD_TABLE)))
    if ($bRunTimeDebug){
        STDERR->print("WARN INFO: @returnStatusMsg\n");
        STDERR->print("\nDEBUG: INFO: Arg: FieldValue          = $FieldValue\n");
        STDERR->print("DEBUG: INFO: Exiting function GetPDBToDTDField()\n");
    }#if
    return ($returnStatus, $FieldValue, @returnStatusMsg);
}#GetPDBToDTDField()

    ############################################################################
    ###########                End Of Subsection                     ###########
    ###########        PDB DTD table access Functions                ###########
    ############################################################################

    ############################################################################
    ###########                   Subsection                         ###########
    ###########               Specialty Functions                    ###########
    ###########  SortRecordFormatFields()                            ###########
    ###########  PDB1LetterSeqs()                                    ###########
    ###########  RemoveOccurrenceSign()                              ###########
    ###########  MoveChildToProcessedList()                          ###########
    ############################################################################

############################################################################
# FUNCTION:     SortRecordFormatFields()
# PURPOSE:      To get a particular field from a record. 
# PARAMETERS:   @FieldKeys - [IN] The line to be queried.
# RETURN:       Input file to be used.
# CREDIT:       Insertion-Sort
############################################################################
sub SortRecordFormatFields{

    my @FieldKeys      = ();
    my $n              =  0;
    my $i              =  0;
    my $j              =  0;
    my $Lkey           =  0;
    my $Ukey           =  0;
    my $LowerLimit     =  0;
    my $UpperLimit     =  0;
    my @LowerLimitList = ();
    my @UpperLimitList = ();
    my @TokenList      = ();

    (@FieldKeys) = @_;
    if ($bRunTimeDebug){
        STDERR->print("\nDEBUG: INFO: Entering function SortRecordFormatFields()\n");
        my $tmptmp = join ' ', @FieldKeys;
        STDERR->print("Before Sort: $tmptmp\n");
    }#if

    $n = scalar(@FieldKeys);
    if ($bRunTimeDebug){STDERR->print("\nDEBUG: INFO: n = $n\n");}
    for ($i = 0; $i <= $n; $i++){
        ($LowerLimit, $UpperLimit) = split(/_/, $FieldKeys[$i]);
        push @LowerLimitList, $LowerLimit;
        push @UpperLimitList, $UpperLimit;
    }#for

    for ($j = 1; $j <= $n-1; $j++){			
        $Lkey = $LowerLimitList[$j];	
        $Ukey = $UpperLimitList[$j];					
        $i = $j - 1;					
        while (0 <= $i && $Lkey < $LowerLimitList[$i]){	
            $LowerLimitList[$i+1] = $LowerLimitList[$i];
            $UpperLimitList[$i+1] = $UpperLimitList[$i];		
            $i = $i-1;					
        }#while	
        $LowerLimitList[$i+1] = $Lkey;
        $UpperLimitList[$i+1] = $Ukey;
    }#for

    @FieldKeys = ();
    for ($i = 0; $i <= $n-1; $i++){
        @TokenList = ();
        push @TokenList, $LowerLimitList[$i];
        push @TokenList, $UpperLimitList[$i];
        $FieldKeys[$i]  = join '_', @TokenList;
    }#for

    if ($bRunTimeDebug){
        STDERR->print("\nDEBUG: INFO: Exiting function SortRecordFormatFields()\n");
        my $newtmp = join ' ', @FieldKeys;
        STDERR->print("After Sort: $newtmp\n");
    }#if
    return (@FieldKeys);
}#SortRecordFormatFields()

############################################################################
# FUNCTION:     PDB1LetterSeqs()
# PURPOSE:      Reads the PDB file, finds the SEQRES section and returns all the found sequences as 1 letter chains.
# PARAMETERS:   None.
# REMARK:       For SEQRES list: Builds Sequence matching the first sequence's Residue number.  
# RETURN:       TRUE for success, otherwise FALSE.
############################################################################
sub PDB1LetterSeqs{
    my $bFileFlag       = "";
    my $refObject       = "";
    my $FileName        = "";
    my @Lines           = "";
    my @ResidueList     = ();
    my @CurrResidueList = ();
    my $refResidueList  = "";
    my $SeqID           = "";
    my $ResidueNumber   = "";
    my $Count           = "";
    my $CurrentLine     = "";
    my $CurrSeqID       = "";
    my $CurrResidueNumber = "";
    my $CurrCount       = "";
    my @ResidueSeqsList = ();
    my $ChainLine       = "";
    my @ChainList       = ();
    my $ChainCount      =  0;
    my $Residue         = "";
    my $OneResidue      = "";
    my @NewChain        = ();
    my $ConvertedChain  = "";

    ($bFileFlag, $refObject) = @_;

    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function PDB1LetterSeqs()\n");}
    if ($bFileFlag){
        $FileName = $$refObject;
        if (open(FILE,"$FileName")){
            @Lines=<FILE>;
            close FILE;
            @ResidueList = grep /^SEQRES/, @Lines;
            if (0 eq scalar(@ResidueList)){
	            STDERR->print("\n**** No SEQRES records found in file: $FileName\n");
                return(0);
            }#if
	        $CurrentLine = $ResidueList[0];
            $SeqID         = GetRecordField($CurrentLine, '12_12');
            $ResidueNumber = GetRecordField($CurrentLine, '14_17');
            $ResidueNumber =~ s/^\s+//;
            $ResidueNumber =~ s/\s+$//;
            while ($CurrentLine = shift(@ResidueList)){
                $CurrSeqID         = GetRecordField($CurrentLine, '12_12');
                $CurrResidueNumber = GetRecordField($CurrentLine, '14_17');
                $CurrResidueNumber =~ s/^\s+//;
                $CurrResidueNumber =~ s/\s+$//;
                if (($CurrSeqID eq $SeqID) && ($CurrResidueNumber eq $ResidueNumber)){
                    push @CurrResidueList, $CurrentLine;
                }else{
                    my @TmpList = @CurrResidueList;
                    push @ResidueSeqsList, \@TmpList;
                    @CurrResidueList = ();
                    $SeqID = $CurrSeqID;
                    $ResidueNumber = $CurrResidueNumber;
                    push @CurrResidueList, $CurrentLine;
                }#else
            }#while
            my @TmpList = @CurrResidueList;
            push @ResidueSeqsList, \@TmpList;
            @CurrResidueList = ();
        }else{
            STDERR->print("\nERROR INFO: Unable to open file: $FileName\n");
            return(0);
        }#else
    }else{
        my @TmpList = @{$refObject};
        push @ResidueSeqsList, \@TmpList;
    }#else

    #Determine the current chain name.
    foreach $refResidueList (@ResidueSeqsList){
        @ResidueList = @{$refResidueList};
	    $CurrentLine = $ResidueList[0];
        $SeqID         = GetRecordField($CurrentLine, '12_12');
        $ResidueNumber = GetRecordField($CurrentLine, '14_17');
        $ResidueNumber =~ s/^\s+//;
        $ResidueNumber =~ s/\s+$//;
        @NewChain = ();
        foreach $CurrentLine (@ResidueList){
            $CurrSeqID         = GetRecordField($CurrentLine, '12_12');
            $CurrResidueNumber = GetRecordField($CurrentLine, '14_17');
            $CurrResidueNumber =~ s/^\s+//;
            $CurrResidueNumber =~ s/\s+$//;
            if (($CurrSeqID eq $SeqID) && ($CurrResidueNumber eq $ResidueNumber)){
                $ChainLine = GetRecordField($CurrentLine, '20_70');
                $ChainLine =~ s/^\s+//;
                $ChainLine =~ s/\s+$//;
                @ChainList = split(/\s+/,$ChainLine);
                $ChainCount = scalar(@ChainList);
                foreach $Residue (@ChainList){
                    $OneResidue = ${%{$SEQRES_TABLE{$Residue}}}{$ONE_LETTER_RESIDUE};
                    if ( $OneResidue ne ""){
                        push @NewChain, $OneResidue;
                    }else{
                        push @NewChain, "($Residue)";
                    }#else
                }#foreach
            }#if
        }#foreach
        $ConvertedChain = join '', @NewChain;
        if ($bFileFlag){
            STDERR->print("\n\nNew converted $SeqID Sequence:\n");
            STDERR->print("$ConvertedChain\n\n");
        }else{
            return($ConvertedChain);
        }#else
    }#foreach
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function PDB1LetterSeqs()\n");}
    return ($ConvertedChain);
}#PDB1LetterSeqs()

############################################################################
# FUNCTION:     RemoveOccurrenceSign()
# PURPOSE:      Gets the Occurrence Sign encode on the name of a Child element.
# PARAMETERS:   $TmpChildNode  - [IN] Child element name.
# REMARK:       Reversed for later use.
# RETURN:       TRUE for success, otherwise FALSE.
############################################################################
sub RemoveOccurrenceSign{
    my $refTmpChildNode = "";
    my $TmpChildNode    = "";
    my $bCreateMultiInstancesOfChildType =  0;
    my $OccurrenceSign  =  0;

    ($refTmpChildNode) = @_;

    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function RemoveOccurrenceSign()\n");}
    $TmpChildNode = $$refTmpChildNode;
    SWITCH: {
        if (grep(/\+$/, $TmpChildNode)){#(element-content+) Content must occur one or more times.
            $TmpChildNode =~ s/\+$//;
            $OccurrenceSign = $PLUS_SIGN;
            $bCreateMultiInstancesOfChildType = 1;
            last SWITCH;
        }#if
       if (grep(/\*$/, $TmpChildNode)){#(element-content*) Content can occur zero or more times.
            $TmpChildNode =~ s/\*$//;
            $OccurrenceSign = $MULTIPLE_SIGN;
            $bCreateMultiInstancesOfChildType = 1;
            last SWITCH;
        }#if
        if (grep(/\?$/, $TmpChildNode)){#(element-content?) Content can occur zero or one times.
            $TmpChildNode =~ s/\?$//;
            $OccurrenceSign = $QUESTIONMARK_SIGN;
            $bCreateMultiInstancesOfChildType = 0;
            last SWITCH;
        }#if
        default:{#Content must occur once, and only once.
            $OccurrenceSign = $EMPTY_SIGN;
            $bCreateMultiInstancesOfChildType = 0;
            last SWITCH;
        }#default
    }#SWITCH
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function RemoveOccurrenceSign()\n");}
    $$refTmpChildNode = $TmpChildNode;
    return ($OccurrenceSign, $bCreateMultiInstancesOfChildType);
}#RemoveOccurrenceSign()


############################################################################
# FUNCTION:     MoveChildToProcessedList()
# PURPOSE:      Removes a Child element from the ChildNodeList to the ProcessedChildNodeNames.
# PARAMETERS:   $DTDElementName   - [IN] DTD Element Name.
#               $refChildNodeList - [IN] Reference to a ChildNodeList.
#               $refProcessedChildNodeNames - [IN] Reference to a ProcessedChildNodeNames.
# REMARK:       Reversed for later use.
# RETURN:       The new ProcessedChildNodeNames for success, otherwise FALSE.
############################################################################
sub MoveChildToProcessedList{
    my $refChildNodeList = "";
    my $refProcessedChildNodeNames = "";
    my $DTDElementName   = "";
    my @ChildNodeList    = ();
    my @TmpChildNodeList = ();
    my @UnprocessedList  = ();
    my @ProcessedChildNodeNames = ();
    my $TmpNode          = "";
    my $OccurrenceSign   =  0;

    ($DTDElementName, $refProcessedChildNodeNames, $refChildNodeList) = @_;

    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function MoveChildToProcessedList()\n");}
    @ChildNodeList = @{$refChildNodeList};
    @ProcessedChildNodeNames = @{$refProcessedChildNodeNames};
    if ( grep /^$DTDElementName/, @ChildNodeList){
        while ($TmpNode = shift(@ChildNodeList)){
            ($OccurrenceSign) = RemoveOccurrenceSign(\$TmpNode);
            if ($DTDElementName eq $TmpNode){
                push @ProcessedChildNodeNames, $TmpNode;
            }else{
                push @UnprocessedList, "${TmpNode}${OccurrenceSign}";
            }#else
        }#while
        @ChildNodeList = @UnprocessedList;
    }#if
    @{$refProcessedChildNodeNames} = @ProcessedChildNodeNames;
    @{$refChildNodeList} = @ChildNodeList;
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function MoveChildToProcessedList()\n");}
    return (1);
}#MoveChildToProcessedList()

############################################################################
# FUNCTION:     ConvertSecondsToTime()
# PURPOSE:      To convert a quantity of seconds to hours, minutes, and seconds.
# PARAMETERS:   $SizeList - [IN] A quantity of time in seconds. 
# RETURN:       The time in a hours, minutes, and seconds format.
#############################################################################
sub ConvertSecondsToTime{

    my $defMin = 60;
    my $defHour = 60*$defMin;
    my $defDay  = 24*$defHour;
    my $seconds = 60;
    my ($hour, $min, $sec, $numHours, $numMins, $numSecs, $time) = 0;

    ($seconds) = @_;
    $numHours = int($seconds/$defHour);
    $seconds  = ($seconds - ( $numHours * $defHour));
    $numMins  = int($seconds/$defMin);
    $numSecs  = ($seconds - ( $numMins * $defMin));
    if ($numHours < 10){ $numHours = "0${numHours}";}
    if ($numMins  < 10){ $numMins  = "0${numMins}";}
    if ($numSecs  < 10){ $numSecs  = "0${numSecs}";}
    $time = "$numHours:$numMins:$numSecs";
    return($time);
}#ConvertSecondsToTime()

#############################################################################
## FUNCTION:     CalculatePhiPsiAngles()
## PURPOSE:      
## PARAMETERS:   $   - [IN]     
##               $  - [IN/OUT] 
## RETURN:       
#############################################################################
sub CalculatePhiPsiAngles{
    my @SeqResAtomList = ();
    my @SeqResGroupedList = ();
    my @SeqChain       = ();
    my $SeqID          = "";
    my $CurrAtomName   = "";
    my $CurrSeqID      = "";
    my $CurrResidueSeqNumber   = "";
    my $NextAtomName   = "";
    my $NextSeqID      = "";
    my $NextResidueSeqNumber   = "";
    my ($x, $y, $z)    = "";
    my $line;
    my $fileHandle;
    my @temp;
    my $size =  0;
    my @next;
    my @prev;
    my @curr;
    my @prev_C;
    my @curr_N;
    my @curr_CA;
    my @curr_C;
    my @next_N;
    my $phi;
    my $psi;
    my $type;
    my $out;
    my $answer;
    my $bPrintToScreen  = 0; #MUST BE FALSE


    ($bPrintToScreen) = @_;

    @SeqResAtomList = grep /^ATOM/, @g_PDBRecordFileList;
    $line  = $SeqResAtomList[0];  #read the first line
    $SeqID = GetRecordField($line, '22_22');
    while ($line = shift @SeqResAtomList){  #was line read? (is $line defined?)
        ($CurrAtomName, $CurrSeqID, $CurrResidueSeqNumber, $x, $y, $z) = ParseAtomLine($line);
        if ($CurrAtomName eq 'N'){ 
            push @SeqResGroupedList, "$CurrAtomName:$CurrSeqID:$CurrResidueSeqNumber:$x:$y:$z";
            $line = shift @SeqResAtomList;
            ($CurrAtomName, $CurrSeqID, $CurrResidueSeqNumber, $x, $y, $z) = ParseAtomLine($line);
            push @SeqResGroupedList, "$CurrAtomName:$CurrSeqID:$CurrResidueSeqNumber:$x:$y:$z";
            $line = shift @SeqResAtomList;
            ($CurrAtomName, $CurrSeqID, $CurrResidueSeqNumber, $x, $y, $z) = ParseAtomLine($line);
            push @SeqResGroupedList, "$CurrAtomName:$CurrSeqID:$CurrResidueSeqNumber:$x:$y:$z";
        }#if
    }#while
    my $ListSize = scalar(@SeqResGroupedList);
    for (my $i = 0; $i < $ListSize; $i = $i+3){
        if (($i-3) >= 0){
            @prev = @curr;
        }else{
           @prev = ();
        }#else
        $curr[0] = $SeqResGroupedList[$i];
        $curr[1] = $SeqResGroupedList[$i+1];
        $curr[2] = $SeqResGroupedList[$i+2];
        if (($i+5) < $ListSize){
           $next[0] = $SeqResGroupedList[$i+3];
           $next[1] = $SeqResGroupedList[$i+4];
           $next[2] = $SeqResGroupedList[$i+5];
        }else{
           @next = ();
        }#else
        if ($bVerify){print "prev: \"@prev\"\ncurr: \"@curr\"\nnext: \"@next\"\n\n";}
        $phi  = "";
        $psi  = "";
        SWITCH: {
            if ((scalar(@prev) == 0) && (scalar(@curr) > 0) && (scalar(@next) > 0)){
                @curr_N = split /\:/,$curr[0]; # N
                @curr_CA = split /\:/,$curr[1];# CA
                @curr_C = split /\:/,$curr[2]; # C
                @next_N = split /\:/,$next[0]; # N
                $psi = dihedral ($curr_N[3], $curr_N[4], $curr_N[5], $curr_CA[3], $curr_CA[4], $curr_CA[5],
                                 $curr_C[3], $curr_C[4], $curr_C[5], $next_N[3], $next_N[4], $next_N[5]);
                $type = "None";
                last SWITCH;
            }#if
            if ((scalar(@prev) > 0) && (scalar(@curr) > 0) && (scalar(@next) > 0)){
                @prev_C = split /\:/,$prev[2]; # C
                @curr_N = split /\:/,$curr[0]; # N
                @curr_CA = split /\:/,$curr[1];# CA
                @curr_C = split /\:/,$curr[2]; # C
                @next_N = split /\:/,$next[0]; # N
                $phi = dihedral ($prev_C[3], $prev_C[4], $prev_C[5], $curr_N[3], $curr_N[4], $curr_N[5],
                                 $curr_CA[3], $curr_CA[4], $curr_CA[5], $curr_C[3], $curr_C[4], $curr_C[5]);
                $psi = dihedral ($curr_N[3], $curr_N[4], $curr_N[5], $curr_CA[3], $curr_CA[4], $curr_CA[5],
                                 $curr_C[3], $curr_C[4], $curr_C[5], $next_N[3], $next_N[4], $next_N[5]);
                if ( $phi >= 10 && $phi <= 90 && $psi >= 10 && $psi <= 130){
                    $type = "lf";
                }elsif ($phi >= -59 && $phi <= -39 && $psi >= -36 && $psi <= -16){
                    $type = "3h";
                }elsif ($phi >= -67 && $phi <= -47 && $psi >= -80 && $psi <= -60){
                    $type = "pi";
                }elsif ($phi >= -80 && $phi <= -40 && $psi >= -50 && $psi <= -10){
                    $type = "bI";
                }elsif ($phi >= -110 && $phi <= -75 && $psi >= -15 && $psi <= -20){
                    $type = "bI";
                }elsif ($phi >= -80 && $phi <= -40 && $psi >= 100 && $psi <= 140){
                    $type = "bII";
                }elsif ($phi >= 60 && $phi <= 100 && $psi >= -20 && $psi <= 20){
                    $type = "bII";
                }elsif ($phi >= -80 && $phi <= -40 && $psi >= -50 && $psi <= -10){
                    $type = "bIII";
                }elsif ($phi >= -80 && $phi <= -40 && $psi >= -50 && $psi <= -10){
                    $type = "bIII";
                }else{
                    $type = "None";
                }
                last SWITCH;
            }#if
            if ((scalar(@prev) > 0) && (scalar(@curr) > 0) && (scalar(@next) == 0)){
                @prev_C = split /\:/,$prev[2]; # C
                @curr_N = split /\:/,$curr[0]; # N
                @curr_CA = split /\:/,$curr[1];# CA
                @curr_C = split /\:/,$curr[2]; # C
                $phi = dihedral ($prev_C[3], $prev_C[4], $prev_C[5], $curr_N[3], $curr_N[4], $curr_N[5],
                                 $curr_CA[3], $curr_CA[4], $curr_CA[5], $curr_C[3], $curr_C[4], $curr_C[5]);
                $type = "None";
                last SWITCH;
            }#if
        }#SWITCH
        if ((scalar(@curr) > 0) && ((scalar(@prev) > 0) || (scalar(@next) > 0))){
            my %newResidue = [];
            $newResidue{$RESIDUE_SEQ_NUM} = $curr_N[2];
            $newResidue{$PHI}             = $phi;
            $newResidue{$PSI}             = $psi;
            $newResidue{$RAMACHANDRAN}    = $type;
            if ($curr_N[1] eq $SeqID){
                 push @SeqChain, \%newResidue;
            }else{
                my @TmpSeqChain = @SeqChain;
                @SeqChain = ();
                $g_PhiPsiChainHash{$SeqID} = \@TmpSeqChain;
                $SeqID =  $curr_N[1];
                push @SeqChain, \%newResidue;
            }#else
        }#if
    }#for
    my @TmpSeqChain = @SeqChain;
    @SeqChain = ();
    $g_PhiPsiChainHash{$SeqID} = \@TmpSeqChain;

    if ($bVerify || $bPrintToScreen ){
        my @ChainNames = ();
        @ChainNames = keys %g_PhiPsiChainHash;
        @ChainNames = reverse @ChainNames;
        foreach $SeqID (@ChainNames){
            STDERR->print("\nSequense ID: \"$SeqID\"\n");
            STDERR->print("Residue#     Phi     Psi  Ramachandran\n");
            my $refChainList = $g_PhiPsiChainHash{$SeqID};
            my @ChainList = @{$refChainList};
            foreach my $refResidue (@ChainList){
                my %Residue = %{$refResidue};
                my $FormatMsg = sprintf ("%-5i    %7.2f %7.2f  %-4s", 
                $Residue{$RESIDUE_SEQ_NUM}, $Residue{$PHI}, $Residue{$PSI}, $Residue{$RAMACHANDRAN});
                print "$FormatMsg \n";
            }#foreach
        }#foreach
    }#if
}#CalculatePhiPsiAngles() 

#############################################################################
## FUNCTION:     ParseAtomLine()
## PURPOSE:      
## PARAMETERS:   $refPDBNode   - [IN]     A hash reference containing the Current PDB Node hash.
##               
## RETURN:       
#############################################################################
sub ParseAtomLine{
    my $Line = "";
    my $AtomName = "";
    my $SeqID = "";
    my $ResidueSeqNumber = "";
    my $x = "";
    my $y = "";
    my $z = "";

    ($Line) = @_;
    $Line =~ s/\s+$//;
    $Line =~ s/^\s+//;
    $AtomName = GetRecordField($Line, '13_16');
    $AtomName =~ s/^\s+//;
    $AtomName =~ s/\s+$//;
    $SeqID = GetRecordField($Line, '22_22');
    $ResidueSeqNumber = GetRecordField($Line, '23_26');
    $ResidueSeqNumber =~ s/^\s+//;
    $ResidueSeqNumber =~ s/\s+$//;
    $x = GetRecordField($Line, '31_38');
    $x =~ s/^\s+//;
    $x =~ s/\s+$//;
    $y = GetRecordField($Line, '39_46');
    $y =~ s/^\s+//;
    $y =~ s/\s+$//;
    $z = GetRecordField($Line, '47_54');
    $z =~ s/^\s+//;
    $z =~ s/\s+$//;
    return ($AtomName, $SeqID, $ResidueSeqNumber, $x, $y, $z);
}#ParseAtomLine()

#############################################################################
## FUNCTION:     dihedral()
## PURPOSE:      
## PARAMETERS:   $refPDBNode   - [IN]     A hash reference containing the Current PDB Node hash.
##               
## RETURN:       
#############################################################################
sub dihedral{
        #coordinates of:
        #atom 1        atom 2         atom 3         atom 4
    my ($x1, $y1, $z1, $x2, $y2, $z2, $x3, $y3, $z3, $x4, $y4, $z4) =  0;
    my ($mag_nB, $mag_nF) =  0;
    my $dot               =  0; #dot product
    my $exp               =  0;
    my $radians           =  0; #dihedral in radians
    my $degrees           =  0; #dihedral in degrees
    my $sign              =  0;
    my $PI = atan2(0,-1);  #calculate PI

   ($x1, $y1, $z1, $x2, $y2, $z2, $x3, $y3, $z3, $x4, $y4, $z4) = @_;
   #Cross Product
   my $Bx  =   (($y1-$y2)*($z3-$z2) - ($z1-$z2)*($y3-$y2));
   my $By  = (-(($x1-$x2)*($z3-$z2) - ($z1-$z2)*($x3-$x2)));
   my $Bz  =   (($x1-$x2)*($y3-$y2) - ($y1-$y2)*($x3-$x2));
   $mag_nB = sqrt((0-$Bx)**2 + (0-$By)**2 + (0-$Bz)**2);#establish parameters to compute vector legnth

   my $Fx  =   (($y2-$y3)*($z4-$z3) - ($z2-$z3)*($y4-$y3));
   my $Fy  = (-(($x2-$x3)*($z4-$z3) - ($z2-$z3)*($x4-$x3)));
   my $Fz  =   (($x2-$x3)*($y4-$y3) - ($y2-$y3)*($x4-$x3));
   $mag_nF = sqrt((0-$Fx)**2 + (0-$Fy)**2 + (0-$Fz)**2);#establish parameters to compute vector legnth

   #Dot Product
   $dot = ($Bx*$Fx) + ($By*$Fy) + ($Bz*$Fz);#establish parameters to compute dot product
   #establish parameters to compute theta in radians, then degrees
   $exp = ($dot/($mag_nB * $mag_nF));
   $radians = atan2( sqrt(1 - $exp * $exp), $exp );    #acos #establish parameters to compute theta in radians, then degrees
   $degrees = (180 / $PI) * $radians;
   $sign = ($Bx*($x3-$x4)) + ($By*($y3-$y4)) + ($Bz*($z3-$z4));
   if($sign < 0) {$degrees = - abs($degrees);} else {$degrees = abs($degrees);}
   return $degrees;
}#dihedral()

    ############################################################################
    ###########                End Of Subsection                     ###########
    ###########               Specialty Functions                    ###########
    ############################################################################

    ################################################################################################
    ###########                                End Of                                    ###########
    ###########                             Code Section                                 ###########
    ###########                             PDB Functions                                ###########
    ################################################################################################

    ################################################################################################
    ###########                                                                          ###########
    ###########                             Code Section                                 ###########
    ###########                             DTD Functions                                ###########
    ###########  ReadDTDFile()                                                           ###########
    ###########  BuildDTDTree()                                                          ###########
    ###########  ReviewDTDTreeForErrors()                                                ###########
    ################################################################################################

############################################################################
# FUNCTION:     ReadDTDFile()
# PURPOSE:      Reads the DTD data structure.
# PARAMETERS:   None.
#               
# RETURN:       TRUE for success, otherwise FALSE.
############################################################################
sub ReadDTDFile{

    my $FileName                = ""; # the name of the DTD input file
    my $Line                    = ""; # to hold each line read from the DTD file
    my $ElementName             = ""; # the current element name
    my $ElementDeclaration      = ""; # the current element's declaration line including a line number
    my $TmpElementName          = ""; # temp
    my $AttributeName           = ""; # the current attribute name
    my $AttributeDeclaration    = ""; # the current attribute's declaration line including a line number
    my @TmpAttributeList        = (); # list containing all lines in g_AttributeDeclarationList that contain the current element
    my $CurrentAttributeLine    = ""; # used to walk the TmpAttributeList
    my $TmpAttributeName        = ""; # used to hold the attribute name found in CurrentAttributeLine
    my $EntityName              = ""; # the current entity name
    my $EntityDeclaration       = ""; # the current entity's declaration line including a line number
    my $bLookingForFirstElement =  1; # Must be True. It will be turned false after we found the first element
    my $bFoundDuplicate         =  0; #Must be False.
    my $ReturnStatus            =  1; #Must be True. (0 means failure)
    my @returnStatusMsg         = (); # list of messages to be returned in case of failures
    my $LineCount               =  0; #Must be zero intitially; It'll count the lines read from the DTD input file.
    my $LineNum                 =  0; # to hold the line number; 
    my $TmpLine                 = ""; # the current declaration line excluding the line number

    ($FileName) = @_; # get the parameter array and assign it to $FileName

    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function ReadDTDFile()\n");}
    if (open(FILE,"$FileName")){ # Open FileName into file handle FILE
        while ($Line = <FILE>){ # read each current line from FILE in the $Line var
            $Line =~ s/\s+$//; # remove all white spaces from the end of the line
            $LineCount++; # increase the counter for number of lines read
            SWITCH: {
                if ( $Line =~ /^$g_DTDDeclareSyntax{Element}/ ){ # if <!ELEMENT is found in the beginning of the line
                    ## Remove Tag Information
                    $ElementDeclaration = $Line; # var to keep all line content that has an element declaration
                    $ElementDeclaration =~ s/^$g_DTDDeclareSyntax{Element}//; # Remove the <!ELEMENT from the beginning of the line
                    $ElementDeclaration =~ s/^\s+//; # remove any spaces that might have been left in the beginning of the line
                    ($ElementDeclaration)=split(/\>/,$ElementDeclaration); # we split the line (by '>') and save just the first string what is to the right of the first '>' encountered
                    $ElementDeclaration =~ s/\s+$//; # remove any spaces that might have been left at the end of the line
                    $ElementDeclaration =~ s/\s+/ /g; # replace any one-or-more spaces with only-one-space
                    ## Get Element Name
                    $ElementName   = $ElementDeclaration; # var to hold the element name part of the element declaration line
                    $ElementDeclaration =  "$ElementDeclaration $DTD_LINENUM $LineCount"; # we reassign to $ElementDeclaration a string that contains the declaration-string plus "DTDLine: Line#" ; this can be used for debugging purposes to show in which line # of the DTD some problem was found
                    ($ElementName) = split(/\(/,$ElementName); # we split by '(' and thus eliminate the possible children found in the line in between ()
                    ($ElementName) = split(/\s+/,$ElementName); # we split by one-or-more spaces thus eliminate any possible DTD-type
                    $ElementName   =~ s/\s+$//; # we eliminate any space at right-hand-side
                    ## Ensure no duplicates
                    if( !(grep /^$ElementName$/, @g_ElementNameList) ){ # checking if this newly found element name is not found on the list
                        if ($bRunTimeDebug){STDERR->print("FOUND NEW ELEMENT: $ElementDeclaration\n");}
                       push @g_ElementNameList, $ElementName; # push the new element name onto the list
                       push @g_ElementDeclarationList, $ElementDeclaration; # push the new declaration onto the list of declaration lines
                       if ($bLookingForFirstElement){
                           $g_RootElement = $ElementName; # assign the newly found element as the root element name
                           $g_RootLineNum = $LineCount; # record the line number for the root element
                           $bLookingForFirstElement = 0; # set the flag to false for the rest of the run
                       }#if
                    }else{
                        ($TmpLine, $LineNum) = split(/$DTD_LINENUM\s+/,$ElementDeclaration); # see next comment
                        push @returnStatusMsg, "Duplicate Element ($LineNum): $TmpLine\n"; # pushing on the list of returned messages the element declaration and its line #
                        $ReturnStatus = 0; # set the status to failed
                   }#else
                   last SWITCH; # get out of the switch
                }#if
                if ( $Line =~ /^$g_DTDDeclareSyntax{Attribute}/ ){# if <!ATTRIBUTE is found in the beginning of the line
                    ## Remove Tag Information
                    $AttributeDeclaration = $Line;# var to keep all line content that has an attribute declaration
                    $AttributeDeclaration =~ s/^$g_DTDDeclareSyntax{Attribute}//;# Remove the <!ATTRIBUTE from the beginning of the line
                    $AttributeDeclaration =~ s/^\s+//;# remove any spaces that might have been left in the beginning of the line
                    ($AttributeDeclaration)=split(/\>/,$AttributeDeclaration);# we split the line (by '>') and save just the first string what is to the right of the first '>' encountered
                    $AttributeDeclaration =~ s/\s+$//;# remove any spaces that might have been left at the end of the line
                    $AttributeDeclaration =~ s/\s+/ /g;# replace any one-or-more spaces with only-one-space
                    ## Get Element and Attribute Name
                    ($ElementName, $AttributeName)=split(/\s+/,$AttributeDeclaration);# we split by one-or-more spaces thus eliminate any possible DTD-type
                    $AttributeDeclaration = "$AttributeDeclaration $DTD_LINENUM $LineCount";# we reassign to $AttributeDeclaration a string that contains the declaration-string plus "DTDLine: Line#" ; this can be used for debugging purposes to show in which line # of the DTD some problem was found
                    ## Ensure no duplicates
                    $bFoundDuplicate = 0;
                    @TmpAttributeList = grep /^($ElementName )/, @g_AttributeDeclarationList; # find any lines in the attribute declarations list that start with the element name pattern, and store them in TmpAttributeList
                    foreach $CurrentAttributeLine (@TmpAttributeList) {
                        ($TmpElementName, $TmpAttributeName) = split(/\s+/,$CurrentAttributeLine); # split on space(s) to get the element and the attribute names of the current line 
                        $TmpElementName =~ s/^\s+//; # clean up spaces in front
                        $TmpElementName =~ s/\s+$//; # clean up spaces in back
                        if (($ElementName eq $TmpElementName) && ($AttributeName eq $TmpAttributeName)){
                            ($TmpLine, $LineNum) = split(/$DTD_LINENUM\s+/,$CurrentAttributeLine);
                            push @returnStatusMsg, "Duplicate Attribute ($LineNum): $TmpLine\n";
                            $ReturnStatus = 0; # set status to failure
                            $bFoundDuplicate = 1; # set flag for found duplicates
                        }#if
                    }#foreach
                    if(!($bFoundDuplicate)){ # if not a duplicate push the attribute name and its declaration line onto their on respective lists
                        push @g_AttributeNameList, $AttributeName;
                        if ($bRunTimeDebug){STDERR->print("FOUND NEW ATTRIBUTE: \"$AttributeDeclaration\"\n");}
                        push @g_AttributeDeclarationList, $AttributeDeclaration;
                    }#if
                    last SWITCH;# get out of the switch
                }#if
                if ( $Line =~ /^$g_DTDDeclareSyntax{Entity}/ ){ # similar comments as for the if(element); currently the DTD for PDB does not use entities anyway
                    ## Remove Tag Information
                    $EntityDeclaration = $Line;
                    $EntityDeclaration =~ s/^$g_DTDDeclareSyntax{Entity}//;
                    $EntityDeclaration =~ s/^\s+//;
                    ($EntityDeclaration)=split(/\>/,$EntityDeclaration);
                    $EntityDeclaration =~ s/\s+$//;
                    $EntityDeclaration =~ s/\s+/ /g;
                    ## Get Entity Name
                    ($EntityName)=split(/\s+/,$EntityDeclaration);
                    $EntityDeclaration = "$EntityDeclaration  $DTD_LINENUM $LineCount";
                    ## Ensure no duplicates
                    if( !(grep /^$EntityName$/, @g_EntityNameList)){
                        push @g_EntityNameList, $EntityName;
                        if ($bRunTimeDebug){STDERR->print("FOUND NEW ENTITY: \"$EntityDeclaration\"\n");}
                        push @g_EntityDeclarationList, $EntityDeclaration;
                    }else{
                        ($TmpLine, $LineNum) = split(/$DTD_LINENUM\s+/,$EntityDeclaration);
                        push @returnStatusMsg, "Duplicate Entity ($LineNum): $TmpLine\n";
                        $ReturnStatus = 0;
                        if ($bRunTimeDebug){STDERR->print("ERROR INFO: Duplicate Entity: \"$EntityName\"\n");}
                    }#else
                    last SWITCH;
                }#if
            }#SWITCH
        }#while
        close FILE;
    }#if
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function ReadDTDFile()\n");}
    return ($ReturnStatus, @returnStatusMsg);
}#ReadDTDFile()

############################################################################
# FUNCTION:     BuildDTDTree()
# PURPOSE:      Build a tree of the DTD.
# PARAMETERS:   $refCurrentElementNode  - [IN] A hash reference containing a CurrentElementNode hash.
#               
# RETURN:       TRUE for success, otherwise FALSE.
############################################################################
sub BuildDTDTree{

    my $refCurElementNode     =  0; # var that will hold a reference(address) to the current DTD node hash
    my %CurElementNode        = []; # hash (initialized to empty) that will get assigned the key-value pairs for the current node hash
    my @SubElementDeclarationList = (); # it will store any lines in the element declarations list that start with the current element name; used to verify if a proclaimed Child has a Declaration
    my $TmpElementLine        = ""; #
    my $TmpLine               = ""; #
    my $TmpElementName        = ""; #
    my $Junk                  = ""; #
    my $ParentElementName     = ""; #
    my $ParentLineNum         = ""; #
    my $CurElementName        = ""; #
    my $CurCategory           = ""; #
    my $LineNum               = ""; #
    my @CurChildNodeList      = (); #
    my @TmpCurChildNodeList   = (); #
    my $TmpChildNode          = ""; #
    my @TmpAttributeList      = (); #
    my $TmpAttributeLine      = ""; #
    my $TmpAttributeName      = ""; #
    my @CurrentAttributeList  = (); #
    my @CurrentAttributeNameList = (); #
    my $TmpBeginTagAttributes = ""; #
    my $DataType              = "";
    my $DefaultData           = "";
    my $bStopSearch           =  0;  # Must be FALSE. 
    my $StatusResult          =  0; #
    my @StatusResultMsg       = ();
    my @returnStatusMsg       = ();
    my $FormatMsg             = ""; #

    ($refCurElementNode) = @_; # assigning the parameter array to the variable refCurElementNode; In this case it will be an address of the current node hash (initially the \%DTDTree)

    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function BuildDTDTree()\n");}
    %CurElementNode = %{$refCurElementNode};                         # dereference the hash reference and copy its contents into new hash CurElementNode
    $CurElementName = $CurElementNode{$ELEMENT_NAME};                # copy into var $CurElementName the value corresponding to the 
                                                                     #$ELEMENT_NAME key in the hash CurElementNode
    if (($bRunTimeDebug eq 0) && ($bVerify eq 0) && ($bLineProcess eq 0) && ($bQStat eq 0)){
    STDERR->print(".");                                              # print one dot for each time the BuildDTDTree is called
    }#if

    ###############################################################
    #Ensure the Proclaimed Child has a Declaration.
    #Should always be only one since a duplicate check has already been done.
    ###############################################################
    @SubElementDeclarationList = grep /^($CurElementName )/, @g_ElementDeclarationList; #find any lines in the element declarations list that start with
                                                                                        # the element name pattern, and store them in SubE.D.List
    if ( 0 == scalar(@SubElementDeclarationList)) {                                     # if the SubElementDeclarationList is empty get the parent 
        $ParentElementName = ${%{$CurElementNode{$ref_PARENTNODE}}}{$ELEMENT_NAME};  # element name and its line number to print error message
        $ParentLineNum     = ${%{$CurElementNode{$ref_PARENTNODE}}}{$ELEMENT_LINE_NUM};
        $FormatMsg = "Proclaimed Child ($ParentLineNum): Parent Element \"$ParentElementName\" " .
                     "proclaimed a child Element \"$CurElementName\"\n";
        push @returnStatusMsg, $FormatMsg;
        $ParentLineNum =~ s/\S/ /g;
        $FormatMsg = "                  $ParentLineNum   but none exist in the Element Declaration list.\n";
        push @returnStatusMsg, $FormatMsg;
        return(0, @returnStatusMsg);                                                     # exit out of BuildDTDTree and return the error message
    }#if

    ###############################################################
    # Parse the declaration to get the Element's Category. 
    ###############################################################
    if ($bRunTimeDebug){STDERR->print("DEBUG INFO: New List of Elements lines: @SubElementDeclarationList\n");}
    while (($TmpElementLine = shift(@SubElementDeclarationList)) && (!$bStopSearch)){
        ($TmpElementLine, $LineNum) = split(/$DTD_LINENUM\s+/,$TmpElementLine);     # use split to get the LineNumber out of TmpElementLine
        $TmpLine = $TmpElementLine;                                                 # make a temp copy
        ($TmpLine, $Junk) = split(/\(/,$TmpLine);                                   # we split by '(' and thus eliminate the possible children found in
        if ($bRunTimeDebug){STDERR->print("Split Line: \"$TmpLine\", \"$Junk\" \n");} # the line after '('
        ($TmpElementName, $Junk) = split(/\s+/,$TmpLine);                           # split to copy the element name into TmpElementName
        $TmpElementName =~ s/\s+$//;
        if ($bRunTimeDebug){STDERR->print("Split Line: \"$TmpElementName\", \"$Junk\" \n");}
        if ($TmpElementName eq $CurElementName){                                    # if the current TmpElementLine is for the current element
           $g_RealizedAssociatedElementNameCount++;                                 # increment the elements counter 
            #Note this is a local copy while the real struct is refCurElementNode
            $CurElementNode{$ELEMENT_LINE_NUM} = $LineNum;                      # assign $ELEMENT_LINE_NUM member of current node hash value of LineNum
            #Update the real struct since any child will get the real struct.
            ${%{$refCurElementNode}}{$ELEMENT_LINE_NUM} = $LineNum;
            my $TmpBuffer = $TmpElementName;                                    #c? ???? is my needed ??? # used to avoid overwriting of TmpElementName
#           push @g_RealizedAssociatedElementNameList, $TmpBuffer;                  # save the element  name into the g_RealizedA.E.NameList
####################################
            ## take into account reuse of declarations
            if( !(grep /^$CurElementName$/, @g_RealizedAssociatedElementNameList) ){ # check if this realized element may have been used.
                push @g_RealizedAssociatedElementNameList, $TmpBuffer;                  # save the element  name into the g_RealizedA.E.NameList
            }else{
                if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO:Reused: $CurElementName\n");}
                $g_RealizedAssociatedElementNameReusedCount++;
            }#else
####################################
            if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Current Element line: $TmpElementLine\n");}
            $TmpElementLine =~ s/^$CurElementName//;                            # 7 statements remove everything from TmpElementLine except element type.
            $TmpElementLine =~ s/^\s+//;
            $TmpElementLine =~ s/^\(//;
            $TmpElementLine =~ s/^\s+//;
            $TmpElementLine =~ s/\s+$//;
            $TmpElementLine =~ s/\)$//;
            $TmpElementLine =~ s/\s+$//;
            $CurCategory = $TmpElementLine;
            $bStopSearch = 1;                                                # we found all we needed about the current element, thus stop the while loop
        }#if
    }#while

    ###############################################################
    #Get the list of attributes for the current element, if any.
    ###############################################################
    @TmpAttributeList = grep /^($CurElementName )/, @g_AttributeDeclarationList;       # copy into TmpAttributeList any lines found in g_A.D.List
    foreach $TmpAttributeLine (@TmpAttributeList){                                  #that start with the current element name
        ($TmpAttributeLine, $LineNum) = split(/$DTD_LINENUM\s+/,$TmpAttributeLine); # use split to get the LineNumber out of TmpAttributeLine
        ($TmpElementName, $Junk) = split(/\s+/,$TmpAttributeLine);                  # copy into TmpElementName the element name found in TmpAttributeLine
        $TmpElementName =~ s/^\s+//;
        $TmpElementName =~ s/\s+$//;
        if ($TmpElementName eq $CurElementName){                                    # if the current TmpAttributeLine is for the current element
            $g_AttributesAssociatedWithElementCount++;                              # increment the attributes counter for the current element
            if ($bRunTimeDebug){STDERR->print("DEBUG INFO: Current Attribute line: $TmpAttributeLine\n");}
#            push @g_AttributesAssociatedWithElements, $TmpAttributeLine;            # save the TmpAttributeLine into the g_A.A.WithElements list
####################################
            ## take into account reuse of declarations
            if( !(grep /^$TmpAttributeLine$/, @g_AttributesAssociatedWithElements) ){ #
                push @g_AttributesAssociatedWithElements, $TmpAttributeLine;          #
            }else{
                $g_AttributesAssociatedWithElementReusedCount++;
            }#else
####################################
            $TmpAttributeLine =~ s/^$CurElementName//;                              # get rid of the CurElementName from TmpAttributeLine
            $TmpAttributeLine =~ s/^\s+//;                                          # clean any spaces
            ($TmpAttributeName, $DataType, $DefaultData) = split(/\s+/,$TmpAttributeLine);            # save the attribute name into TmpAttributeName
            push @CurrentAttributeNameList, $TmpAttributeName;                      # push the attribute name into the CurrentAttributeNameList
            if (($DataType eq $ATTRIB_TYPE_CDATA) && (grep /^\"\w+\"$/, $DefaultData)){
                $DefaultData =~ s/^\"//;
                $DefaultData =~ s/\"$//;
                $TmpAttributeName = "$TmpAttributeName=\"$DefaultData\"";
            }
            $TmpBeginTagAttributes = "$TmpBeginTagAttributes $TmpAttributeName";    # temporary string that will be used later to create the tagged XML
                                                                                    # line (of type <elem attrib1="somevalue" attrib2="somevalue" etc>)
            push @CurrentAttributeList, $TmpAttributeLine;                          # push the TmpAttributeLine (which now has just attribute name and 
        }#if                                                                        #its type) into the CurrentAttributeList
    }#foreach
    $TmpBeginTagAttributes =~ s/^\s+//;
    $CurElementNode{$ref_ATTRIBUTE_NAME_LIST} = \@CurrentAttributeNameList;         # assign to the $ref_ATTRIBUTE_NAME_LIST member of the current node
                                                                                    # hash the address of the CurrentAttributeNameList
    $CurElementNode{$ref_ATTRIBUTE_LIST} = \@CurrentAttributeList;                  # same for the ref_ATTRIBUTE_LIST


    ###############################################################
    # Determine the Element's Category. 
    ###############################################################
    if ($bRunTimeDebug){
        STDERR->print("\nDEBUG INFO: Determine the Element's \"$CurElementName\" category\n");
        STDERR->print("DEBUG INFO: Category Line Data: $CurCategory\n");
    }#if
    SWITCH: {
        if ($CurCategory eq $ELEM_CAT_PND_PCDATA){
            $CurElementNode{$ELEMENT_CATEGORY} = $ELEM_CAT_PND_PCDATA;
            if ($TmpBeginTagAttributes eq ""){                                             # if we do not have attributes
                $CurElementNode{$BEGIN_TAG} = "<$CurElementName>"; 
            }else{
                $CurElementNode{$BEGIN_TAG} = "<$CurElementName $TmpBeginTagAttributes>"; 
            }#if
            $CurElementNode{$PCDATA}           = "";                                       # initialize to empty string
            $CurElementNode{$END_TAG}          = "</$CurElementName>";                     # create the end tag
#  PrintNodeReport(\%CurElementNode, "DTD");
           last SWITCH;
        }#if
        if ($CurCategory eq $ELEM_CAT_ANY){
            $CurElementNode{$ELEMENT_CATEGORY} = $ELEM_CAT_ANY;
            if ($TmpBeginTagAttributes eq ""){
                $CurElementNode{$BEGIN_TAG} = "<$CurElementName>"; 
            }else{
                $CurElementNode{$BEGIN_TAG} = "<$CurElementName $TmpBeginTagAttributes>";
            }#if
            $CurElementNode{$PCDATA}           = "";
            $CurElementNode{$END_TAG}          = "</$CurElementName>";
#  PrintNodeReport(\%CurElementNode, "DTD");
           last SWITCH;
        }#if
        if ($CurCategory eq $ELEM_CAT_EMPTY){
            $CurElementNode{$ELEMENT_CATEGORY} = $ELEM_CAT_EMPTY;
            if ($TmpBeginTagAttributes eq ""){
                $CurElementNode{$BEGIN_TAG}        = "<$CurElementName/>";
            }else{
                $CurElementNode{$BEGIN_TAG}        = "<$CurElementName $TmpBeginTagAttributes/>";
            }#if
            $CurElementNode{$PCDATA}           = "";
            $CurElementNode{$END_TAG}          = "";
#  PrintNodeReport(\%CurElementNode, "DTD");
           last SWITCH;
        }#if
        default:{
            $CurElementNode{$ELEMENT_CATEGORY} = $ELEM_CAT_LIST;
            if ($TmpBeginTagAttributes eq ""){
                $CurElementNode{$BEGIN_TAG}        = "<$CurElementName>";
            }else{
                $CurElementNode{$BEGIN_TAG}        = "<$CurElementName $TmpBeginTagAttributes>";
            }#if
            $CurElementNode{$PCDATA}           = "";
            $CurElementNode{$END_TAG}          = "</$CurElementName>";
            last SWITCH;
        }#default
    }#SWITCH
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Category Type: $CurElementNode{$ELEMENT_CATEGORY}\n");}
    ###############################################################
    # Create new children Nodes for the DTD Tree. 
    ###############################################################
    if ($CurElementNode{$ELEMENT_CATEGORY} eq $ELEM_CAT_LIST){
        (@CurChildNodeList) = split(/,/,$CurCategory); # split on ',' to get the list of children
        @TmpCurChildNodeList = @CurChildNodeList; # make a temp copy
        @CurChildNodeList = (); # asign empty list to CurChildNodeList
        foreach $TmpChildNode (@TmpCurChildNodeList) { # clean up spaces and save each TmpChildNode into the CurChildNodeList
            $TmpChildNode =~ s/^\s+//;
            $TmpChildNode =~ s/\s+$//;
            push @CurChildNodeList, $TmpChildNode;
        }#foreach
        if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: ChildNodeList:  @CurChildNodeList\n");}
        @TmpCurChildNodeList = @CurChildNodeList; # copy into TmpCurChildNodeList
        $CurElementNode{$ref_CHILDNODE_LIST} = \@CurChildNodeList; # assign to the $ref_CHILDNODE_LIST member of the current node hash the address of the CurChildNodeList
#  PrintNodeReport(\%CurElementNode, "DTD");
        foreach $TmpChildNode (@TmpCurChildNodeList) { # clean up for each TmpChildNode spaces, +s, *s and ?s
            $TmpChildNode =~ s/^\s+//;
            $TmpChildNode =~ s/\s+$//;
            $TmpChildNode =~ s/\+$//;
            $TmpChildNode =~ s/\*$//;
            $TmpChildNode =~ s/\?$//;
            $g_ProclaimedAssociatedElementCount++; # increment counter for the g_ProclaimedAssociatedElementCount
            my %NewElementNode = ($ELEMENT_NAME       => '', # for each TmpChildNode create a NewElementNode hash
                                  $ELEMENT_CATEGORY   => '',
                                  $ELEMENT_LINE_NUM   => '',
                                  $ref_MYNODE         => '',
                                  $ref_PARENTNODE     => '',
                                  $ref_CHILDNODE_LIST => '',
                                  $ref_ATTRIBUTE_LIST => '');
            my @EmptyAttributeList = ();
            $NewElementNode{$ELEMENT_NAME}       = $TmpChildNode;
            $NewElementNode{$ref_MYNODE}         = \%NewElementNode;
            $NewElementNode{$ref_PARENTNODE}     = $CurElementNode{$ref_MYNODE};
            $NewElementNode{$ref_ATTRIBUTE_LIST} = \@EmptyAttributeList;
            
            $CurElementNode{$TmpChildNode} = \%NewElementNode; # save the address of the child named "$TmpChildNode"
            
            ($StatusResult, @StatusResultMsg)    = BuildDTDTree(\%NewElementNode); # recursive call to BuildDTDTree for the new child node
            if ( 0 == $StatusResult){
                push @returnStatusMsg, @StatusResultMsg;
                return(0, @returnStatusMsg);
            }#if
        }#foreach
    }#if

    %{$refCurElementNode} = %CurElementNode; # Once we are done working with %CurElementNode, we copy all its contents back into the original hash at address $refCurElementNode

    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function BuildDTDTree()\n");}
    return(1, ());
}#BuildDTDTree()

############################################################################
# FUNCTION:     ReviewDTDTreeForErrors()
# PURPOSE:      Ensure all declared Elements, Attribute, and Entities have
#               been incorporated into the DTD tree.
# PARAMETERS:   $ - [IN] 
#
# RETURN:       None.
############################################################################
sub ReviewDTDTreeForErrors{
    my $ref_ErrorMsg             =  0;
    my $ElementDeclarationCount  =  0;
    my $TmpElementLine           = "";
    my $TmpAssociatedAttributeLine = "";
    my $TmpElementName           =  0;
    my $AttributeDeclarationCount=  0;
    my $TmpAttributeName         = "";
    my $AttributeAssociatedCount =  0;
    my $TmpAttributeLine         =  0;
    my $OrphanElementCount       =  0;
    my $OrphanAttributeCount     =  0;
    my $EntityCount              =  0;
    my $TmpElementName           = "";
    my $TmpAssocElementName      = "";
    my $TmpAssocAttributeName    = "";
    my $Junk                     =  0;
    my @AttributeWithUndeclaredElementList = ();
    my @AttributeWithUnAssociatedAncestorList = ();
    my @SubAssociatedAttributeList = ();
    my @TmpElementList           = ();
    my @TmpElementNameList       = ();
    my @TmpAttributeList         = ();
    my $TmpLine                  = "";
    my $bStopPrinting            =  0; #MUST BE FALSE
    my $bFoundInList             =  0;
    my $PrintCount               =  0;
    my $ErrorStatus              =  0;
    my @Msg                      = ();
    my $MsgLine                  = "";
    my $LineNum                  =  0;
    my $ReturnStatus             = 1; #MUST BE TRUE

    ($ErrorStatus, @Msg) = @_;


    $ElementDeclarationCount = scalar (@g_ElementDeclarationList);
    $AttributeDeclarationCount = scalar (@g_AttributeDeclarationList);
    $EntityCount = scalar (@g_EntityDeclarationList);
#    $OrphanElementCount = $ElementDeclarationCount - $g_RealizedAssociatedElementNameCount;
    $OrphanElementCount = $ElementDeclarationCount - $g_RealizedAssociatedElementNameCount + $g_RealizedAssociatedElementNameReusedCount;
    $OrphanAttributeCount = $AttributeDeclarationCount - $g_AttributesAssociatedWithElementCount + $g_AttributesAssociatedWithElementReusedCount;

    STDERR->print("\n");
    STDERR->print("******************************************\n");
    STDERR->print("****     General DTD Information      ****\n");
    STDERR->print("******************************************\n\n");
    STDERR->print("************************************\n");
    STDERR->print("****  DTD File Declared Definitions:\n");
    STDERR->print("************************************\n");
    STDERR->print("   Element Declaration: $ElementDeclarationCount\n");
    STDERR->print("Attributes Declaration: $AttributeDeclarationCount\n");
    STDERR->print("    Entity Declaration: $EntityCount\n\n");
    if ($ErrorStatus != $ERROR_DTD_READ){
        STDERR->print("***************************\n");
        STDERR->print("****  DTD Tree Definitions:\n");
        STDERR->print("***************************\n");
        STDERR->print("          Root Element: $g_RootElement \n");
        STDERR->print("   Proclaimed Elements: $g_ProclaimedAssociatedElementCount\n");
        STDERR->print("   Associated Elements: $g_RealizedAssociatedElementNameCount\n");
        STDERR->print("     Orphaned Elements: $OrphanElementCount\n\n");
        STDERR->print(" Associated Attributes: $g_AttributesAssociatedWithElementCount\n");
        STDERR->print("   Orphaned Attributes: $OrphanAttributeCount\n\n");
    }#if
    SWITCH: {
        if ($ErrorStatus eq $ERROR_DTD_READ){
            STDERR->print("******************************************************************\n");
            STDERR->print("****  Error: Errors were detected while reading the DTD file  ****\n");
            STDERR->print("******************************************************************\n");
            foreach $MsgLine (@Msg){
                STDERR->print($MsgLine);
            }#foreach
            $ReturnStatus = 0;
            last SWITCH;
        }#if
        if ($ErrorStatus eq $ERROR_DTD_BUILD){
            STDERR->print("********************************************************************\n");
            STDERR->print("****  Error: Errors were detected while building the DTD tree.  ****\n");
            STDERR->print("********************************************************************\n");
            foreach $MsgLine (@Msg){
                STDERR->print($MsgLine);
            }#foreach
            $ReturnStatus = 0;
            last SWITCH;
        }#if
        default:{
            if (($OrphanElementCount > 0) || ($OrphanAttributeCount > 0)){
                STDERR->print("****************************************************************************\n");
                STDERR->print("****  Error: The DTD tree was built without all declared definitions.   ****\n");
                STDERR->print("****                                                                    ****\n");
                STDERR->print("****         Element orphans exist when it or one of its ancestors are  ****\n");
                STDERR->print("****         not proclaimed by a parent Element.  Review the number of  ****\n");
                STDERR->print("****         Proclaimed and Associated Elements to determine the number ****\n");
                STDERR->print("****         of disassociated trees branches possibly causing multiple  ****\n");
                STDERR->print("****         orphans.  Attribute orphans exist when its Element is not  ****\n");
                STDERR->print("****         declared or a parent Element does not proclaim the         ****\n");
                STDERR->print("****         Attribute's Element as its child Element.                  ****\n");
                STDERR->print("****************************************************************************\n");

                if ($OrphanElementCount > 0){  #Orphan
                    $ReturnStatus = 0;
                    STDERR->print("\n");
                    STDERR->print("****************************\n");
                    STDERR->print("****  Unassociated Elements:\n");
                    STDERR->print("****************************\n");
                    @TmpElementList = @g_ElementDeclarationList;
                    while (($TmpElementLine = shift(@TmpElementList)) && (!$bStopPrinting)){
                        ($TmpElementLine, $LineNum) = split(/$DTD_LINENUM\s+/,$TmpElementLine);
                        ($TmpElementName, $TmpAttributeName) = split(/\s+/,$TmpElementLine); 
                        $TmpElementName =~ s/^\s+//;
                        $TmpElementName =~ s/\s+$//;
                        if (0 == (grep /^$TmpElementName$/, @g_RealizedAssociatedElementNameList)){
                            $TmpElementLine =~ s/^\s+//;
                            $TmpElementLine =~ s/\s+$//;
                            STDERR->print("Orphan Element ($LineNum): \"$TmpElementLine\"\n");
                            $PrintCount++;
                        }#if
                        if ($PrintCount >= 25 ){
                            STDERR->print("\n");
                            STDERR->print("  ...\n");
                            STDERR->print("  ...\n");
                            STDERR->print("  ...\n");
                            $bStopPrinting = 1;
                        }#if
                    }#while
                    $bStopPrinting = 0;
                    $PrintCount = 0;
                }#if
                if ($OrphanAttributeCount > 0){  #Orphan
                    $ReturnStatus = 0;
                    @TmpAttributeList = @g_AttributeDeclarationList;
                    while (($TmpAttributeLine = shift(@TmpAttributeList)) && (!$bStopPrinting)){
                        ($TmpAttributeLine, $LineNum) = split(/$DTD_LINENUM\s+/,$TmpAttributeLine);
                        ($TmpElementName, $TmpAttributeName) = split(/\s+/,$TmpAttributeLine); 
                        $TmpElementName =~ s/^\s+//;
                        $TmpElementName =~ s/\s+$//;
                        $TmpAttributeName =~ s/^\s+//;
                        $TmpAttributeName =~ s/\s+$//;
                        ## Orphan due to its Element was not declaired.
                        if (0 == (grep /^$TmpElementName$/, @g_ElementNameList)){
                            $TmpAttributeLine =~ s/^$TmpElementName//;
                            $TmpAttributeLine =~ s/^\s+//;
                            $TmpAttributeLine =~ s/\s+$//;
                            $TmpLine = "Orphan Attribute ($LineNum): ($TmpElementName) \"$TmpAttributeLine\"\n";
                            push @AttributeWithUndeclaredElementList, $TmpLine;
                            $PrintCount++;
                        }else{
                            $bFoundInList = 0;
                            @SubAssociatedAttributeList = grep /$TmpAttributeName/, @g_AttributesAssociatedWithElements;
                            foreach $TmpAssociatedAttributeLine (@SubAssociatedAttributeList) {
                                ($TmpAssocElementName,$TmpAssocAttributeName) = split(/\s+/,$TmpAssociatedAttributeLine);
                                $TmpAssocElementName   =~ s/^\s+//;
                                $TmpAssocElementName   =~ s/\s+$//;
                                $TmpAssocAttributeName =~ s/^\s+//;
                                $TmpAssocAttributeName =~ s/\s+$//;
                                if (($TmpElementName eq $TmpAssocElementName) &&
                                    ($TmpAttributeName eq $TmpAssocAttributeName)){
                                    $bFoundInList = 1;
                                }#if
                            }#foreach
                            # Orphan due to an ancestor is an orphan.
                            if ( $bFoundInList == 0){
                                $TmpAttributeLine =~ s/^$TmpElementName//;
                                $TmpAttributeLine =~ s/^\s+//;
                                $TmpAttributeLine =~ s/\s+$//;
                                $TmpLine = "Orphan Attribute ($LineNum): ($TmpElementName) \"$TmpAttributeLine\"\n";
                                push @AttributeWithUnAssociatedAncestorList, $TmpLine;
                                $PrintCount++;
                            }#if
                        }#else
                        if ($PrintCount >= 25 ){$bStopPrinting = 1; }
                    }#while
                    if (0 != scalar(@AttributeWithUndeclaredElementList)){
                        STDERR->print("\n");
                        STDERR->print("***************************************\n");
                        STDERR->print("****  Attribute's Element not declared:\n");
                        STDERR->print("***************************************\n");
                        foreach $TmpLine (@AttributeWithUndeclaredElementList){
                            STDERR->print($TmpLine);
                        }#foreach
                    }#if
                    if (0 != scalar(@AttributeWithUnAssociatedAncestorList)){
                        STDERR->print("\n");
                        STDERR->print("*****************************************************\n");
                        STDERR->print("****  Attribute's Element or ancestor not proclaimed:\n");
                        STDERR->print("*****************************************************\n");
                        foreach $TmpLine (@AttributeWithUnAssociatedAncestorList){
                            STDERR->print($TmpLine);
                        }#foreach
                    }#if
                    if ($bStopPrinting == 1 ){
                        STDERR->print("\n");
                        STDERR->print("  ...\n");
                        STDERR->print("  ...\n");
                        STDERR->print("  ...\n");
                    }#if
                    $bStopPrinting = 0;
                    $PrintCount = 0;
                }#if
            }#if (($OrphanElementCount > 0) || ($OrphanAttributeCount > 0))
            last SWITCH;
        }#default
    }#SWITCH
    STDERR->print("\n");
    STDERR->print("******************************************\n");
    STDERR->print("****  End of General DTD Information  ****\n");
    STDERR->print("******************************************\n\n");
    if ($bRunTimeDebug){STDERR->print("\nDEBUG: INFO: Exiting function PrintTotalsReport()\n");}
    return ($ReturnStatus);
}#ReviewDTDTreeForErrors

    ################################################################################################
    ###########                                End Of                                    ###########
    ###########                             Code Section                                 ###########
    ###########                             DTD Functions                                ###########
    ################################################################################################


    ################################################################################################
    ###########                                                                          ###########
    ###########                             Code Section                                 ###########
    ###########                          Interface Functions                             ###########
    ###########  PrintLineReport()                                                       ###########
    ###########  PrintNodeReport()                                                       ###########
    ###########  QuickStat()                                                             ###########
    ###########  PrintVersion()                                                          ###########
    ###########  GetFileName()                                                           ###########
    ###########  GetUserResponse()                                                       ###########
    ###########  BuildPrintableXMLFromPDBTree()                                          ###########
    ###########  PrintXMLFile()                                                          ###########
    ###########  PrintFormatList()                                                       ###########
    ###########  PrintAllDTDGlobalList()                                                 ###########
    ################################################################################################

############################################################################
# FUNCTION:     PrintLineReport()
# PURPOSE:      To print a line hash. 
# PARAMETERS:   $refCurLineInfo  - [IN] A hash reference containing a CurLineInfo hash.
#
# RETURN:       None.
############################################################################
sub PrintLineReport{

    my $refLineInfo     =  0;
    my $NodeType        = "";
    my %LineInfo        = [];
    my @KeyList         = "";
    my $TmpKey          = "";

    ($refLineInfo, $NodeType) = @_;
    %LineInfo      = %{$refLineInfo};

    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function PrintLineReport()\n");}
    STDERR->print("\n******** LineInfo: \"$NodeType\" ********\n");
    if ( 0 < (length ($LineInfo{$PDB_LINE}))){
        STDERR->print(" Record Name: $LineInfo{$RECORD_NAME}\n");
        STDERR->print("Element Name: $LineInfo{$ELEMENT_NAME}\n");
        STDERR->print(" Record Type: $LineInfo{$RECORD_TYPE}\n");
        STDERR->print("    PDB Line: \"$LineInfo{$PDB_LINE}\"\n"); 
        STDERR->print("      Action: \"$LineInfo{$ACTION}\"\n"); 
        STDERR->print("rfField Hash: \"$LineInfo{$ref_FIELD_HASH}\"\n"); 
        STDERR->print("   Key Count: $LineInfo{$KEY_COUNT}\n");
############### Master Keys 
        if (0 != @{$LineInfo{$ref_KEYS}} ){
            @KeyList = @{$LineInfo{$ref_KEYS}};
            STDERR->print(" Master Keys: ");
            foreach $TmpKey (@KeyList) {
                STDERR->print("\"$TmpKey\" ");
            }#foreach
            STDERR->print("\n");
        }else{
            STDERR->print(" Master Keys: None\n");
        }#if
############### Current Keys 
        if (0 != @{$LineInfo{$ref_CURR_KEYS}} ){
            @KeyList = @{$LineInfo{$ref_CURR_KEYS}};
            STDERR->print("   Curr Keys: ");
            foreach $TmpKey (@KeyList) {
                STDERR->print("\"$TmpKey\" ");
            }#foreach
            STDERR->print("\n");
        }else{
            STDERR->print("   Curr Keys: None\n");
        }#if
############### Used Keys 
        if (0 != @{$LineInfo{$ref_USED_KEYS}} ){
            @KeyList = @{$LineInfo{$ref_USED_KEYS}};
            STDERR->print("   Used Keys: ");
            foreach $TmpKey (@KeyList) {
                STDERR->print("\"$TmpKey\" ");
            }#foreach
            STDERR->print("\n");
        }else{
            STDERR->print("   Used Keys: None\n");
        }#if
        STDERR->print("** Current Pivot Data **\n");
        STDERR->print(" Pivet Index: \"$LineInfo{$PIVOT_INDEX}\"\n");
        STDERR->print(" Pivot   Key: \"$LineInfo{$PIVOT_KEY}\"\n");
        STDERR->print(" Pivot Entry: \"$LineInfo{$PIVOT_ENTRY}\"\n");
        STDERR->print(" M Pivot Key: \"$LineInfo{$MASTER_PIVOT_KEY}\"\n");
        STDERR->print("** Record  Pivot Data **\n");
        STDERR->print(" Multi State: \"$LineInfo{$MULTIKEY_STATE}\"\n");
        STDERR->print("       MKey1: \"$LineInfo{$MKEY1}\"  MKey1 Data: \"$LineInfo{$MKEY_FIELD_DATA1}\"\n");
        STDERR->print("       MKey2: \"$LineInfo{$MKEY2}\"  MKey2 Data: \"$LineInfo{$MKEY_FIELD_DATA2}\"\n");
        STDERR->print("       MKey3: \"$LineInfo{$MKEY3}\"  MKey3 Data: \"$LineInfo{$MKEY_FIELD_DATA3}\"\n");
        STDERR->print("       MKey4: \"$LineInfo{$MKEY4}\"  MKey4 Data: \"$LineInfo{$MKEY_FIELD_DATA4}\"\n");
        STDERR->print("       MKey5: \"$LineInfo{$MKEY5}\"  MKey5 Data: \"$LineInfo{$MKEY_FIELD_DATA5}\"\n");
        STDERR->print("** Entry ID Count ******\n");
        STDERR->print("       Count: \"$LineInfo{$ENTRY_ID_COUNT}\"\n");
        STDERR->print("************************\n");
        STDERR->print(" Line Status: \"$LineInfo{$LINE_STATUS}\"\n");
        STDERR->print("************************\n");
    }else{
        STDERR->print("******** No Line      ********\n");
    }#else
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function PrintLineReport()\n");}
}#PrintLineReport()

############################################################################
# FUNCTION:     PrintNodeReport()
# PURPOSE:      To print the data of a PDB or DTD Node. 
# PARAMETERS:   $refCurrentElementNode  - [IN] A hash referene of a PDB or DTD Node.
#
# RETURN:       None.
############################################################################
sub PrintNodeReport{
    my $refCurrentElementNode =  0;
    my $NodeType              = "";
    my %CurrentElementNode    = [];
    my @CurrentChildNodeList  = ();
    my @CurrentAttributeList  = ();
    my $TmpAttribute          = "";

    ($refCurrentElementNode, $NodeType) = @_;
    %CurrentElementNode      = %{$refCurrentElementNode};

    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function PrintNodeReport()\n");}
    STDERR->print("\n******** $NodeType **********\n");
    my $tmp = $CurrentElementNode{$ref_MYNODE};
    STDERR->print("  Node Address: $tmp\n");
    $tmp = $CurrentElementNode{$ref_PARENTNODE};
    STDERR->print("P.Node Address: $tmp\n");
    STDERR->print("*********************\n");
    STDERR->print("   Element: $CurrentElementNode{$ELEMENT_NAME}\n");
    if (0 != @{$CurrentElementNode{$ref_ATTRIBUTE_LIST}}){
        @CurrentAttributeList = @{$CurrentElementNode{$ref_ATTRIBUTE_LIST}};
        foreach $TmpAttribute (@CurrentAttributeList) {
            STDERR->print("Attributes: $TmpAttribute\n");
        }#foreach
    }else{
        STDERR->print("Attributes: None\n");
    }#if
    if (0 != @{$CurrentElementNode{$ref_ATTRIBUTE_NAME_LIST}}){
        @CurrentAttributeList = @{$CurrentElementNode{$ref_ATTRIBUTE_NAME_LIST}};
        STDERR->print("Attributes Name: ");
        foreach $TmpAttribute (@CurrentAttributeList) {
            STDERR->print("\"$TmpAttribute\" ");
        }#foreach
        STDERR->print("\n");
    }else{
        STDERR->print("Attributes Name: None or Processed\n");
    }#else

    STDERR->print(" BEGIN_TAG: $CurrentElementNode{$BEGIN_TAG}\n");
    STDERR->print("    PCDATA: \"$CurrentElementNode{$PCDATA}\"\n");
    STDERR->print("   END_TAG: $CurrentElementNode{$END_TAG}\n");
    STDERR->print("  Category: $CurrentElementNode{$ELEMENT_CATEGORY}\n");
    if ($CurrentElementNode{$ELEMENT_CATEGORY} eq $ELEM_CAT_LIST){
        @CurrentChildNodeList = @{$CurrentElementNode{$ref_CHILDNODE_LIST}};
        PrintFormatList(80, "Child Elements: ", @CurrentChildNodeList);
    }#if
    if (grep(/^$NODE_VISIT_STATUS$/, keys %CurrentElementNode)){
        STDERR->print("   Visited: $CurrentElementNode{$NODE_VISIT_STATUS}\n");
        STDERR->print("    Status: $CurrentElementNode{$NODE_STATUS}\n");
    }#if
    STDERR->print("*********************\n");
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function PrintNodeReport()\n");}
}#PrintNodeReport()

############################################################################
# FUNCTION:     QuickStat()
# PURPOSE:      To print data of a line and PDB  Node. 
# PARAMETERS:   $refPDBNode  - [IN] A hash reference containing the Current PDB Node hash.
#               $refLineInfo - [IN] A hash reference containing a LineInfo hash.
#               $Msg         - [IN] Message.
# RETURN:       None.
############################################################################
sub QuickStat{

    my $refPDBNode            =  0;
    my $refLineInfo           =  0;
    my %PDBNode               =  0;
    my %LineInfo              = [];
    my $HeadMsg               = "";
    my $TailMsg               = "";
    my $StatusMsg             = "";

    ($refPDBNode, $refLineInfo, $HeadMsg, $TailMsg)  = @_;
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function QuickStat()\n");}
    %PDBNode= %{$refPDBNode};
    %LineInfo= %{$refLineInfo};
    my $RC = "";
    SWITCH: {
        if ($LineInfo{$RECORD_TYPE} eq $REC_SINGLE){
            $RC = "S";
            last SWITCH;
        }#if
        if ($LineInfo{$RECORD_TYPE} eq $REC_SINGLE_CONT){
            $RC = "SC";
            last SWITCH;
        }#if
        if ($LineInfo{$RECORD_TYPE} eq $REC_MULTIPLE){
            $RC = "M";
            last SWITCH;
        }#if
        if ($LineInfo{$RECORD_TYPE} eq $REC_MULTIPLE_CONT ){
            $RC = "MC";
            last SWITCH;
        }#if
        if ($LineInfo{$RECORD_TYPE} eq $REC_GROUP){
            $RC = "G";
            last SWITCH;
        }#if
        if ($LineInfo{$RECORD_TYPE} eq $REC_OTHER){
            $RC = "O";
            last SWITCH;
        }#if
    }#SWITCH
    my $ACT = "";
    SWITCH: {
        if ($LineInfo{$ACTION} eq $READ){
            $ACT = "READ";
            last SWITCH;
        }#if
        if ($LineInfo{$ACTION} eq $CONCAT){
            $ACT = "CONCAT";
            last SWITCH;
        }#if
        if ($LineInfo{$ACTION} eq $SEARCH){
            $ACT = "SEARCH";
            last SWITCH;
        }#if
        if ($LineInfo{$ACTION} eq $PARSE ){
            $ACT = "PARSE";
            last SWITCH;
        }#if
        if ($LineInfo{$ACTION} eq $PARSE_TO_MULTI_CHILDREN ){
            $ACT = "PARSE_TO_MULTI_CHILDREN";
            last SWITCH;
        }#if
        if ($LineInfo{$ACTION} eq $TOKEN){
            $ACT = "TOKEN";
            last SWITCH;
        }#if
        if ($LineInfo{$ACTION} eq $REC_OTHER){
            $ACT = "OTHER";
            last SWITCH;
        }#if

    }#SWITCH


    $StatusMsg = sprintf ("%-9s Rec: %-6s Type:%-2s Act:%-6s Stat:%-10s CPiv:%-5s MP:%-1s OnNode: %-5s %-10s %-5s %-7s\n", $HeadMsg,
                                                                               $LineInfo{$RECORD_NAME}, $RC, $ACT, $LineInfo{$LINE_STATUS},
                                                                               $LineInfo{$PIVOT_KEY}, $LineInfo{$MASTER_PIVOT_KEY},
                                                                               $PDBNode{$ELEMENT_NAME}, $PDBNode{$NODE_STATUS},
                                                                               $PDBNode{$NODE_VISIT_STATUS}, $TailMsg);
    STDERR->print  ($StatusMsg);
#    STDERR->print  ("##** Rec: $LineInfo{$RECORD_NAME} ");
#    STDERR->print  ("Type: $RC ");
#    STDERR->print  ("Action: $ACT ");
#    STDERR->print  ("Status: $LineInfo{$LINE_STATUS} ");
#    STDERR->print  ("CP: $LineInfo{$PIVOT_KEY} ");
#    STDERR->print  ("MP: $LineInfo{$MASTER_PIVOT_KEY} ");
#    STDERR->print  ("on Node: $PDBNode{$ELEMENT_NAME} ");
#    STDERR->print  (" $PDBNode{$NODE_STATUS} ");
#    STDERR->print  (" $PDBNode{$NODE_VISIT_STATUS}");
#    STDERR->print  (" $Msg\n");

    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function QuickStat()\n");}
}#QuickStat()

############################################################################
# FUNCTION:     PrintVersion()
# PURPOSE:      Prints Version information about PDBParser.
# PARAMETERS:   None.
# RETURN:       None.
############################################################################
sub PrintVersion{
    my $FormatStr = "";

    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function PrintVersion()\n");}
    $FormatStr = sprintf ("%-10s", $PDB_PARSER_VERSION);
    STDERR->print("****************************************************************************************\n");
    STDERR->print("***                       PDBParser                                                  ***\n");
    STDERR->print("***  Version:             $FormatStr                                                 ***\n");
    STDERR->print("***                                                                                  ***\n");
    STDERR->print("***  PDBParser will convert a Bioinformatics's PDB file format to xml format, based  ***\n");
    STDERR->print("***  on a supplied DTD.                                                              ***\n");
    STDERR->print("***                                                                                  ***\n");
    STDERR->print("***  Project: URI(tm) Universal Research Interchange Format                          ***\n");
    STDERR->print("***                                                                                  ***\n");
    STDERR->print("***  Legal:  Copyright (C) 2005, URI, Bioinformatics, CSC592                         ***\n");
    STDERR->print("***                                                                                  ***\n");
    STDERR->print("****************************************************************************************\n");
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function PrintVersion()\n");}
}#PrintVersion()

############################################################################
# FUNCTION:     GetFileName()
# PURPOSE:      To get an input file from the user. 
# PARAMETERS:   $FileName   - [IN]  Variable with the file extention type.
# RETURN:       Input file to be used.
############################################################################
sub GetFileName{
    my @TempFileList        = ();
    my @ValidResponses      = ();
    my $FileName            = "";
    my $FileType            = "";
    my $FriendlyFileName    = "";

    ($FileType) = @_;

    if ($bRunTimeDebug){STDERR->print("\nDEBUG: INFO: Entering function GetFileName()\n");}
    SWITCH: {
        if ($FileType eq $PDB_EXT){
            STDERR->print("\nThe name of a Bioinformatics's PDB input file will be needed.\n");
            $FriendlyFileName = "Bioinformatics PDB"; 
            last SWITCH;
        }#if
        if ($FileType eq $DTD_EXT){
            STDERR->print("\nThe name of a Bioinformatics's DTD input file will be needed.\n");
            $FriendlyFileName = "Bioinformatics DTD"; 
            last SWITCH;
        }#if
        default:{
            STDERR->print("\nAn internal error has occurred due to processing an unknown\n");
            STDERR->print("file extention type: $FileType\n");
            STDERR->print("\nPDBParser will exit.\n");
            exit(1);
            last SWITCH;
        }#default:
    }#SWITCH
    @ValidResponses  = ();
    STDERR->print("Here is a list of input files in the current directory.\n");
    opendir(DIR, cwd());
    @TempFileList = grep /\.$FileType$/, readdir DIR;
    @TempFileList = sort @TempFileList;
    closedir(DIR);
    if ( 0 < (scalar(@TempFileList))){
        PrintFormatList(80, "$FriendlyFileName ($FileType): ", @TempFileList);
        push @ValidResponses, @TempFileList;
    }else{
        PrintFormatList(80, "$FriendlyFileName ($FileType): ", ("No Files"));
    }#else
    @TempFileList = ();
    STDERR->print("\n");
    SWITCH: {
        if (3 > (scalar(@ValidResponses))){
            $FileName = GetUserResponse("Your response for the input file is invalid.\n", 0, 1, @ValidResponses);
            last SWITCH;
        }#if
        if (3 <= (scalar(@ValidResponses))){
            $FileName = GetUserResponse("Your response for the input file is invalid.\n", 0, 0, @ValidResponses);
            last SWITCH;
        }#if
    }#SWITCH
    if ($bRunTimeDebug){STDERR->print("\nDEBUG: INFO: Exiting function GetFileName()\n");}
    return($FileName);
}#GetFileName()

############################################################################
# FUNCTION:     GetUserResponse()
# PURPOSE:      To get an interactive response from the user.
# PARAMETERS:   $InvalidResponseStatement - [IN] A response statement for an
#                                                invalid user selection.
#               $DefaultResponseIndex     - [IN] An index into @ValidResponses
#                                                displayed as a default selection.
#               $bShowValidResponses      - [IN] Displays @ValidResponses on the prompt.
#               @ValidResponses           - [IN] List of valid user responses.
#
# REMARK:       If no valid response is provided, no integrity check will be 
#               performed and the User response will be returned.  If a valid
#               response list is provided an integrity check will be performed.  
#               If a valid response list is provided, the caller may choose to 
#               have the list displayed on the response prompt. If a valid response 
#               list is provided and the $DefaultResponseIndex is valid, a 
#               default Response will be display and the User may press return
#               to accept this response.  Note: If a $DefaultResponseIndex is 
#               valid, it will always be displayed, otherwise it is never displayed.
#
# RETURN:       The User's response.
############################################################################
sub GetUserResponse{
    my $UserResponse              = "";
    my $InvalidResponseStatement  = "";
    my @ValidResponses            = ();
    my $FormattedResponses        = "";
    my $nValidResponses           =  0;
    my $DefaultResponseIndex      =  0;
    my $DefaultResponse           = "";
    my $bShowValidResponses       =  0; # Must be FALSE.
    my $bShowResponsesOnPrompt    =  0; # Must be FALSE.
    my $bHaveValidDefaultResponse =  0; # Must be FALSE.
    my $bHaveValidResponses       =  0; # Must be FALSE.

    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function GetUserResponse()\n");}

    ($InvalidResponseStatement, $DefaultResponseIndex, $bShowValidResponses, @ValidResponses ) = @_;
 
    $nValidResponses = scalar(@ValidResponses); 
    if ( 1 <= $nValidResponses){
        $bHaveValidResponses = 1;
    }#if
    if ((0 <= $DefaultResponseIndex) && ($bHaveValidResponses) && ($DefaultResponseIndex <= ($nValidResponses - 1))){
        $bHaveValidDefaultResponse = 1;
        $DefaultResponse = @ValidResponses[$DefaultResponseIndex];
    }#if
    if ($bShowValidResponses == 1){
        $bShowResponsesOnPrompt = 1;
    }#if
    if ($bRunTimeDebug){
        PrintFormatList(80, "DEBUG INFO: ValidResponses ", @ValidResponses);
        STDERR->print("DEBUG INFO:nValidResponses: $nValidResponses\n");
        STDERR->print("DEBUG INFO:DefaultResponseIndex: $DefaultResponseIndex\n");
        STDERR->print("DEBUG INFO:bShowValidResponses: $bShowValidResponses\n");
        STDERR->print("DEBUG INFO:DefaultResponse: $DefaultResponse\n");
    }#if
    $FormattedResponses = join '|', @ValidResponses;
    SWITCH: {
        if ($bShowResponsesOnPrompt == 1 && $bHaveValidDefaultResponse == 1){
            STDERR->print("Please specify [$FormattedResponses]($DefaultResponse):");
            last SWITCH;
        }#if
        if ($bShowResponsesOnPrompt == 1 && $bHaveValidDefaultResponse == 0){
            STDERR->print("Please specify [$FormattedResponses]:");
            last SWITCH;
        }#if
        if ($bShowResponsesOnPrompt == 0 && $bHaveValidDefaultResponse == 1){
            STDERR->print("Please specify []($DefaultResponse):");
            last SWITCH;
        }#if
        if ($bShowResponsesOnPrompt == 0 && $bHaveValidDefaultResponse == 0){
            STDERR->print("Please specify []():");
            last SWITCH;
        }#if
    }#SWITCH
    if (STDIN->eof){
        STDERR->print("\nReceived EOF from STDIN, suspecting it is due to CTRL-C/CTRL-D, exiting PDB Parser.\n");
        exit;
    }#if
    $UserResponse = STDIN->getline;
    $UserResponse =~ s/\s+$//;
    if ($bHaveValidResponses == 1){
        while((!(grep /^$UserResponse$/, @ValidResponses)) && (!($UserResponse eq "" && $bHaveValidDefaultResponse))){
            PrintFormatList(100, "***ERROR - ", $InvalidResponseStatement);
            SWITCH: {
                if ($bShowResponsesOnPrompt == 1 && $bHaveValidDefaultResponse == 1){
                    STDERR->print("Please specify [$FormattedResponses]($DefaultResponse):");
                    last SWITCH;
                }#if
                if ($bShowResponsesOnPrompt == 1 && $bHaveValidDefaultResponse == 0){
                    STDERR->print("Please specify [$FormattedResponses]:");
                    last SWITCH;
                }#if
                if ($bShowResponsesOnPrompt == 0 && $bHaveValidDefaultResponse == 1){
                    STDERR->print("Please specify []($DefaultResponse):");
                    last SWITCH;
                }#if
                if ($bShowResponsesOnPrompt == 0 && $bHaveValidDefaultResponse == 0){
                    STDERR->print("Please specify []():");
                    last SWITCH;
                }#if
            }#SWITCH
            if (STDIN->eof){
                STDERR->print("\nReceived EOF for STDIN, suspecting it is due to CTRL-C/CTRL-D, exiting PDB Parser.\n");
                exit;
            }#if
            $UserResponse = STDIN->getline;
            $UserResponse =~ s/\s+$//;
        }#while
        if ($UserResponse eq "" && $bHaveValidDefaultResponse){
            $UserResponse = $DefaultResponse;
        }#if
    }# ($bHaveValidResponses == 1)
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function GetUserResponse()\n");}
    return($UserResponse);
}#GetUserResponse()

############################################################################
# FUNCTION:     BuildPrintableXMLFromPDBTree()
# PURPOSE:      Build a printable xml list from the PDB Instance tree.
# PARAMETERS:   $refPDBNode  - [IN] A hash reference containing the Current PDB Node hash.
#               
# RETURN:       TRUE for success, otherwise FALSE.
############################################################################
sub BuildPrintableXMLFromPDBTree{

    # Trees
    my $refPDBNode       =  0;
    my $LinePos          =  0;
    my %PDBNode          = [];
    # Current Line
    my $CurrentLine      =  0;
    my $TmpChildNode     = "";
    my @ChildNodeList    = ();
    my $i                =  0;
    my $FormatMsg        = "";

    ($refPDBNode, $LinePos) = @_;

    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function BuildPrintableXMLFromPDBTree()\n");}
    %PDBNode = %{$refPDBNode};

    if (($bRunTimeDebug eq 0) && ($bVerify eq 0) && 
        ($bLineProcess eq 0) &&  ($bQStat eq 0) &&
        ($bPrintXMLToScreen eq 0)){
            STDERR->print(".");
    }#if
    if ($PDBNode{$NODE_VISIT_STATUS} eq $VISIT_STATUS_BLACK){
        SWITCH: {
            if ($PDBNode{$ELEMENT_CATEGORY} eq $ELEM_CAT_ANY){
                SWITCH: {
                    if (0 != @{$PDBNode{$ref_CHILDNODE_LIST}}){
                        $PDBNode{$ELEMENT_CATEGORY} = $ELEM_CAT_LIST;
                        last SWITCH;
                    }#if
                    if($PDBNode{$PCDATA} ne ""){
                        $PDBNode{$ELEMENT_CATEGORY} = $ELEM_CAT_PND_PCDATA;
                        last SWITCH;
                    }#if
                    default:{
                        $PDBNode{$ELEMENT_CATEGORY} = $ELEM_CAT_EMPTY;
                        last SWITCH;
                    }#default
               }#SWITCH
            }#if
            if ($PDBNode{$ELEMENT_CATEGORY} eq $ELEM_CAT_EMPTY){
                for ($i = 1; $i <= $LinePos; $i++){
                    $FormatMsg = $FormatMsg . " ";
                }#for
                $FormatMsg = "${FormatMsg}${PDBNode{$BEGIN_TAG}}\n";
                push @g_PrintableXMLFile, $FormatMsg;
                if ($bPrintXMLToScreen){STDERR->print("$FormatMsg");}
               last SWITCH;
            }#if
            if ($PDBNode{$ELEMENT_CATEGORY} eq $ELEM_CAT_PND_PCDATA){
                for ($i = 1; $i <= $LinePos; $i++){
                    $FormatMsg = $FormatMsg . " ";
                }#for
                $FormatMsg = "${FormatMsg}${PDBNode{$BEGIN_TAG}}";
                $FormatMsg = "${FormatMsg}${PDBNode{$PCDATA}}${PDBNode{$END_TAG}}\n";
                push @g_PrintableXMLFile, $FormatMsg;
                if ($bPrintXMLToScreen){STDERR->print("$FormatMsg");}
               last SWITCH;
            }#if
            if ($PDBNode{$ELEMENT_CATEGORY} eq $ELEM_CAT_LIST){
                for ($i = 1; $i <= $LinePos; $i++){
                    $FormatMsg = $FormatMsg . " ";
                }#for
                $FormatMsg = "${FormatMsg}${PDBNode{$BEGIN_TAG}}\n";
                push @g_PrintableXMLFile, $FormatMsg;
                if ($bPrintXMLToScreen){STDERR->print("$FormatMsg");}
                @ChildNodeList = @{$PDBNode{$ref_CHILDNODE_LIST}};
                foreach $TmpChildNode (@ChildNodeList){
                    BuildPrintableXMLFromPDBTree($PDBNode{$TmpChildNode}, , $LinePos + $LINE_SPACE)
                }#foreach
                $FormatMsg = "";
                for ($i = 1; $i <= $LinePos; $i++){
                    $FormatMsg = $FormatMsg . " ";
                }#for
                $FormatMsg = "${FormatMsg}${PDBNode{$END_TAG}}\n";
                push @g_PrintableXMLFile, $FormatMsg;
                if ($bPrintXMLToScreen){STDERR->print("$FormatMsg");}
                last SWITCH;
            }#if
        }#SWITCH
    }#if
    %{$refPDBNode} = %PDBNode;
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function BuildPrintableXMLFromPDBTree()\n");}
    return(1);
}#BuildPrintableXMLFromPDBTree()

############################################################################
# FUNCTION:     PrintXMLFile()
# PURPOSE:      Print a pre formatted XML file.
# PARAMETERS:   None.
#               
# RETURN:       TRUE for success, otherwise FALSE.
############################################################################
sub PrintXMLFile{

    my $FileNameXML      = "";
    my $ReturnStatus     = "";
    my @returnStatusMsg  = ();

    ($FileNameXML) = @_;
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function PrintXMLFile()\n");}
    open(FILE,">$FileNameXML"); 
    #printing the xml version info and 
    print FILE '<?xml version="1.0" encoding="iso-8859-1"?>';
    print FILE "\n";
    #printing the path for DTD validation
    print FILE "<!DOCTYPE URI_protein SYSTEM \"$FileNameDTD\">";
    print FILE "\n";
    #printing the XML for the PDB tree
    print FILE "@g_PrintableXMLFile";
    close FILE;

    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting function PrintXMLFile()\n");}
    return ($ReturnStatus, @returnStatusMsg);
}#PrintXMLFile()

############################################################################
# FUNCTION:     PrintFormatList()
# PURPOSE:      To print out a list of string tokens (SPACE separated) onto
#               multiple lines with a given line length.
# PARAMETERS:   $UserMaxLineLenght - [IN] Variable to receive the suggested 
#                                         line lenght. This will be reset if
#                                         if greater than $MAX_LINE_LENGTH.
#               $UserHeader        - [IN] User header for each line printed
#                                         or Empty String for no header.
#               @List              - [IN] List of tokens to be printed. 
# RETURN:       None.
############################################################################
sub PrintFormatList{
    my $MAX_LINE_LENGTH   = 100;
    my $UserMaxLineLength =  0;
    my $LineHeader        = "";
    my @List              = ();
    my $LineHeaderLength  =  0;
    my $bNewLine          =  1;
    my $LineLength        =  0;
    my $Token             = "";
    my $TokenLength       =  0;

    ($UserMaxLineLength, $LineHeader, @List) = @_;

    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Entering function PrintFormatList()\n");}
    if ($bRunTimeDebug){STDERR->print("DEBUG INFO: Arg List:(\"$UserMaxLineLength\", \"$LineHeader\", \"@List\")\n");}
    $LineHeaderLength = length($LineHeader);
    if($UserMaxLineLength > $MAX_LINE_LENGTH){$UserMaxLineLength = $MAX_LINE_LENGTH;}
    if($LineHeaderLength <= $UserMaxLineLength){
        foreach $Token (@List){
            $TokenLength = length($Token);
	        if ($bNewLine == 1){
                $LineLength = $LineHeaderLength + $TokenLength;
                if($LineLength <= $UserMaxLineLength){
                    STDERR->print("\n$LineHeader$Token ");
                    $LineLength = $LineLength + 1;#Add Space
                    $bNewLine = 0;
                }else{
                    STDERR->print("\n$LineHeader");
                    $LineLength = $LineHeaderLength;
                    $bNewLine = 1;
                }#else
	        }else{
                $LineLength = $LineLength + $TokenLength;
                if( $LineLength <= $UserMaxLineLength){
                    STDERR->print("$Token ");
                    $LineLength = $LineLength + 1;#Add Space
                }else{
                    $LineLength = $LineHeaderLength + $TokenLength;
                    if($LineLength <= $UserMaxLineLength){
                        STDERR->print("\n$LineHeader$Token ");
                        $LineLength = $LineLength + 1;#Add Space
                        $bNewLine = 0;
                    }else{
                        STDERR->print("\n$LineHeader");
                        $LineLength = $LineHeaderLength;
                        $bNewLine = 1;
                    }#else
                }#else
            }#else
        }#foreach
    STDERR->print("\n");
    }#if
    if ($bRunTimeDebug){STDERR->print("\nDEBUG INFO: Exiting PrintFormatList()\n");}
}#PrintFormatList()

############################################################################
# FUNCTION:     PrintAllDTDGlobalList()
# PURPOSE:      Prints all the global list used to build the DTD Tree.
# PARAMETERS:   None.
#
# RETURN:       None.
############################################################################
sub PrintAllDTDGlobalList{

    STDERR->print("\nList of Elements.\n");
    PrintFormatList(80, "Elem: ", @g_ElementNameList);

    STDERR->print("\nList of Attributes.\n");
    PrintFormatList(80, "Attr: ", @g_AttributeNameList);
    STDERR->print("\nList of Entities.\n");
    PrintFormatList(80, "Attr: ", @g_EntityNameList);

    PrintFormatList(80, "Raw Element List: ", @g_ElementDeclarationList);
    my $tmpOutput = "";
    foreach $tmpOutput (@g_ElementDeclarationList){
        STDERR->print("Raw Element List: $tmpOutput\n");
    }#foreach
    STDERR->print("\nList of Attributes. @g_AttributeDeclarationList\n");
    STDERR->print("\nList of Attributes. @g_EntityDeclarationList\n");

}#PrintAllDTDGlobalList()

    ################################################################################################
    ###########                                End Of                                    ###########
    ###########                             Code Section                                 ###########
    ###########                          Interface Functions                             ###########
    ################################################################################################
