MayaChemTools

   1 package FileIO::FingerprintsFPFileIO;
   2 #
   3 # $RCSfile: FingerprintsFPFileIO.pm,v $
   4 # $Date: 2015/02/28 20:48:43 $
   5 # $Revision: 1.19 $
   6 #
   7 # Author: Manish Sud <msud@san.rr.com>
   8 #
   9 # Copyright (C) 2015 Manish Sud. All rights reserved.
  10 #
  11 # This file is part of MayaChemTools.
  12 #
  13 # MayaChemTools is free software; you can redistribute it and/or modify it under
  14 # the terms of the GNU Lesser General Public License as published by the Free
  15 # Software Foundation; either version 3 of the License, or (at your option) any
  16 # later version.
  17 #
  18 # MayaChemTools is distributed in the hope that it will be useful, but without
  19 # any warranty; without even the implied warranty of merchantability of fitness
  20 # for a particular purpose.  See the GNU Lesser General Public License for more
  21 # details.
  22 #
  23 # You should have received a copy of the GNU Lesser General Public License
  24 # along with MayaChemTools; if not, see <http://www.gnu.org/licenses/> or
  25 # write to the Free Software Foundation Inc., 59 Temple Place, Suite 330,
  26 # Boston, MA, 02111-1307, USA.
  27 #
  28 
  29 use strict;
  30 use Carp;
  31 use Exporter;
  32 use Scalar::Util ();
  33 use TextUtil ();
  34 use FileUtil ();
  35 use TimeUtil ();
  36 use Fingerprints::FingerprintsStringUtil ();
  37 use PackageInfo ();
  38 use FileIO::FileIO;
  39 
  40 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  41 
  42 @ISA = qw(FileIO::FileIO Exporter);
  43 @EXPORT = qw();
  44 @EXPORT_OK = qw(IsFingerprintsFPFile);
  45 
  46 %EXPORT_TAGS = (all  => [@EXPORT, @EXPORT_OK]);
  47 
  48 # Setup class variables...
  49 my($ClassName);
  50 _InitializeClass();
  51 
  52 # Class constructor...
  53 sub new {
  54   my($Class, %NamesAndValues) = @_;
  55 
  56   # Initialize object...
  57   my $This = $Class->SUPER::new();
  58   bless $This, ref($Class) || $Class;
  59   $This->_InitializeFingerprintsFPFileIO();
  60 
  61   $This->_InitializeFingerprintsFPFileIOProperties(%NamesAndValues);
  62 
  63   return $This;
  64 }
  65 
  66 # Initialize object data...
  67 #
  68 sub _InitializeFingerprintsFPFileIO {
  69   my($This) = @_;
  70 
  71   # Fingerprints string data format during read/write...
  72   #
  73   # For file read:
  74   #
  75   # AutoDetect  - automatically detect format of fingerprints string
  76   # FingerprintsBitVectorString - Bit vector fingerprints string format
  77   # FingerprintsVectorString - Vector fingerprints string format
  78   #
  79   # Default value: AutoDetect
  80   #
  81   # For file write:
  82   #
  83   # FingerprintsBitVectorString - Bit vector fingerprints string format
  84   # FingerprintsVectorString - Vector fingerprints string format
  85   #
  86   # Default value: undef
  87   #
  88   $This->{FingerprintsStringMode} = undef;
  89 
  90   # For file read:
  91   #
  92   #   o Fingerprints bit-vector and vector object for current fingerprints string
  93   #
  94   # For file write:
  95   #
  96   #   o Fingerprints bit-vector and vector object for current fingerprints string
  97   #   o Any supported fingerprints object: PathLengthFingerprints, ExtendedConnectivity, and so on.
  98   #
  99   $This->{FingerprintsObject} = undef;
 100 
 101   # Fingeprints string for current line during read/write...
 102   $This->{FingerprintsString} = undef;
 103 
 104   # Partial fingeprints string corresponding to what's on the current line for current
 105   # line during read/write...
 106   $This->{PartialFingerprintsString} = undef;
 107 
 108   # Required header data keys and values during read/write...
 109   @{$This->{RequiredHeaderDataKeys}} = ();
 110   %{$This->{RequiredHeaderDataKeysAndValues}} = ();
 111 
 112   # First data line read/write...
 113   $This->{FirstDataLineIO} = 1;
 114 
 115   # Current fingerprints string data line number during read/write...
 116   $This->{LineNum} = 0;
 117 
 118   # FP line data during read/write...
 119   $This->{DataLine} = undef;
 120 
 121   # Initialize parameters for read...
 122   $This->_InitializeFingerprintsFPFileIORead();
 123 
 124   # Initialize parameters for write...
 125   $This->_InitializeFingerprintsFPFileIOWrite();
 126 
 127   return $This;
 128 }
 129 
 130 # Initialize class ...
 131 sub _InitializeClass {
 132   #Class name...
 133   $ClassName = __PACKAGE__;
 134 
 135 }
 136 
 137 # Initialize object data for reading fingerprints FP file...
 138 #
 139 sub _InitializeFingerprintsFPFileIORead {
 140   my($This) = @_;
 141 
 142   # Header data keys and values...
 143   #
 144   @{$This->{HeaderDataKeys}} = ();
 145   %{$This->{HeaderDataKeysAndValues}} = ();
 146   %{$This->{CannonicalHeaderDataKeysAndValues}} = ();
 147 
 148   # By default, the fingerprints data is assumed to be valid and no validation is
 149   # performed before generating fingerprints objects...
 150   #
 151   $This->{ValidateData} = 1;
 152 
 153   # Level of detail to print during validation of data for invalid or missing data...
 154   $This->{DetailLevel} = 1;
 155 
 156   # Number of missing and invalid fingerprints string data lines...
 157   $This->{NumOfLinesWithMissingData} = 0;
 158   $This->{NumOfLinesWithInvalidData} = 0;
 159 
 160   # Compound ID for current fingerprints string...
 161   $This->{CompoundID} = undef;
 162 
 163   # Status of data in fingerprints FP file...
 164   $This->{ValidFileData} = 0;
 165   $This->{ValidRequiredHeaderDataKeys} = 0;
 166   $This->{ValidFingerprintsStringMode} = 0;
 167 
 168   return $This;
 169 }
 170 
 171 # Initialize object data for writing fingerprints FP file...
 172 #
 173 sub _InitializeFingerprintsFPFileIOWrite {
 174   my($This) = @_;
 175 
 176   # Fingerprints bit vector string format...
 177   #
 178   # Possible values: BinaryString or HexadecimalString [Default]
 179   #
 180   # Default BitStringFormat is set during first write using Fingerprints::FingerprintsStringUtil::GetDefaultBitStringFormat.
 181   #
 182   $This->{BitStringFormat} = undef;
 183 
 184   # Bits order in fingerprints bit vector string...
 185   #
 186   # Ascending - First bit in each byte as the lowest bit [Default]
 187   # Descending - First bit in each byte as the highest bit
 188   #
 189   # Default BitsOrder is set during first write using Fingerprints::FingerprintsStringUtil::GetDefaultBitsOrder.
 190   #
 191   $This->{BitsOrder} = undef;
 192 
 193   # Fingerprints vector string format...
 194   #
 195   # Possible values: IDsAndValuesString, IDsAndValuesPairsString, ValuesAndIDsString, ValuesAndIDsPairsString, ValuesString
 196   #
 197   # Default VectorStringFormat is set during first write using Fingerprints::FingerprintsStringUtil::GetDefaultVectorStringFormat.
 198   # For fingerprints vector object containing vector NumericalValues, it corresponds to IDsAndValuesString; otherwise,
 199   # it's set to ValuesString.
 200   #
 201   $This->{VectorStringFormat} = undef;
 202 
 203   # Overwriting existing file...
 204   $This->{Overwrite} = 0;
 205 
 206   return $This;
 207 }
 208 
 209 # Initialize object values...
 210 sub _InitializeFingerprintsFPFileIOProperties {
 211   my($This, %NamesAndValues) = @_;
 212 
 213   # All other property names and values along with all Set/Get<PropertyName> methods
 214   # are implemented on-demand using ObjectProperty class.
 215 
 216   my($Name, $Value, $MethodName);
 217   while (($Name, $Value) = each  %NamesAndValues) {
 218     $MethodName = "Set${Name}";
 219     $This->$MethodName($Value);
 220   }
 221 
 222   if (!exists $NamesAndValues{Name}) {
 223     croak "Error: ${ClassName}->New: Object can't be instantiated without specifying file name...";
 224   }
 225 
 226   # Make sure it's a fingerprints file...
 227   $Name = $NamesAndValues{Name};
 228   if (!$This->IsFingerprintsFPFile($Name)) {
 229     croak "Error: ${ClassName}->New: Object can't be instantiated: File, $Name, doesn't appear to be fingerprints format...";
 230   }
 231 
 232   if ($This->GetMode() =~ /^Read$/i) {
 233     $This->_InitializeFingerprintsFPFileIOReadProperties(%NamesAndValues);
 234   }
 235   elsif ($This->GetMode() =~ /^(Write|Append)$/i) {
 236     $This->_InitializeFingerprintsFPFileIOWriteProperties(%NamesAndValues);
 237   }
 238 
 239   return $This;
 240 }
 241 
 242 # Initialize object properties for reading fingerprints FP file...
 243 #
 244 sub _InitializeFingerprintsFPFileIOReadProperties {
 245   my($This, %NamesAndValues) = @_;
 246 
 247   # Set default value for FingerprintsStringMode...
 248   if (!$This->{FingerprintsStringMode}) {
 249     $This->{FingerprintsStringMode} = 'AutoDetect';
 250   }
 251 
 252   $This->_PrepareForReadingFingerprintsFPFileData();
 253 
 254   return $This;
 255 }
 256 
 257 # Initialize object properties for writing fingerprints FP file...
 258 #
 259 sub _InitializeFingerprintsFPFileIOWriteProperties {
 260   my($This, %NamesAndValues) = @_;
 261 
 262   # Check FingerprintsStringMode value...
 263   if (!exists $NamesAndValues{FingerprintsStringMode}) {
 264     croak "Error: ${ClassName}->New: Object can't be instantiated without specifying FingerprintsStringMode...";
 265   }
 266 
 267   if ($This->{FingerprintsStringMode} !~ /^(FingerprintsBitVectorString|FingerprintsVectorString)$/i) {
 268     croak "Error: ${ClassName}->New: Object can't be instantiated: FingerprintsStringMode value, $This->{FingerprintsStringMode}, is not valid; Supported values for write/append: FingerprintsBitVectorString or FingerprintsVectorString...";
 269   }
 270 
 271   $This->_PrepareForWritingFingerprintsFPFileData();
 272 
 273   return $This;
 274 }
 275 
 276 # Set FingerprintsStringMode...
 277 #
 278 sub SetFingerprintsStringMode {
 279   my($This, $Value) = @_;
 280 
 281   # AutoDetect - automatically detect format of fingerprints string
 282   # FingerprintsBitVectorString - Bit vector fingerprints string format
 283   # FingerprintsVectorString - Vector fingerprints string format
 284 
 285   if ($Value !~ /^(AutoDetect|FingerprintsBitVectorString|FingerprintsVectorString)$/i) {
 286     croak "Error: ${ClassName}->SetFingerprintsStringMode: FingerprintsStringMode value, $Value, is not valid; Supported values: AutoDetect, FingerprintsBitVectorString or FingerprintsVectorString...";
 287   }
 288 
 289   $This->{FingerprintsStringMode} = $Value;
 290 
 291   return $This;
 292 }
 293 
 294 # Set DetailLevel...
 295 #
 296 sub SetDetailLevel {
 297   my($This, $Value) = @_;
 298 
 299   if (!TextUtil::IsPositiveInteger($Value)) {
 300     croak "Error: ${ClassName}->SetDetailLevel: DetailLevel value, $Value, is not valid; Supported values: > 0...";
 301   }
 302 
 303   $This->{DetailLevel} = $Value;
 304 
 305   return $This;
 306 }
 307 
 308 # Set BitStringFormat...
 309 #
 310 sub SetBitStringFormat {
 311   my($This, $Value) = @_;
 312 
 313   if ($Value !~ /^(BinaryString|HexadecimalString)$/i) {
 314     croak "Error: ${ClassName}->SetBitStringFormat: BitStringFormat value, $Value, is not valid; Supported values: BinaryString or HexadecimalString...";
 315   }
 316 
 317   $This->{BitStringFormat} = $Value;
 318 
 319   return $This;
 320 }
 321 
 322 # Set BitsOrder...
 323 #
 324 sub SetBitsOrder {
 325   my($This, $Value) = @_;
 326 
 327   # Ascending - First bit in each byte as the lowest bit
 328   # Descending - First bit in each byte as the highest bit
 329   #
 330   if ($Value !~ /^(Ascending|Descending)$/i) {
 331     croak "Error: ${ClassName}->SetBitsOrder: FingerprintsStringMode value, $Value, is not valid; Supported values: Ascending or Descending...";
 332   }
 333 
 334   $This->{BitsOrder} = $Value;
 335 
 336   return $This;
 337 }
 338 
 339 # Set compound ID...
 340 #
 341 sub SetCompoundID {
 342   my($This, $Value) = @_;
 343 
 344   if ($Value =~ / /) {
 345     $Value =~ s/ //g;
 346     carp "Warning: ${ClassName}->SetCompoundID: Spaces are not allowed in compound ID; They have been removed...";
 347   }
 348 
 349   $This->{CompoundID} = $Value;
 350 
 351   return $This;
 352 }
 353 
 354 # Set VectorStringFormat...
 355 #
 356 sub SetVectorStringFormat {
 357   my($This, $Value) = @_;
 358 
 359   # Possible values: IDsAndValuesString, IDsAndValuesPairsString, ValuesAndIDsString, ValuesAndIDsPairsString
 360 
 361   if ($Value !~ /^(IDsAndValuesString|IDsAndValuesPairsString|ValuesAndIDsString|ValuesAndIDsPairsString|ValuesString)$/i) {
 362     croak "Error: ${ClassName}->SetVectorStringFormat: FingerprintsStringMode value, $Value, is not valid; Supported values: IDsAndValuesString, IDsAndValuesPairsString, ValuesAndIDsString, ValuesAndIDsPairsString, or ValuesString...";
 363   }
 364 
 365   $This->{VectorStringFormat} = $Value;
 366 
 367   return $This;
 368 }
 369 
 370 # Get header data keys or number of header data keys in header data block...
 371 #
 372 sub GetHeaderDataKeys {
 373   my($This) = @_;
 374 
 375   return wantarray ? @{$This->{HeaderDataKeys}} : scalar @{$This->{HeaderDataKeys}};
 376 }
 377 
 378 # Set header data keys...
 379 #
 380 sub SetHeaderDataKeys {
 381   my($This, @Keys) = @_;
 382 
 383   croak "Error: ${ClassName}->SetHeaderDataKeys: Can't set HeaderDataKeys: Not allowed...";
 384 
 385   return $This;
 386 }
 387 
 388 # Get header data keys and values hash...
 389 #
 390 sub GetHeaderDataKeysAndValues {
 391   my($This) = @_;
 392 
 393   return %{$This->{HeaderDataKeysAndValues}};
 394 }
 395 
 396 # Set header data keys and values hash...
 397 #
 398 sub SetHeaderDataKeysAndValues {
 399   my($This, %KeysAndValues) = @_;
 400 
 401   croak "Error: ${ClassName}->SetHeaderDataKeysAndValues: Can't set HeaderDataKeysAndValues: Not allowed...";
 402 
 403   return $This;
 404 }
 405 
 406 # Get required header data keys or number of header data keys in header data block...
 407 #
 408 sub GetRequiredHeaderDataKeys {
 409   my($This) = @_;
 410 
 411   return wantarray ? @{$This->{RequiredHeaderDataKeys}} : scalar @{$This->{RequiredHeaderDataKeys}};
 412 }
 413 
 414 # Set required header data keys...
 415 #
 416 sub SetRequiredHeaderDataKeys {
 417   my($This, @Keys) = @_;
 418 
 419   croak "Error: ${ClassName}->SetRequiredHeaderDataKeys: Can't set RequiredHeaderDataKeys: Not allowed...";
 420 
 421   return $This;
 422 }
 423 
 424 # Get required header data keys and values hash...
 425 #
 426 sub GetRequiredHeaderDataKeysAndValues {
 427   my($This) = @_;
 428 
 429   return %{$This->{RequiredHeaderDataKeysAndValues}};
 430 }
 431 
 432 # Set required header data keys and values hash...
 433 #
 434 sub SetRequiredHeaderDataKeysAndValues {
 435   my($This, %KeysAndValues) = @_;
 436 
 437   croak "Error: ${ClassName}->SetRequiredHeaderDataKeysAndValues: Can't set RequiredHeaderDataKeysAndValues: Not allowed...";
 438 
 439   return $This;
 440 }
 441 
 442 # Get fingerprints object for current data line...
 443 #
 444 sub GetFingerprints {
 445   my($This) = @_;
 446 
 447   return $This->{FingerprintsObject};
 448 }
 449 
 450 # Set fingerprints object for current data line...
 451 #
 452 sub SetFingerprints {
 453   my($This, $FingerprintsObject) = @_;
 454 
 455   $This->{FingerprintsObject} = $FingerprintsObject;
 456 
 457   return $This;
 458 }
 459 
 460 # Get fingerprints string  for current data line...
 461 #
 462 sub GetFingerprintsString {
 463   my($This) = @_;
 464 
 465   return $This->{FingerprintsString} ? $This->{FingerprintsString} : 'None';
 466 }
 467 
 468 # Set fingerprints string for current data line...
 469 #
 470 sub SetFingerprintsString {
 471   my($This, $FingerprintsString) = @_;
 472 
 473   $This->{FingerprintsString} = $FingerprintsString;
 474 
 475   return $This;
 476 }
 477 
 478 # Get partial fingerprints string  for current data line...
 479 #
 480 sub GetPartialFingerprintsString {
 481   my($This) = @_;
 482 
 483   return $This->{PartialFingerprintsString} ? $This->{PartialFingerprintsString} : 'None';
 484 }
 485 
 486 # Set partial fingerprints string for current data line...
 487 #
 488 sub SetPartialFingerprintsString {
 489   my($This, $PartialFingerprintsString) = @_;
 490 
 491   $This->{PartialFingerprintsString} = $PartialFingerprintsString;
 492 
 493   return $This;
 494 }
 495 
 496 # Does fingerprints FP file contain valid data?
 497 #
 498 sub IsFingerprintsFileDataValid {
 499   my($This) = @_;
 500 
 501   return $This->{ValidFileData} ? 1 : 0;
 502 }
 503 
 504 # Does current data line contains valid fingerprints object data?
 505 #
 506 sub IsFingerprintsDataValid {
 507   my($This) = @_;
 508 
 509   return defined $This->{FingerprintsObject} ? 1 : 0;
 510 }
 511 
 512 # Check presence of a header data key...
 513 #
 514 sub IsHeaderDataKeyPresent {
 515   my($This, $Key) = @_;
 516   my($CannonicalKey);
 517 
 518   $CannonicalKey = lc $Key;
 519 
 520   return exists $This->{CannonicalHeaderDataKeysAndValues}{$CannonicalKey} ? 1 : 0;
 521 }
 522 
 523 # Get value of header data key...
 524 #
 525 sub GetHeaderDataKeyValue {
 526   my($This, $Key) = @_;
 527   my($CannonicalKey);
 528 
 529   $CannonicalKey = lc $Key;
 530 
 531   return exists $This->{CannonicalHeaderDataKeysAndValues}{$CannonicalKey} ?  $This->{CannonicalHeaderDataKeysAndValues}{$CannonicalKey} : undef;
 532 }
 533 
 534 #
 535 # Read next available fingerprints line, process it and generate appropriate fingerprints
 536 # objects...
 537 #
 538 sub Read {
 539   my($This) = @_;
 540 
 541   # Read data line...
 542   if (!$This->_ReadDataLine()) {
 543     return undef;
 544   }
 545 
 546   # No need to process invalid FP file with invalid data...
 547   if (!$This->{ValidFileData}) {
 548     if ($This->{ValidateData}) {
 549       $This->{NumOfLinesWithMissingData} += 1;
 550     }
 551     return $This;
 552   }
 553 
 554   # Perform data validation...
 555   if ($This->{ValidateData}) {
 556     if (!$This->_ValidateReadDataLine()) {
 557       return $This;
 558     }
 559   }
 560 
 561   # Check again to handle problematic data for non-validated data lines...
 562   if (!$This->{FingerprintsString}) {
 563     return $This;
 564   }
 565 
 566   # Generate fingeprints object...
 567   $This->_GenerateFingerprintsObject();
 568 
 569   # Setup fingerprints compound ID for fingerprints string...
 570   $This->_GenerateCompoundID();
 571 
 572   return $This;
 573 }
 574 
 575 # Read next available fingerprints line, process it and generate appropriate fingerprints
 576 # objects...
 577 #
 578 sub Next {
 579   my($This) = @_;
 580 
 581   return $This->Read();
 582 }
 583 
 584 # Read fingerprints data line line...
 585 #
 586 sub _ReadDataLine {
 587   my($This) = @_;
 588 
 589   # Initialize data for current line...
 590   $This->_InitializeReadDataLine();
 591 
 592   if ($This->{FirstDataLineIO}) {
 593     # Get first data line...
 594     $This->_ProcessFirstDataLineRead();
 595   }
 596   else {
 597     # Get next data line...
 598     $This->{LineNum} += 1;
 599     $This->{DataLine} = TextUtil::GetTextLine($This->{FileHandle});
 600   }
 601 
 602   # Is it end of file?
 603   if (!$This->{DataLine}) {
 604     return 0;
 605   }
 606 
 607   # Process data line to retrieve compound ID and fingerprints string information...
 608   $This->_ProcessDataLineRead();
 609 
 610   return 1;
 611 }
 612 
 613 # Process data line to retrieve compound ID and fingerprints string information...
 614 #
 615 sub _ProcessDataLineRead {
 616   my($This) = @_;
 617   my($CompoundID, $PartialFingerprintsString);
 618 
 619   ($CompoundID, $PartialFingerprintsString) = $This->{DataLine} =~ /^(.*?)[ ]+(.*?)$/;
 620 
 621   if (!(defined($CompoundID) && defined($PartialFingerprintsString))) {
 622     return $This;
 623   }
 624 
 625   $This->{CompoundID} = $CompoundID;
 626   $This->{PartialFingerprintsString} = $PartialFingerprintsString;
 627 
 628   # Set up fingerprints string...
 629   $This->_GenerateFingerprintsStringFromPartialFingerprintsString();
 630 
 631   return $This;
 632 }
 633 
 634 # Initialize data line for reading...
 635 #
 636 sub _InitializeReadDataLine {
 637   my($This) = @_;
 638 
 639   $This->{CompoundID} = undef;
 640   $This->{DataLine} = undef;
 641 
 642   $This->{FingerprintsObject} = undef;
 643 
 644   $This->{FingerprintsString} = undef;
 645   $This->{PartialFingerprintsString} = undef;
 646 
 647   return $This;
 648 }
 649 
 650 # Validate fingerprints string data line...
 651 #
 652 sub _ValidateReadDataLine {
 653   my($This) = @_;
 654 
 655   # Check for missing data...
 656   if (!($This->{CompoundID} && $This->{PartialFingerprintsString})) {
 657     # Missing data...
 658     $This->{NumOfLinesWithMissingData} += 1;
 659     if ($This->{DetailLevel} >= 3) {
 660       carp "Warning: ${ClassName}->_ValidateReadDataLine: Data line number $This->{LineNum} contains no fingerprints data: $This->{DataLine}...";
 661     }
 662     elsif ($This->{DetailLevel} >= 2) {
 663       carp "Warning: ${ClassName}->_ValidateReadDataLine: Data line number $This->{LineNum} contains no fingerprints data...";
 664     }
 665     return 0;
 666   }
 667 
 668   # Check for invalid data...
 669   my($InvalidFingerprintsData);
 670 
 671   $InvalidFingerprintsData = 0;
 672   if ($This->{FingerprintsString}) {
 673     $InvalidFingerprintsData = Fingerprints::FingerprintsStringUtil::AreFingerprintsStringValuesValid($This->{FingerprintsString}) ? 0 : 1;
 674   }
 675   else {
 676     $InvalidFingerprintsData = 1;
 677   }
 678 
 679   if ($InvalidFingerprintsData) {
 680     $This->{NumOfLinesWithInvalidData} += 1;
 681     if ($This->{DetailLevel} >= 3) {
 682       carp "Warning: ${ClassName}->_ValidateReadDataLine: Data line number $This->{LineNum} contains invalid fingerprints data: $This->{DataLine}...";
 683     }
 684     elsif ($This->{DetailLevel} >= 2) {
 685       carp "Warning: ${ClassName}->_ValidateReadDataLine: Data line number $This->{LineNum} contains invalid fingerprints data...";
 686     }
 687     return 0;
 688   }
 689 
 690   return 1;
 691 }
 692 
 693 # Setup fingerprints compound ID for fingerprints string...
 694 sub _GenerateCompoundID {
 695   my($This) = @_;
 696 
 697   # Set fingerprints ID...
 698   if ($This->{FingerprintsObject}) {
 699     $This->{FingerprintsObject}->SetID($This->{CompoundID});
 700   }
 701 
 702   return $This;
 703 }
 704 
 705 # Process first read...
 706 #
 707 sub _ProcessFirstDataLineRead {
 708   my($This) = @_;
 709   my($Line);
 710 
 711   $This->{FirstDataLineIO} = 0;
 712 
 713   # Skip over header data lines and collect first data line...
 714 
 715   LINE: while ($Line = TextUtil::GetTextLine($This->{FileHandle})) {
 716     $This->{LineNum} += 1;
 717 
 718     # Is it a header data line?
 719     if ($Line =~ /^#/) {
 720       next LINE;
 721     }
 722     $This->{DataLine} = $Line;
 723     last LINE;
 724   }
 725 
 726   return $This;
 727 }
 728 
 729 # Get ready for reading fingerprints FP file...
 730 #
 731 sub _PrepareForReadingFingerprintsFPFileData {
 732   my($This) = @_;
 733 
 734   # Retrieve FP file data headers information....
 735   $This->_RetrieveFPFileDataHeaders();
 736 
 737   # Validate header data keys and values information...
 738   $This->_ValidateReadHeaderDataKeysAndValues();
 739 
 740   # Validate fingeprints string mode information...
 741   if ($This->{ValidRequiredHeaderDataKeys}) {
 742     $This->_ValidateReadFingerprintsStringMode();
 743   }
 744 
 745   # Set status of FP file data...
 746   $This->{ValidFileData} = ($This->{ValidRequiredHeaderDataKeys} && $This->{ValidFingerprintsStringMode}) ? 1 : 0;
 747 
 748   return $This;
 749 }
 750 
 751 # Retrieve information about fingerprints date header in FP file...
 752 #
 753 sub _RetrieveFPFileDataHeaders {
 754   my($This) = @_;
 755   my($FPFile, $Line, $Index, $KeyValuePair, $Key, $Value, $KeyValueDelimiter, $KeyValuePairDelimiter, @LineKeyValuePairs);
 756 
 757   $FPFile = $This->{Name};
 758 
 759   if (!(-e $FPFile)) {
 760     croak "Error: ${ClassName}->_RetrieveFPFileDataHeaders: File, $FPFile, doesn't exist...";
 761   }
 762 
 763   if (!open FPFILE, "$FPFile") {
 764     croak "Error: ${ClassName}->_RetrieveFPFileDataHeaders: Couldn't open input FP file $FPFile: $! ...";
 765   }
 766 
 767   # Process header key/value pair data...
 768   #
 769   $KeyValueDelimiter = '=';
 770   $KeyValuePairDelimiter = ';';
 771 
 772   @{$This->{HeaderDataKeys}} = ();
 773   %{$This->{HeaderDataKeysAndValues}} = ();
 774   %{$This->{CannonicalHeaderDataKeysAndValues}} = ();
 775 
 776   LINE: while ($Line = TextUtil::GetTextLine(\*FPFILE)) {
 777     # Is it a key/value pairs line?
 778     if ($Line !~ /^#/) {
 779       last LINE;
 780     }
 781 
 782     # Take out starting hash mark before processing key/value pairs...
 783     $Line =~ s/^#//;
 784     if (TextUtil::IsEmpty($Line)) {
 785       next LINE;
 786     }
 787 
 788     @LineKeyValuePairs = ();
 789 
 790     for $KeyValuePair (split "$KeyValuePairDelimiter", $Line) {
 791       ($Key, $Value) = split "$KeyValueDelimiter", $KeyValuePair;
 792 
 793       $Key = defined($Key) ? TextUtil::RemoveLeadingAndTrailingWhiteSpaces($Key) : '';
 794       $Value = defined($Value) ? TextUtil::RemoveLeadingAndTrailingWhiteSpaces($Value) : '';
 795 
 796       if (TextUtil::IsEmpty($Key) || TextUtil::IsEmpty($Value)) {
 797         carp "Warning: ${ClassName}->_RetrieveFPFileDataHeaders: Data header line containing \"Key = Value\" pairs is not valid: It must contain even number of \"Key = Value\" pairs with valid values. Ignoring data header line: \"$Line\"...";
 798         next LINE;
 799       }
 800       push @{$This->{HeaderDataKeys}}, $Key;
 801       push @LineKeyValuePairs, ($Key, $Value);
 802     }
 803 
 804     for ($Index = 0; $Index < $#LineKeyValuePairs; $Index += 2) {
 805       $Key = $LineKeyValuePairs[$Index]; $Value = $LineKeyValuePairs[$Index + 1];
 806 
 807       $This->{HeaderDataKeysAndValues}{$Key} = $Value;
 808       $This->{CannonicalHeaderDataKeysAndValues}{lc($Key)} = $Value;
 809     }
 810   }
 811   close FPFILE;
 812 
 813   return $This;
 814 }
 815 
 816 # Validate header data and keys...
 817 #
 818 sub _ValidateReadHeaderDataKeysAndValues {
 819   my($This) = @_;
 820   my($FingerprintsStringType, $Key, $Value, @RequiredHeaderDataKeys);
 821 
 822   $This->{ValidRequiredHeaderDataKeys} = 0;
 823   @{$This->{RequiredHeaderDataKeys}} = ();
 824 
 825   # Is FingerprintsStringType key is present?
 826   if (!$This->IsHeaderDataKeyPresent('FingerprintsStringType')) {
 827     carp "carp: ${ClassName}->_ValidateReadHeaderDataKeysAndValues: FingerprintsStringType data header key is missing in fingerprints file...";
 828     return 0;
 829   }
 830   $FingerprintsStringType = $This->GetHeaderDataKeyValue('FingerprintsStringType');
 831 
 832   # Are all required data header keys present?
 833   #
 834   @RequiredHeaderDataKeys = ();
 835 
 836   if ($FingerprintsStringType =~ /^(FingerprintsBitVector|FingerprintsVector)$/i) {
 837     push @RequiredHeaderDataKeys, $This->_GetRequiredHeaderDataKeys($FingerprintsStringType);
 838   }
 839   else {
 840     carp "Warning: ${ClassName}->_ValidateReadHeaderDataKeysAndValues: FingerprintsStringType data header key value, $FingerprintsStringType, is not valid. SUpported values: FingerprintsBitVector or FingerprintsVector...";
 841     return 0;
 842   }
 843 
 844   for $Key (@RequiredHeaderDataKeys) {
 845     if (!$This->IsHeaderDataKeyPresent($Key)) {
 846       croak "Error: ${ClassName}->_ValidateReadHeaderDataKeysAndValues: Requires data header key, $Key, is missing in fingerprints file...";
 847     }
 848   }
 849 
 850   push @{$This->{RequiredHeaderDataKeys}}, @RequiredHeaderDataKeys;
 851 
 852   # Are all required data header key values valid?
 853   #
 854   if (!$This->_ValidateRequiredHeaderDataKeyValues()) {
 855     return 0;
 856   }
 857 
 858   # Process required header key values...
 859   #
 860   $This->_ProcessRequiredHeaderDataKeyValues();
 861 
 862   $This->{ValidRequiredHeaderDataKeys} = 1;
 863 
 864   return 1;
 865 }
 866 
 867 # Validate data header key values....
 868 #
 869 sub _ValidateRequiredHeaderDataKeyValues {
 870   my($This) = @_;
 871   my($Key, $Value);
 872 
 873   for $Key (@{$This->{RequiredHeaderDataKeys}}) {
 874     $Value = $This->GetHeaderDataKeyValue($Key);
 875     KEY: {
 876       if ($Key =~ /^FingerprintsStringType$/i) {
 877         if ($Value !~ /^(FingerprintsBitVector|FingerprintsVector)$/i) {
 878           carp "Warning: ${ClassName}->_ValidateRequiredHeaderDataKeyValues: Required $Key data header key value, $Value, is not valid. Supported values: FingerprintsBitVector or FingerprintsVector...";
 879           return 0;
 880         }
 881         last KEY;
 882       }
 883       if ($Key =~ /^Size$/i) {
 884         if (!TextUtil::IsPositiveInteger($Value)) {
 885           carp "Warning: ${ClassName}->_ValidateRequiredHeaderDataKeyValues: Required $Key data header key value, $Value, is not valid. Supported values: > 0...";
 886           return 0;
 887         }
 888         last KEY;
 889       }
 890       if ($Key =~ /^BitStringFormat$/i) {
 891         if ($Value !~ /^(BinaryString|HexadecimalString)$/i) {
 892           carp "Warning: ${ClassName}->_ValidateRequiredHeaderDataKeyValues: Required $Key data header key value, $Value, is not valid. Supported values: BinaryString or HexadecimalString ...";
 893           return 0;
 894         }
 895         last KEY;
 896       }
 897       if ($Key =~ /^BitsOrder$/i) {
 898         if ($Value !~ /^(Ascending|Descending)$/i) {
 899           carp "Warning: ${ClassName}->_ValidateRequiredHeaderDataKeyValues: Required $Key data header key value, $Value, is not valid. Supported values: Ascending or Descending...";
 900           return 0;
 901         }
 902         last KEY;
 903       }
 904       if ($Key =~ /^VectorStringFormat$/i) {
 905         if ($Value !~ /^(IDsAndValuesString|IDsAndValuesPairsString|ValuesAndIDsString|ValuesAndIDsPairsString|ValuesString)$/i) {
 906           carp "Warning: ${ClassName}->_ValidateRequiredHeaderDataKeyValues: Required $Key data header key value, $Value, is not valid. Supported values: IDsAndValuesString, IDsAndValuesPairsString, ValuesAndIDsString, ValuesAndIDsPairsString, or ValuesString ...";
 907           return 0;
 908         }
 909         last KEY;
 910       }
 911       if ($Key =~ /^VectorValuesType$/i) {
 912         if ($Value !~ /^(OrderedNumericalValues|NumericalValues|AlphaNumericalValues)$/i) {
 913           carp "Warning: ${ClassName}->_ValidateRequiredHeaderDataKeyValues: Required $Key data header key value, $Value, is not valid. Supported values: OrderedNumericalValues, NumericalValues or AlphaNumericalValues...";
 914           return 0;
 915         }
 916         last KEY;
 917       }
 918       if ($Key =~ /^Description$/i) {
 919         if (TextUtil::IsEmpty($Value)) {
 920           carp "Warning: ${ClassName}->_ValidateRequiredHeaderDataKeyValues: Required $Key data header key value is not valid. Supported value: A no-empty text string...";
 921           return 0;
 922         }
 923         last KEY;
 924       }
 925       carp "Warning: ${ClassName}->_ValidateRequiredHeaderDataKeyValues: Required $Key data header key is not not supported...";
 926       return 0;
 927     }
 928   }
 929 
 930   return 1;
 931 }
 932 
 933 # Process required header key valeues for access during complete fingerprints
 934 # string generation from a partial fingerprints string specified on fingerprints
 935 # line...
 936 #
 937 sub _ProcessRequiredHeaderDataKeyValues {
 938   my($This) = @_;
 939   my($Key, $Value, @Keys);
 940 
 941   %{$This->{RequiredHeaderDataKeysAndValues}} = ();
 942 
 943   for $Key (@{$This->{RequiredHeaderDataKeys}}) {
 944     $Value = $This->GetHeaderDataKeyValue($Key);
 945     $This->{RequiredHeaderDataKeysAndValues}{$Key} = $Value;
 946   }
 947 
 948   # Setup prefixes for generating fingerprints strings...
 949   $This->{FingerprintsBitVectorStringPrefix} = '';
 950   $This->{FingerprintsVectorStringPrefix1} = '';
 951   $This->{FingerprintsVectorStringPrefix2} = '';
 952 
 953   if ($This->{RequiredHeaderDataKeysAndValues}{FingerprintsStringType} =~ /^FingerprintsBitVector$/i) {
 954     @Keys = qw(FingerprintsStringType Description Size BitStringFormat BitsOrder);
 955     $This->{FingerprintsBitVectorStringPrefix} = $This->_GenerateFingerprintsPrefixUsingKeys(@Keys);
 956   }
 957   elsif ($This->{RequiredHeaderDataKeysAndValues}{FingerprintsStringType} =~ /^FingerprintsVector$/i) {
 958     @Keys = qw(FingerprintsStringType Description);
 959     $This->{FingerprintsVectorStringPrefix1} = $This->_GenerateFingerprintsPrefixUsingKeys(@Keys);
 960 
 961     @Keys = qw(VectorValuesType VectorStringFormat);
 962     $This->{FingerprintsVectorStringPrefix2} = $This->_GenerateFingerprintsPrefixUsingKeys(@Keys);
 963   }
 964 
 965   return $This;
 966 }
 967 
 968 # Generate fingerprints prefix using header keys data...
 969 #
 970 sub _GenerateFingerprintsPrefixUsingKeys {
 971   my($This, @Keys) = @_;
 972   my($Delimiter, $Key, @Values);
 973 
 974   $Delimiter = Fingerprints::FingerprintsStringUtil::GetFingeprintsStringDelimiter();
 975 
 976   @Values = ();
 977   for $Key (@Keys) {
 978     push @Values, $This->{RequiredHeaderDataKeysAndValues}{$Key};
 979   }
 980 
 981   return join($Delimiter, @Values)
 982 }
 983 
 984 # Get required header data keys...
 985 #
 986 sub _GetRequiredHeaderDataKeys {
 987   my($This, $FingerprintsStringType) = @_;
 988   my(@RequiredKeys);
 989 
 990   @RequiredKeys = ();
 991 
 992   if ($FingerprintsStringType =~ /FingerprintsBitVector$/i) {
 993     push @RequiredKeys, qw(FingerprintsStringType Description Size BitStringFormat BitsOrder);
 994   }
 995   elsif ($FingerprintsStringType =~ /^FingerprintsVector/i) {
 996     push @RequiredKeys, qw(FingerprintsStringType Description VectorStringFormat VectorValuesType);
 997   }
 998   else {
 999     carp "Warning: ${ClassName}->GetRequiredHeaderDataKeys: FingerprintsStringType value, $FingerprintsStringType, is not valid. Supported values: FingerprintsBitVector or FingerprintsVector...";
1000   }
1001 
1002   return @RequiredKeys;
1003 }
1004 
1005 # Validate fingerprints string mode information...
1006 #
1007 sub _ValidateReadFingerprintsStringMode {
1008   my($This) = @_;
1009   my($FingerprintsStringType, $FingerprintsStringDescription, $FingerprintsBitVectorStringMode, $FingerprintsVectorStringMode, $FirstFingerprintsStringType, $FirstFingerprintsStringDescription);
1010 
1011   $This->{ValidFingerprintsStringMode} = 0;
1012   $This->{FingerprintsBitVectorStringMode} = 0;
1013   $This->{FingerprintsVectorStringMode} = 0;
1014 
1015   $This->{FirstFingerprintsStringType} = '';
1016   $This->{FirstFingerprintsStringDescription} = '';
1017 
1018   $FingerprintsBitVectorStringMode = 0;
1019   $FingerprintsVectorStringMode = 0;
1020 
1021   $FirstFingerprintsStringType = '';
1022   $FirstFingerprintsStringDescription = '';
1023 
1024   $FingerprintsStringType = $This->GetHeaderDataKeyValue('FingerprintsStringType');
1025   $FingerprintsStringDescription = $This->GetHeaderDataKeyValue('Description');
1026 
1027   if ($This->{FingerprintsStringMode} =~ /^FingerprintsBitVectorString$/i) {
1028     if ($FingerprintsStringType !~ /^FingerprintsBitVector$/i) {
1029       carp "Warning: ${ClassName}->_ValidateReadFingerprintsStringMode: Fingerprints string data type, $FingerprintsStringType, doesn't correspond to, FingerprintsBitVectorString, specified using \"FingerprintsStringMode\"...";
1030       return 0;
1031     }
1032     $FingerprintsBitVectorStringMode = 1;
1033     $FirstFingerprintsStringType = 'FingerprintsBitVector';
1034     $FirstFingerprintsStringDescription = $FingerprintsStringDescription;
1035   }
1036   elsif ($This->{FingerprintsStringMode} =~ /^FingerprintsVectorString$/i) {
1037     if ($FingerprintsStringType !~ /^FingerprintsVector$/i) {
1038       carp "Warning: ${ClassName}->_ValidateReadFingerprintsStringMode: Fingerprints string data type, $FingerprintsStringType, doesn't correspond to, FingerprintsVectorString, specified using \"FingerprintsStringMode\"...";
1039       return 0;
1040     }
1041     $FingerprintsVectorStringMode = 1;
1042     $FirstFingerprintsStringType = 'FingerprintsVector';
1043     $FirstFingerprintsStringDescription = $FingerprintsStringDescription;
1044   }
1045   else {
1046     # AutoDetect mode...
1047     if ($FingerprintsStringType =~ /^FingerprintsBitVector$/i) {
1048       $FingerprintsBitVectorStringMode = 1;
1049     }
1050     elsif ($FingerprintsStringType =~ /^FingerprintsVector$/i) {
1051       $FingerprintsVectorStringMode = 1;
1052     }
1053     else {
1054       carp "Warning: ${ClassName}->_ValidateReadFingerprintsStringMode: Fingerprints string data type, $FingerprintsStringType, identified during, AutoDetect, value of \"FingerprintsStringMode\" is not valid; Supported fingerprints types: FingerprintBitVector or FingerprintsVector...";
1055       return 0;
1056     }
1057     $FirstFingerprintsStringType = $FingerprintsStringType;
1058     $FirstFingerprintsStringDescription = $FingerprintsStringDescription;
1059   }
1060 
1061   $This->{ValidFingerprintsStringMode} = 1;
1062 
1063   $This->{FingerprintsBitVectorStringMode} = $FingerprintsBitVectorStringMode;
1064   $This->{FingerprintsVectorStringMode} = $FingerprintsVectorStringMode;
1065 
1066   $This->{FirstFingerprintsStringType} = $FirstFingerprintsStringType;
1067   $This->{FirstFingerprintsStringDescription} = $FirstFingerprintsStringDescription;
1068 
1069   return 1;
1070 }
1071 
1072 # Write fingerprints string generated from specified fingerprints - fingerprints-bit vector or
1073 # fingerprints vector - object and other data to FP file...
1074 #
1075 sub WriteFingerprints {
1076   my($This, $FingerprintsObject, $CompoundID) = @_;
1077 
1078   # Initialize data for current line...
1079   $This->_InitializeWriteDataLine();
1080 
1081   # Set fingerprints object and compound ID...
1082   $This->{FingerprintsObject} = $FingerprintsObject;
1083   $This->SetCompoundID($CompoundID);
1084 
1085   # Generate fingerprints string...
1086   $This->_GenerateFingerprintsString();
1087 
1088   # Generate partial fingerprints string...
1089   $This->_GeneratePartialFingerprintsStringFromFingerprintsString();
1090 
1091   # Write data line..
1092   $This->_WriteDataLine();
1093 
1094   return $This;
1095 }
1096 
1097 # Write fingerprints string and other data to FP file...
1098 #
1099 # Notes:
1100 #   o FingerprintsStringMode, BitStringFormat, BitsOrder, VectorStringFormat values
1101 #     are ignored during writing of fingerprints and it's written to the file as it is.
1102 #   o FingerprintsString is a regular fingerprints string as oppose to a partial fingerprints
1103 #     string.
1104 #
1105 sub WriteFingerprintsString {
1106   my($This, $FingerprintsString, $CompoundID) = @_;
1107 
1108   # Initialize data for current line...
1109   $This->_InitializeWriteDataLine();
1110 
1111   # Set fingerprints string and compound ID...
1112   $This->{FingerprintsString} = $FingerprintsString;
1113   $This->SetCompoundID($CompoundID);
1114 
1115   # Generate fingerprints object...
1116   $This->_GenerateFingerprintsObject();
1117 
1118   # Generate partial fingerprints string...
1119   $This->_GeneratePartialFingerprintsStringFromFingerprintsString();
1120 
1121   # Write data line..
1122   $This->_WriteDataLine();
1123 
1124   return $This;
1125 }
1126 
1127 # Initialize data line for reading...
1128 #
1129 sub _InitializeWriteDataLine {
1130   my($This) = @_;
1131 
1132   $This->{DataLine} = undef;
1133   $This->{CompoundID} = undef;
1134 
1135   $This->{FingerprintsObject} = undef;
1136 
1137   $This->{FingerprintsString} = undef;
1138   $This->{PartialFingerprintsString} = undef;
1139 
1140   return $This;
1141 }
1142 
1143 # Write fingerprints data line line...
1144 #
1145 sub _WriteDataLine {
1146   my($This) = @_;
1147   my($FileHandle, $Line);
1148 
1149   if ($This->{FirstDataLineIO}) {
1150     $This->_ProcessFirstDataLineWrite();
1151   }
1152 
1153   # Write data compound ID along with partial fingerprints string...
1154   $Line = $This->{CompoundID} . ' ' . $This->{PartialFingerprintsString};
1155 
1156   $This->{LineNum} += 1;
1157   $FileHandle = $This->{FileHandle};
1158   print $FileHandle "$Line\n";
1159 
1160   $This->{DataLine} = $Line;
1161 
1162   return $This;
1163 }
1164 
1165 # Process first write...
1166 #
1167 sub _ProcessFirstDataLineWrite {
1168   my($This) = @_;
1169   my($Line, $FileHandle);
1170 
1171   $This->{FirstDataLineIO} = 0;
1172 
1173   if ($This->GetMode() =~ /^Write$/i) {
1174     # Skip it for append mode...
1175     $This->_WritePackageAndTimeStampHeaderKeys();
1176     $This->_WriteRequiredHeaderDataKeys();
1177   }
1178 
1179   return $This;
1180 }
1181 
1182 # Write out package and time stamp information...
1183 #
1184 sub _WritePackageAndTimeStampHeaderKeys {
1185   my($This) = @_;
1186   my($FileHandle, $Key, $Value);
1187 
1188   $FileHandle = $This->{FileHandle};
1189 
1190   # Package information...
1191   $This->{LineNum} += 1;
1192   $Key = "Package"; $Value = PackageInfo::GetPackageName() . " " . PackageInfo::GetVersionNumber();
1193   print $FileHandle "# $Key = $Value\n";
1194 
1195   $This->{LineNum} += 1;
1196   $Key = "Release Date"; $Value = PackageInfo::GetReleaseDate();
1197   print $FileHandle "# $Key = $Value\n";
1198 
1199   # Timestamp information...
1200   $This->{LineNum} += 1;
1201   print $FileHandle "#\n";
1202 
1203   $This->{LineNum} += 1;
1204   $Key = "TimeStamp"; $Value = TimeUtil::FPFileTimeStamp();
1205   print $FileHandle "# $Key = $Value\n";
1206 
1207   return $This;
1208 }
1209 
1210 # Write out required header data keys...
1211 #
1212 sub _WriteRequiredHeaderDataKeys {
1213   my($This) = @_;
1214   my($FileHandle, $Key, $Value);
1215 
1216   $FileHandle = $This->{FileHandle};
1217 
1218   $This->_GenerateWriteRequiredHeaderDataKeys();
1219 
1220   $This->{LineNum} += 1;
1221   print $FileHandle "#\n";
1222 
1223   for $Key (@{$This->{RequiredHeaderDataKeys}}) {
1224     $Value = $This->{RequiredHeaderDataKeysAndValues}{$Key};
1225 
1226     $This->{LineNum} += 1;
1227     print $FileHandle "# $Key = $Value\n";
1228 
1229     if ($Key =~ /^FingerprintsStringType$/i) {
1230       $This->{LineNum} += 1;
1231       print $FileHandle "#\n";
1232     }
1233   }
1234 
1235   $This->{LineNum} += 1;
1236   print $FileHandle "#\n";
1237 
1238   return $This;
1239 }
1240 
1241 sub _GenerateWriteRequiredHeaderDataKeys {
1242   my($This) = @_;
1243 
1244   if ($This->{FingerprintsBitVectorStringMode} && ($This->{FingerprintsString} =~ /^FingerprintsBitVector/i)) {
1245     $This->_GenerateWriteRequiredHeaderDataKeysForBitVectorString();
1246   }
1247   elsif ($This->{FingerprintsVectorStringMode} && ($This->{FingerprintsString} =~ /^FingerprintsVector/i)) {
1248     $This->_GenerateWriteRequiredHeaderDataKeysForVectorString();
1249   }
1250   else {
1251     croak "Error: ${ClassName}->_GenerateWriteRequiredHeaderDataKeys: Required header data keys can't be generated: FingerprintsStringMode value, $This->{FingerprintsStringMode}, doesn't correspond to type of first FingerprintsString: $This->{FingerprintsString}...";
1252   }
1253 
1254   return $This;
1255 }
1256 
1257 # Generate required data header keys and values for writing fingerprints bit vector string...
1258 #
1259 sub _GenerateWriteRequiredHeaderDataKeysForBitVectorString {
1260   my($This) = @_;
1261   my($Key, $VectorType, $Description, $Size, $BitStringFormat, $BitsOrder);
1262 
1263   @{$This->{RequiredHeaderDataKeys}} = ();
1264   push @{$This->{RequiredHeaderDataKeys}}, $This->_GetRequiredHeaderDataKeys('FingerprintsBitVector');
1265 
1266   ($VectorType, $Description, $Size, $BitStringFormat, $BitsOrder) = Fingerprints::FingerprintsStringUtil::GetFingerprintsStringValues($This->{FingerprintsString});
1267 
1268   %{$This->{RequiredHeaderDataKeysAndValues}} = ();
1269 
1270   for $Key (@{$This->{RequiredHeaderDataKeys}}) {
1271     KEYTYPE: {
1272       if ($Key =~ /^FingerprintsStringType$/i) {
1273         $This->{RequiredHeaderDataKeysAndValues}{$Key} = $VectorType;
1274         last KEYTYPE;
1275       }
1276       if ($Key =~ /^Description$/i) {
1277         $This->{RequiredHeaderDataKeysAndValues}{$Key} = $Description;
1278         last KEYTYPE;
1279       }
1280       if ($Key =~ /^Size$/i) {
1281         $This->{RequiredHeaderDataKeysAndValues}{$Key} = $Size;
1282         last KEYTYPE;
1283       }
1284       if ($Key =~ /^BitStringFormat$/i) {
1285         $This->{RequiredHeaderDataKeysAndValues}{$Key} = $BitStringFormat;
1286         last KEYTYPE;
1287       }
1288       if ($Key =~ /^BitsOrder$/i) {
1289         $This->{RequiredHeaderDataKeysAndValues}{$Key} = $BitsOrder;
1290         last KEYTYPE;
1291       }
1292       croak "Error: ${ClassName}->_GenerateWriteRequiredHeaderDataKeysForBitVectorString: Required header data key, $Key, value can't be generated: It's not a known key ...";
1293     }
1294   }
1295 
1296   return $This;
1297 }
1298 
1299 # Generate required data header keys and values for writing fingerprints vector string...
1300 #
1301 sub _GenerateWriteRequiredHeaderDataKeysForVectorString {
1302   my($This) = @_;
1303   my($Key, $Value,  $VectorType, $Description, $NumOfValues, $VectorValuesType, $VectorStringFormat);
1304 
1305   @{$This->{RequiredHeaderDataKeys}} = ();
1306   push @{$This->{RequiredHeaderDataKeys}}, $This->_GetRequiredHeaderDataKeys('FingerprintsVector');
1307 
1308   ($VectorType, $Description, $NumOfValues, $VectorValuesType, $VectorStringFormat) = Fingerprints::FingerprintsStringUtil::GetFingerprintsStringValues($This->{FingerprintsString});
1309 
1310   %{$This->{RequiredHeaderDataKeysAndValues}} = ();
1311 
1312   for $Key (@{$This->{RequiredHeaderDataKeys}}) {
1313     KEYTYPE: {
1314       if ($Key =~ /^FingerprintsStringType$/i) {
1315         $This->{RequiredHeaderDataKeysAndValues}{$Key} = $VectorType;
1316         last KEYTYPE;
1317       }
1318       if ($Key =~ /^Description$/i) {
1319         $This->{RequiredHeaderDataKeysAndValues}{$Key} = $Description;
1320         last KEYTYPE;
1321       }
1322       if ($Key =~ /^VectorValuesType$/i) {
1323         $This->{RequiredHeaderDataKeysAndValues}{$Key} = $VectorValuesType;
1324         last KEYTYPE;
1325       }
1326       if ($Key =~ /^VectorStringFormat$/i) {
1327         $This->{RequiredHeaderDataKeysAndValues}{$Key} = $VectorStringFormat;
1328         last KEYTYPE;
1329       }
1330       croak "Error: ${ClassName}->_GenerateWriteRequiredHeaderDataKeysForVectorString: Required header data key, $Key, value can't be generated: It's not a known key ...";
1331     }
1332   }
1333 
1334   return $This;
1335 }
1336 
1337 
1338 # Get ready for writing fingerprints FP file...
1339 #
1340 sub _PrepareForWritingFingerprintsFPFileData {
1341   my($This) = @_;
1342   my($FPFile, $FileDir, $FileName, $FileExt, $OutDelim);
1343 
1344   $FPFile = $This->{Name};
1345   if (!$This->{Overwrite}) {
1346     if (-e $FPFile) {
1347       croak "Error: ${ClassName}->_PrepareForWritingFingerprintsFPFileData: File, $FPFile, already exist. Use overwrite option...";
1348     }
1349   }
1350 
1351   # Setup FingerprintsStringMode status...
1352   #
1353   $This->{FingerprintsBitVectorStringMode} = 0;
1354   $This->{FingerprintsVectorStringMode} = 0;
1355   $This->{ValidFingerprintsStringMode} = 0;
1356 
1357   if ($This->{FingerprintsStringMode} =~ /^FingerprintsBitVectorString$/i) {
1358     $This->{FingerprintsBitVectorStringMode} = 1;
1359   }
1360   elsif ($This->{FingerprintsStringMode} =~ /^FingerprintsVectorString$/i) {
1361     $This->{FingerprintsVectorStringMode} = 1;
1362   }
1363 
1364   $This->{ValidFingerprintsStringMode} = ($This->{FingerprintsBitVectorStringMode} || $This->{FingerprintsVectorStringMode}) ? 1 : 0;
1365 
1366   if ($This->{FingerprintsBitVectorStringMode}) {
1367     $This->_SetDefaultBitStringFormat();
1368     $This->_SetDefaultBitsOrder();
1369   }
1370   elsif ($This->{FingerprintsVectorStringMode}) {
1371     $This->_SetDefaultVectorStringFormat();
1372   }
1373 
1374   return $This;
1375 }
1376 
1377 # Set default value for bit string format...
1378 #
1379 sub _SetDefaultBitStringFormat {
1380   my($This) = @_;
1381 
1382   if (!$This->{BitStringFormat}) {
1383     $This->{BitStringFormat} = Fingerprints::FingerprintsStringUtil::GetDefaultBitStringFormat();
1384   }
1385 
1386   return $This;
1387 }
1388 
1389 # Set default value for bit string format...
1390 #
1391 sub _SetDefaultBitsOrder {
1392   my($This) = @_;
1393 
1394   if (!$This->{BitsOrder}) {
1395     $This->{BitsOrder} = Fingerprints::FingerprintsStringUtil::GetDefaultBitsOrder();
1396   }
1397 
1398   return $This;
1399 }
1400 
1401 # Set default value for vector string format...
1402 #
1403 sub _SetDefaultVectorStringFormat {
1404   my($This) = @_;
1405 
1406   if (!$This->{VectorStringFormat} && $This->{FingerprintsObject}) {
1407     $This->{VectorStringFormat} = Fingerprints::FingerprintsStringUtil::GetDefaultVectorStringFormat($This->{FingerprintsObject});
1408   }
1409 
1410   return $This;
1411 }
1412 
1413 # Generate fingerprints object using current fingerprints string...
1414 #
1415 sub _GenerateFingerprintsObject {
1416   my($This) = @_;
1417 
1418   $This->{FingerprintsObject} = undef;
1419 
1420   if (!$This->{FingerprintsString}) {
1421     return $This;
1422   }
1423 
1424   if ($This->{FingerprintsBitVectorStringMode}) {
1425     $This->{FingerprintsObject} = Fingerprints::FingerprintsStringUtil::ParseFingerprintsBitVectorString($This->{FingerprintsString});
1426   }
1427   elsif ($This->{FingerprintsVectorStringMode}) {
1428     $This->{FingerprintsObject} = Fingerprints::FingerprintsStringUtil::ParseFingerprintsVectorString($This->{FingerprintsString});
1429   }
1430   else {
1431     return undef;
1432   }
1433 
1434   return $This;
1435 }
1436 
1437 # Generate fingerprints string using current fingerprints object...
1438 #
1439 sub _GenerateFingerprintsString {
1440   my($This) = @_;
1441 
1442   $This->{FingerprintsString} = '';
1443 
1444   if (!$This->{FingerprintsObject}) {
1445     return $This;
1446   }
1447 
1448   if ($This->{FingerprintsBitVectorStringMode}) {
1449     $This->{FingerprintsString} = Fingerprints::FingerprintsStringUtil::GenerateFingerprintsString($This->{FingerprintsObject}, $This->{BitStringFormat}, $This->{BitsOrder});
1450   }
1451   elsif ($This->{FingerprintsVectorStringMode}) {
1452     $This->{FingerprintsString} = Fingerprints::FingerprintsStringUtil::GenerateFingerprintsString($This->{FingerprintsObject}, $This->{VectorStringFormat});
1453   }
1454 
1455   return $This;
1456 }
1457 
1458 # Generate fingerprints string using partial fingerprints string and header keys data...
1459 #
1460 # Notes:
1461 #   o FP file fingerprints data line only contain partial fingerprints data which
1462 #     can't be used directly to create fingerprints bit-vector or vector objects
1463 #     using functions available in FingerprintsStringUtil.pm module
1464 #
1465 sub _GenerateFingerprintsStringFromPartialFingerprintsString {
1466   my($This) = @_;
1467   my($FPStringDelim);
1468 
1469   $This->{FingerprintsString} = '';
1470 
1471   if (!$This->{PartialFingerprintsString}) {
1472     return $This;
1473   }
1474 
1475   $FPStringDelim = Fingerprints::FingerprintsStringUtil::GetFingeprintsStringDelimiter();
1476 
1477   if ($This->{FingerprintsBitVectorStringMode}) {
1478     $This->{FingerprintsString} = $This->{FingerprintsBitVectorStringPrefix} . $FPStringDelim . $This->{PartialFingerprintsString};
1479   }
1480   elsif ($This->{FingerprintsVectorStringMode}) {
1481     my($NumOfValues, $VectorStringData);
1482 
1483     ($NumOfValues, $VectorStringData) =  $This->{PartialFingerprintsString} =~ /^(.*?)$FPStringDelim(.*?)$/;
1484     if (!(defined($NumOfValues) && defined($VectorStringData) && $VectorStringData)) {
1485       return $This;
1486     }
1487 
1488     $This->{FingerprintsString} = $This->{FingerprintsVectorStringPrefix1} . $FPStringDelim . $NumOfValues . $FPStringDelim . $This->{FingerprintsVectorStringPrefix2} . $FPStringDelim . $VectorStringData;
1489   }
1490 
1491   return $This;
1492 }
1493 
1494 # Generate partial fingerprints string using fingerprints string and header keys data...
1495 #
1496 # Notes:
1497 #   o FP file fingerprints data line only contain partial fingerprints data which
1498 #     can't be used directly to create fingerprints bit-vector or vector objects
1499 #     using functions available in FingerprintsStringUtil.pm module
1500 #
1501 sub _GeneratePartialFingerprintsStringFromFingerprintsString {
1502   my($This) = @_;
1503 
1504   $This->{PartialFingerprintsString} = '';
1505 
1506   if (!$This->{FingerprintsString}) {
1507     return $This;
1508   }
1509 
1510   if ($This->{FingerprintsBitVectorStringMode}) {
1511     my($VectorType, $Description, $Size, $BitStringFormat, $BitsOrder, $BitVectorString);
1512 
1513     ($VectorType, $Description, $Size, $BitStringFormat, $BitsOrder, $BitVectorString) = Fingerprints::FingerprintsStringUtil::GetFingerprintsStringValues($This->{FingerprintsString});
1514     $This->{PartialFingerprintsString} = $BitVectorString;
1515   }
1516   elsif ($This->{FingerprintsVectorStringMode}) {
1517     my($FPStringDelim, $VectorType, $Description, $NumOfValues, $VectorValuesType, $VectorStringFormat, $VectorString1, $VectorString2, $VectorString);
1518 
1519     $FPStringDelim = Fingerprints::FingerprintsStringUtil::GetFingeprintsStringDelimiter();
1520 
1521     ($VectorType, $Description, $NumOfValues, $VectorValuesType, $VectorStringFormat, $VectorString1, $VectorString2) = Fingerprints::FingerprintsStringUtil::GetFingerprintsStringValues($This->{FingerprintsString});
1522     $VectorString = TextUtil::IsEmpty($VectorString2) ? $VectorString1 : "${VectorString1}${FPStringDelim}${VectorString2}";
1523 
1524     $This->{PartialFingerprintsString} = $NumOfValues . $FPStringDelim . $VectorString;
1525   }
1526 
1527   return $This;
1528 }
1529 
1530 # Is it a fingerprints file?
1531 sub IsFingerprintsFPFile ($;$) {
1532   my($FirstParameter, $SecondParameter) = @_;
1533   my($This, $FileName, $Status);
1534 
1535   if ((@_ == 2) && (_IsFingerprintsFPFileIO($FirstParameter))) {
1536     ($This, $FileName) = ($FirstParameter, $SecondParameter);
1537   }
1538   else {
1539     $FileName = $FirstParameter;
1540   }
1541 
1542   # Check file extension...
1543   $Status = FileUtil::CheckFileType($FileName, "fpf fp");
1544 
1545   return $Status;
1546 }
1547 
1548 # Is it a FingerprintsFPFileIO object?
1549 sub _IsFingerprintsFPFileIO {
1550   my($Object) = @_;
1551 
1552   return (Scalar::Util::blessed($Object) && $Object->isa($ClassName)) ? 1 : 0;
1553 }
1554