MayaChemTools

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