#!/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()       