MayaChemTools

   1 package FileIO::FingerprintsTextFileIO;
   2 #
   3 # $RCSfile: FingerprintsTextFileIO.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 Fingerprints::FingerprintsStringUtil ();
  36 use FileIO::FileIO;
  37 
  38 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  39 
  40 @ISA = qw(FileIO::FileIO Exporter);
  41 @EXPORT = qw();
  42 @EXPORT_OK = qw(IsFingerprintsTextFile);
  43 
  44 %EXPORT_TAGS = (all  => [@EXPORT, @EXPORT_OK]);
  45 
  46 # Setup class variables...
  47 my($ClassName);
  48 _InitializeClass();
  49 
  50 # Class constructor...
  51 sub new {
  52   my($Class, %NamesAndValues) = @_;
  53 
  54   # Initialize object...
  55   my $This = $Class->SUPER::new();
  56   bless $This, ref($Class) || $Class;
  57   $This->_InitializeFingerprintsTextFileIO();
  58 
  59   $This->_InitializeFingerprintsTextFileIOProperties(%NamesAndValues);
  60 
  61   return $This;
  62 }
  63 
  64 # Initialize object data...
  65 #
  66 sub _InitializeFingerprintsTextFileIO {
  67   my($This) = @_;
  68 
  69   # Fingerprints string data format during read/write...
  70   #
  71   # For file read:
  72   #
  73   # AutoDetect  - automatically detect format of fingerprints string
  74   # FingerprintsBitVectorString - Bit vector fingerprints string format
  75   # FingerprintsVectorString - Vector fingerprints string format
  76   #
  77   # Default value: AutoDetect
  78   #
  79   # For file write:
  80   #
  81   # FingerprintsBitVectorString - Bit vector fingerprints string format
  82   # FingerprintsVectorString - Vector fingerprints string format
  83   #
  84   # Default value: undef
  85   #
  86   $This->{FingerprintsStringMode} = undef;
  87 
  88   # For file read:
  89   #
  90   #   o Fingerprints bit-vector and vector object for current fingerprints string
  91   #
  92   # For file write:
  93   #
  94   #   o Fingerprints bit-vector and vector object for current fingerprints string
  95   #   o Any supported fingerprints object: PathLengthFingerprints, ExtendedConnectivity, and so on.
  96   #
  97   $This->{FingerprintsObject} = undef;
  98 
  99   # Fingepritns string for current line during read/write...
 100   $This->{FingerprintsString} = undef;
 101 
 102   # First data line read/write...
 103   $This->{FirstDataLineIO} = 1;
 104 
 105   # Current fingerprints string data line number during read/write...
 106   $This->{LineNum} = 0;
 107 
 108   # Text line data during read/write...
 109   $This->{DataLine} = undef;
 110   @{$This->{DataLineWords}} = ();
 111 
 112   # Text file column data during read/write...
 113   @{$This->{DataColLabels}} = ();
 114 
 115   # Text file delimiter during read/write...
 116   $This->{Delim} = '';
 117 
 118   # Initialize parameters for read...
 119   $This->_InitializeFingerprintsTextFileIORead();
 120 
 121   # Initialize parameters for write...
 122   $This->_InitializeFingerprintsTextFileIOWrite();
 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 text file...
 135 #
 136 sub _InitializeFingerprintsTextFileIORead {
 137   my($This) = @_;
 138 
 139   # Column ID specification for identification of comound ID or fingerints string
 140   # data column...
 141   #
 142   # ColNum - A valid column number
 143   # ColLabel - A valid column name
 144   #
 145   $This->{ColMode} = 'ColNum';
 146 
 147   # Fingerprints column to use for retrieving fingerprints string data...
 148   #
 149   # Value of AutoDetect implies use first column containing the word  Fingerprints in its
 150   # column label to retrieve fingerprints string data. Othwewise, a valid column number
 151   # or column name must be specified based on the value of ColMode.
 152   #
 153   $This->{FingerprintsCol} = 'AutoDetect';
 154 
 155   # Compound ID column to use for retrieving compound IDs for fingerprints...
 156   #
 157   # Value of AutoDetect implies use first column containing the word CompoundID in its column
 158   # label to retrieve compound IDs or assign seqyentially generated compound IDs. Othwewise,
 159   # a valid column number or column name must be specified based on the value of ColMode.
 160   #
 161   $This->{CompoundIDCol} = 'AutoDetect';
 162 
 163   # A prefix string used for generating compound IDs like LabelPrefixString<Number> during
 164   # sequential generation of compound IDs. Default value, Cmpd, generates compound IDs
 165   # which look like like Cmpd<Number>.
 166   #
 167   $This->{CompoundIDPrefix} = 'Cmpd';
 168 
 169   # Input delimiter for fingerprints CSV text file. Possible values: comma, semicolon or tab. This
 170   # option is ignored for TSV text file and tab is used as the delimiter.
 171   #
 172   $This->{InDelim} = 'comma';
 173 
 174   # By default, the fingerprints data corresponding to FingerprintsCol is assumed to
 175   # be valid and no validation is performed before generating fingerprints objects...
 176   #
 177   $This->{ValidateData} = 1;
 178 
 179   # Level of detail to print during validation of data for invalid or missing data...
 180   $This->{DetailLevel} = 1;
 181 
 182   # Number of missing and invalid fingerprints string data lines...
 183   $This->{NumOfLinesWithMissingData} = 0;
 184   $This->{NumOfLinesWithInvalidData} = 0;
 185 
 186   # Compound ID for current fingerprints string...
 187   $This->{CompoundID} = undef;
 188 
 189   # Status of data in fingerprints text file...
 190   $This->{ValidFileData} = 0;
 191 
 192   $This->{ValidCompoundIDCol} = 0;
 193   $This->{ValidFingerprintsCol} = 0;
 194 
 195   $This->{ValidFingerprintsStringMode} = 0;
 196 
 197   return $This;
 198 }
 199 
 200 # Initialize object data for writing fingerprints text file...
 201 #
 202 sub _InitializeFingerprintsTextFileIOWrite {
 203   my($This) = @_;
 204 
 205   # Fingerprints bit vector string format...
 206   #
 207   # Possible values: BinaryString or HexadecimalString [Default]
 208   #
 209   # Default BitStringFormat is set during first write using Fingerprints::FingerprintsStringUtil::GetDefaultBitStringFormat.
 210   #
 211   $This->{BitStringFormat} = undef;
 212 
 213   # Bits order in fingerprints bit vector string...
 214   #
 215   # Ascending - First bit in each byte as the lowest bit [Default]
 216   # Descending - First bit in each byte as the highest bit
 217   #
 218   # Default BitsOrder is set during first write using Fingerprints::FingerprintsStringUtil::GetDefaultBitsOrder.
 219   #
 220   $This->{BitsOrder} = undef;
 221 
 222   # Fingerprints vector string format...
 223   #
 224   # Possible values: IDsAndValuesString, IDsAndValuesPairsString, ValuesAndIDsString, ValuesAndIDsPairsString, ValuesString
 225   #
 226   # Default VectorStringFormat is set during first write using Fingerprints::FingerprintsStringUtil::GetDefaultVectorStringFormat.
 227   # For fingerprints vector object containing vector NumericalValues, it corresponds to IDsAndValuesString; othwerwise,
 228   # it's set to ValuesString.
 229   #
 230   $This->{VectorStringFormat} = undef;
 231 
 232   # Delimiter for output fingerprints CSV/TSV file. Possible values: comma, tab, semicolon. This
 233   # option is ignored for TSV text file and tab is used as the delimiter.
 234   #
 235   $This->{OutDelim} = 'comma';
 236 
 237   # Quotes around column values for output fingerprints CSV/TSV text file...
 238   $This->{OutQuote} = 1;
 239 
 240   # Overwriting existing file...
 241   $This->{Overwrite} = 0;
 242 
 243   return $This;
 244 }
 245 
 246 # Initialize object values...
 247 sub _InitializeFingerprintsTextFileIOProperties {
 248   my($This, %NamesAndValues) = @_;
 249 
 250   # All other property names and values along with all Set/Get<PropertyName> methods
 251   # are implemented on-demand using ObjectProperty class.
 252 
 253   my($Name, $Value, $MethodName);
 254   while (($Name, $Value) = each  %NamesAndValues) {
 255     $MethodName = "Set${Name}";
 256     $This->$MethodName($Value);
 257   }
 258 
 259   if (!exists $NamesAndValues{Name}) {
 260     croak "Error: ${ClassName}->New: Object can't be instantiated without specifying file name...";
 261   }
 262 
 263   # Make sure it's a fingerprints file...
 264   $Name = $NamesAndValues{Name};
 265   if (!$This->IsFingerprintsTextFile($Name)) {
 266     croak "Error: ${ClassName}->New: Object can't be instantiated: File, $Name, doesn't appear to be fingerprints format...";
 267   }
 268 
 269   if ($This->GetMode() =~ /^Read$/i) {
 270     $This->_InitializeFingerprintsTextFileIOReadProperties(%NamesAndValues);
 271   }
 272   elsif ($This->GetMode() =~ /^(Write|Append)$/i) {
 273     $This->_InitializeFingerprintsTextFileIOWriteProperties(%NamesAndValues);
 274   }
 275 
 276   return $This;
 277 }
 278 
 279 # Initialize object properties for reading fingerprints text file...
 280 #
 281 sub _InitializeFingerprintsTextFileIOReadProperties {
 282   my($This, %NamesAndValues) = @_;
 283 
 284   # Set default value for FingerprintsStringMode...
 285   if (!$This->{FingerprintsStringMode}) {
 286     $This->{FingerprintsStringMode} = 'AutoDetect';
 287   }
 288 
 289   $This->_PrepareForReadingFingerprintsTextFileData();
 290 
 291   return $This;
 292 }
 293 
 294 # Initialize object properties for writing fingerprints text file...
 295 #
 296 sub _InitializeFingerprintsTextFileIOWriteProperties {
 297   my($This, %NamesAndValues) = @_;
 298 
 299   # Check FingerprintsStringMode value...
 300   if (!exists $NamesAndValues{FingerprintsStringMode}) {
 301     croak "Error: ${ClassName}->New: Object can't be instantiated without specifying FingerprintsStringMode...";
 302   }
 303 
 304   if ($This->{FingerprintsStringMode} !~ /^(FingerprintsBitVectorString|FingerprintsVectorString)$/i) {
 305     croak "Error: ${ClassName}->: Object can't be instantiated: FingerprintsStringMode value, $This->{FingerprintsStringMode}, is not valid; Supported values for write/append: FingerprintsBitVectorString or FingerprintsVectorString...";
 306   }
 307 
 308   if (!exists $NamesAndValues{DataColLabels}) {
 309     croak "Error: ${ClassName}->New: Object can't be instantiated without specifying DataColLabels...";
 310   }
 311 
 312   if ($This->{OutDelim} =~ /semicolon/i && !$This->{OutQuote}) {
 313     croak "Error: ${ClassName}->: Object can't be instantiated: The value specified, $This->{OutQuote}, using \"OutQuote\" is not allowed with semicolon value of \"OutDelim\": Fingerprints string use semicolon as delimiter for various data fields and must be quoted.\n";
 314   }
 315 
 316   $This->_PrepareForWritingFingerprintsTextFileData();
 317 
 318   return $This;
 319 }
 320 
 321 # Set FingerprintsStringMode...
 322 #
 323 sub SetFingerprintsStringMode {
 324   my($This, $Value) = @_;
 325 
 326   # AutoDetect - automatically detect format of fingerprints string
 327   # FingerprintsBitVectorString - Bit vector fingerprints string format
 328   # FingerprintsVectorString - Vector fingerprints string format
 329 
 330   if ($Value !~ /^(AutoDetect|FingerprintsBitVectorString|FingerprintsVectorString)$/i) {
 331     croak "Error: ${ClassName}->SetFingerprintsStringMode: FingerprintsStringMode value, $Value, is not valid; Supported values: AutoDetect, FingerprintsBitVectorString or FingerprintsVectorString...";
 332   }
 333 
 334   $This->{FingerprintsStringMode} = $Value;
 335 
 336   return $This;
 337 }
 338 
 339 # Set ColMode...
 340 #
 341 sub SetColMode {
 342   my($This, $Value) = @_;
 343 
 344   if ($Value !~ /^(ColNum|ColLabel)$/i) {
 345     croak "Error: ${ClassName}->SetColMode: ColMode value, $Value, is not valid; Supported values: ColNum or ColLabel...";
 346   }
 347 
 348   $This->{ColMode} = $Value;
 349 
 350   return $This;
 351 }
 352 
 353 # Set InDelim...
 354 #
 355 sub SetInDelim {
 356   my($This, $Value) = @_;
 357 
 358   if ($Value !~ /^(comma|semicolon|tab)$/i) {
 359     croak "Error: ${ClassName}->SetInDelim: InDelim value, $Value, is not valid; Supported values: comma, semicolon, or tab...";
 360   }
 361 
 362   $This->{InDelim} = $Value;
 363 
 364   return $This;
 365 }
 366 
 367 # Set DetailLevel...
 368 #
 369 sub SetDetailLevel {
 370   my($This, $Value) = @_;
 371 
 372   if (!TextUtil::IsPositiveInteger($Value)) {
 373     croak "Error: ${ClassName}->SetDetailLevel: DetailLevel value, $Value, is not valid; Supported values: > 0...";
 374   }
 375 
 376   $This->{DetailLevel} = $Value;
 377 
 378   return $This;
 379 }
 380 
 381 # Set BitStringFormat...
 382 #
 383 sub SetBitStringFormat {
 384   my($This, $Value) = @_;
 385 
 386   if ($Value !~ /^(BinaryString|HexadecimalString)$/i) {
 387     croak "Error: ${ClassName}->SetBitStringFormat: BitStringFormat value, $Value, is not valid; Supported values: BinaryString or HexadecimalString...";
 388   }
 389 
 390   $This->{BitStringFormat} = $Value;
 391 
 392   return $This;
 393 }
 394 
 395 # Set BitsOrder...
 396 #
 397 sub SetBitsOrder {
 398   my($This, $Value) = @_;
 399 
 400   # Ascending - First bit in each byte as the lowest bit
 401   # Descending - First bit in each byte as the highest bit
 402   #
 403   if ($Value !~ /^(Ascending|Descending)$/i) {
 404     croak "Error: ${ClassName}->SetBitsOrder: FingerprintsStringMode value, $Value, is not valid; Supported values: Ascending or Descending...";
 405   }
 406 
 407   $This->{BitsOrder} = $Value;
 408 
 409   return $This;
 410 }
 411 
 412 # Set VectorStringFormat...
 413 #
 414 sub SetVectorStringFormat {
 415   my($This, $Value) = @_;
 416 
 417   # Possible values: IDsAndValuesString, IDsAndValuesPairsString, ValuesAndIDsString, ValuesAndIDsPairsString, ValuesString
 418 
 419   if ($Value !~ /^(IDsAndValuesString|IDsAndValuesPairsString|ValuesAndIDsString|ValuesAndIDsPairsString|ValuesString)$/i) {
 420     croak "Error: ${ClassName}->SetVectorStringFormat: FingerprintsStringMode value, $Value, is not valid; Supported values: IDsAndValuesString, IDsAndValuesPairsString, ValuesAndIDsString, ValuesAndIDsPairsString, or ValuesString...";
 421   }
 422 
 423   $This->{VectorStringFormat} = $Value;
 424 
 425   return $This;
 426 }
 427 
 428 # Set FingerprintsStringMode...
 429 #
 430 sub SetOutDelim {
 431   my($This, $Value) = @_;
 432 
 433   if ($Value !~ /^(comma|tab|semicolon)$/i) {
 434     croak "Error: ${ClassName}->SetOutDelim: OutDelim value, $Value, is not valid; Supported values: comma, tab or semicolon...";
 435   }
 436 
 437   $This->{OutDelim} = $Value;
 438 
 439   return $This;
 440 }
 441 
 442 # Set DataColLabels...
 443 #
 444 # Set output data column labels using:
 445 #    o List of column labels
 446 #    o Reference to an list of column labels
 447 #
 448 sub SetDataColLabels {
 449   my($This, @Values) = @_;
 450   my($FirstValue, $TypeOfFirstValue);
 451 
 452   if (!@Values) {
 453     carp "Warning: ${ClassName}->_SetDataColLabels: No data column labels specified...";
 454     return $This;
 455   }
 456 
 457   @{$This->{DataColLabels}} = ();
 458 
 459   $FirstValue = $Values[0];
 460   $TypeOfFirstValue = ref $FirstValue;
 461 
 462   if ($TypeOfFirstValue =~ /^ARRAY/) {
 463     # Initialize using array refernce...
 464     push @{$This->{DataColLabels}}, @{$FirstValue};
 465   }
 466   else {
 467     # It's a list of values...
 468     push @{$This->{DataColLabels}}, @Values;
 469   }
 470 
 471   return $This;
 472 }
 473 
 474 # Get column labels or number of column labels in first text line...
 475 #
 476 sub GetDataColLabels {
 477   my($This) = @_;
 478 
 479   return wantarray ? @{$This->{DataColLabels}} : scalar @{$This->{DataColLabels}};
 480 }
 481 
 482 # Get words or number of words in current data line...
 483 #
 484 sub GetDataLineWords {
 485   my($This) = @_;
 486 
 487   return wantarray ? @{$This->{DataLineWords}} : scalar @{$This->{DataLineWords}};
 488 }
 489 
 490 # Set DataLineWords...
 491 #
 492 # Set data line words using:
 493 #    o List of line words
 494 #    o Reference to an list of line words
 495 #
 496 sub SetDataLineWords {
 497   my($This, @Values) = @_;
 498   my($FirstValue, $TypeOfFirstValue);
 499 
 500   if (!@Values) {
 501     carp "Warning: ${ClassName}->SetDataLineWords: No line words specified...";
 502     return $This;
 503   }
 504 
 505   @{$This->{DataLineWords}} = ();
 506 
 507   $FirstValue = $Values[0];
 508   $TypeOfFirstValue = ref $FirstValue;
 509 
 510   if ($TypeOfFirstValue =~ /^ARRAY/) {
 511     # Initialize using array refernce...
 512     push @{$This->{DataLineWords}}, @{$FirstValue};
 513   }
 514   else {
 515     # It's a list of values...
 516     push @{$This->{DataLineWords}}, @Values;
 517   }
 518 
 519   return $This;
 520 }
 521 
 522 # Get fingerprints object for current data line using fingerprints, fingerprints bit-vector
 523 # fingerprints vector object. Fingerprints object correspond to any of supported fingerprints
 524 # objects such as PathLengthFingerprints, ExtendedConnectivity, and so on.
 525 #
 526 sub GetFingerprints {
 527   my($This) = @_;
 528 
 529   return $This->{FingerprintsObject};
 530 }
 531 
 532 # Set fingerprints object for current data line...
 533 #
 534 sub SetFingerprints {
 535   my($This, $FingerprintsObject) = @_;
 536 
 537   $This->{FingerprintsObject} = $FingerprintsObject;
 538 
 539   return $This;
 540 }
 541 
 542 # Get fingerprints string  for current data line...
 543 #
 544 sub GetFingerprintsString {
 545   my($This) = @_;
 546 
 547   return $This->{FingerprintsString} ? $This->{FingerprintsString} : 'None';
 548 }
 549 
 550 # Set fingerprints string for current data line...
 551 #
 552 sub SetFingerprintsString {
 553   my($This, $FingerprintsString) = @_;
 554 
 555   $This->{FingerprintsString} = $FingerprintsString;
 556 
 557   return $This;
 558 }
 559 
 560 # Does fingerprints text file contain valid data?
 561 #
 562 sub IsFingerprintsFileDataValid {
 563   my($This) = @_;
 564 
 565   return $This->{ValidFileData} ? 1 : 0;
 566 }
 567 
 568 # Does current data line contains valid fingerprints object data?
 569 #
 570 sub IsFingerprintsDataValid {
 571   my($This) = @_;
 572 
 573   return defined $This->{FingerprintsObject} ? 1 : 0;
 574 }
 575 
 576 # Read next available fingerprints line, process it and generate appropriate fingerprints
 577 # objects...
 578 #
 579 sub Read {
 580   my($This) = @_;
 581 
 582   # Read data line...
 583   if (!$This->_ReadDataLine()) {
 584     return undef;
 585   }
 586 
 587   # No need to process invalid text file with invalid data...
 588   if (!$This->{ValidFileData}) {
 589     if ($This->{ValidateData}) {
 590       $This->{NumOfLinesWithMissingData} += 1;
 591     }
 592     return $This;
 593   }
 594 
 595   # Perform data validation...
 596   if ($This->{ValidateData}) {
 597     if (!$This->_ValidateReadDataLine()) {
 598       return $This;
 599     }
 600   }
 601 
 602   # Setup fingerprints string after checking again to handle problematic data for
 603   # non-validated data lines...
 604   #
 605   if ($This->{FingerprintsColNum} <= $#{$This->{DataLineWords}}) {
 606     $This->{FingerprintsString} = $This->{DataLineWords}[$This->{FingerprintsColNum}];
 607   }
 608 
 609   # Generate fingeprints object...
 610   $This->_GenerateFingerprintsObject();
 611 
 612   # Setup fingerprints compound ID for fingerprints string...
 613   $This->_GenerateCompoundID();
 614 
 615   return $This;
 616 }
 617 
 618 # Read next available fingerprints line, process it and generate appropriate fingerprints
 619 # objects...
 620 #
 621 sub Next {
 622   my($This) = @_;
 623 
 624   return $This->Read();
 625 }
 626 
 627 # Read fingerprints data line line...
 628 #
 629 sub _ReadDataLine {
 630   my($This) = @_;
 631 
 632   if ($This->{FirstDataLineIO}) {
 633     $This->_ProcessFirstDataLineRead();
 634   }
 635 
 636   # Initialize data for current line...
 637   $This->_InitializeReadDataLine();
 638 
 639   # Get next data line...
 640   $This->{DataLine} = TextUtil::GetTextLine($This->{FileHandle});
 641   if (!$This->{DataLine}) {
 642     return 0;
 643   }
 644 
 645   # Get line words...
 646   $This->{LineNum} += 1;
 647   @{$This->{DataLineWords}} = TextUtil::SplitWords($This->{DataLine}, $This->{Delim});
 648 
 649   return 1;
 650 }
 651 
 652 # Initialize data line for reading...
 653 #
 654 sub _InitializeReadDataLine {
 655   my($This) = @_;
 656 
 657   $This->{CompoundID} = undef;
 658 
 659   $This->{DataLine} = undef;
 660   @{$This->{DataLineWords}} = ();
 661 
 662   $This->{FingerprintsObject} = undef;
 663   $This->{FingerprintsString} = undef;
 664 
 665   return $This;
 666 }
 667 
 668 # Validate fingerprints string data line...
 669 #
 670 sub _ValidateReadDataLine {
 671   my($This) = @_;
 672 
 673   # Check for missing data...
 674   if ($This->{FingerprintsColNum} > $#{$This->{DataLineWords}}) {
 675     # Missing data...
 676     $This->{NumOfLinesWithMissingData} += 1;
 677     if ($This->{DetailLevel} >= 3) {
 678       carp "Warning: ${ClassName}->_ValidateReadDataLine: Data line number $This->{LineNum} contains no fingerprints data: $This->{DataLine}...";
 679     }
 680     elsif ($This->{DetailLevel} >= 2) {
 681       carp "Warning: ${ClassName}->_ValidateReadDataLine: Data line number $This->{LineNum} contains no fingerprints data...";
 682     }
 683     return 0;
 684   }
 685 
 686   # Check for invalid data...
 687   my($InvalidFingerprintsData, $FingerprintsColNum, $FingerprintsType, $FingerprintsDescription);
 688 
 689   $InvalidFingerprintsData = 0;
 690   $FingerprintsColNum = $This->{FingerprintsColNum};
 691 
 692   if (Fingerprints::FingerprintsStringUtil::AreFingerprintsStringValuesValid($This->{DataLineWords}[$FingerprintsColNum])) {
 693     ($FingerprintsType, $FingerprintsDescription) = Fingerprints::FingerprintsStringUtil::GetFingerprintsStringTypeAndDescription($This->{DataLineWords}[$FingerprintsColNum]);
 694     if ($This->{FirstFingerprintsStringType} !~ /^$FingerprintsType$/i || $This->{FirstFingerprintsStringDescription} !~ /^$FingerprintsDescription$/i) {
 695       $InvalidFingerprintsData = 1;
 696     }
 697   }
 698   else {
 699     $InvalidFingerprintsData = 1;
 700   }
 701 
 702   if ($InvalidFingerprintsData) {
 703     $This->{NumOfLinesWithInvalidData} += 1;
 704     if ($This->{DetailLevel} >= 3) {
 705       carp "Warning: ${ClassName}->_ValidateReadDataLine: Data line number $This->{LineNum} contains invalid fingerprints data: $This->{DataLine}...";
 706     }
 707     elsif ($This->{DetailLevel} >= 2) {
 708       carp "Warning: ${ClassName}->_ValidateReadDataLine: Data line number $This->{LineNum} contains invalid fingerprints data...";
 709     }
 710     return 0;
 711   }
 712 
 713   return 1;
 714 }
 715 
 716 # Setup fingerprints compound ID for fingerprints string...
 717 sub _GenerateCompoundID {
 718   my($This) = @_;
 719   my($CompoundID);
 720 
 721   $CompoundID = '';
 722 
 723   if ($This->{UseSequentialCompoundIDs} || ($This->{CompoundIDColNum} > $#{$This->{DataLineWords}})) {
 724     my($CompoundNum);
 725 
 726     $CompoundNum = $This->{LineNum} - 1;
 727     $CompoundID = "$This->{CompoundIDPrefix}${CompoundNum}";
 728   }
 729   else {
 730     $CompoundID = $This->{DataLineWords}[$This->{CompoundIDColNum}];
 731   }
 732 
 733   $This->{CompoundID} = $CompoundID;
 734 
 735   # Set fingerprints ID...
 736   if ($This->{FingerprintsObject}) {
 737     $This->{FingerprintsObject}->SetID($This->{CompoundID});
 738   }
 739 
 740   return $This;
 741 }
 742 
 743 # Process first read...
 744 #
 745 sub _ProcessFirstDataLineRead {
 746   my($This) = @_;
 747 
 748   # Skip column label line...
 749   $This->{LineNum} += 1;
 750   TextUtil::GetTextLine($This->{FileHandle});
 751 
 752   $This->{FirstDataLineIO} = 0;
 753 
 754   return $This;
 755 }
 756 
 757 # Get ready for reading fingerprints text file...
 758 #
 759 sub _PrepareForReadingFingerprintsTextFileData {
 760   my($This) = @_;
 761 
 762   # Retrieve text file columns information....
 763   $This->_RetrieveTextFileColData();
 764 
 765   # Validate columns information...
 766   $This->_ValidateReadCompoundIDCol();
 767   $This->_ValidateReadFingerprintsCol();
 768 
 769   # Validate fingeprints string mode information...
 770   if ($This->{ValidFingerprintsCol}) {
 771     $This->_ValidateReadFingerprintsStringMode();
 772   }
 773 
 774   # Set status of text file data...
 775   $This->{ValidFileData} = ($This->{ValidCompoundIDCol} && $This->{ValidFingerprintsCol} && $This->{ValidFingerprintsStringMode}) ? 1 : 0;
 776 
 777   return $This;
 778 }
 779 
 780 # Retrieve information about columns and fingerprints string...
 781 #
 782 sub _RetrieveTextFileColData {
 783   my($This) = @_;
 784   my($TextFile, $FileDir, $FileName, $FileExt, $InDelim, $Line, $ColLabel, $ColNum, @ColLabels);
 785 
 786   @{$This->{DataColLabels}} = ();
 787   %{$This->{DataColLabelToNumMap}} = ();
 788 
 789   $TextFile = $This->{Name};
 790 
 791   if (!(-e $TextFile)) {
 792     croak "Error: ${ClassName}->New: Object can't be instantiated: File, $TextFile, doesn't exist...";
 793   }
 794 
 795   $FileDir = ""; $FileName = ""; $FileExt = "";
 796   ($FileDir, $FileName, $FileExt) = FileUtil::ParseFileName($TextFile);
 797 
 798   $InDelim = ($FileExt =~ /^tsv$/i) ? "\t" : ($This->{InDelim} =~ /semicolon/i ? "\;" : "\,");
 799   $This->{Delim} = $InDelim;
 800 
 801   if (!open TEXTFILE, "$TextFile") {
 802     croak "Error: ${ClassName}->New: Object can't be instantiated: Couldn't open input text file $TextFile: $! ...";
 803   }
 804 
 805   # Get column label line...
 806   $Line = TextUtil::GetTextLine(\*TEXTFILE);
 807 
 808   close TEXTFILE;
 809 
 810   @ColLabels = TextUtil::SplitWords($Line, $InDelim);
 811 
 812   # Set text file columns info....
 813   push @{$This->{DataColLabels}}, @ColLabels;
 814 
 815   for $ColNum (0 .. $#ColLabels) {
 816     $ColLabel = $ColLabels[$ColNum];
 817     $This->{DataColLabelToNumMap}{$ColLabel} = $ColNum;
 818   }
 819 
 820   return $This;
 821 }
 822 
 823 # Validate compound ID column information...
 824 #
 825 sub _ValidateReadCompoundIDCol {
 826   my($This) = @_;
 827   my($CompoundIDCol, $CompoundIDColNum, $UseSequentialCompoundIDs, $ColFound, $ColLabel, $ColNum);
 828 
 829   $This->{ValidCompoundIDCol} = 0;
 830   $This->{CompoundIDColNum} = undef;
 831   $This->{UseSequentialCompoundIDs} = 0;
 832 
 833   $CompoundIDCol = $This->{CompoundIDCol};
 834 
 835   $UseSequentialCompoundIDs = 0;
 836   $CompoundIDColNum = '';
 837 
 838   if ($CompoundIDCol =~ /^AutoDetect$/i) {
 839     # First column containing the word CompoundID in its label or sequential generation...
 840 
 841     $ColFound = 0;
 842     COLLABEL: for $ColLabel (@{$This->{DataColLabels}}) {
 843       if ($ColLabel =~ /CompoundID/i) {
 844         $ColFound = 1;
 845         $ColNum = $This->{DataColLabelToNumMap}{$ColLabel};
 846         last COLLABEL;
 847       }
 848     }
 849     if ($ColFound) {
 850       $CompoundIDColNum = $ColNum;
 851     }
 852     else {
 853       $UseSequentialCompoundIDs = 1;
 854     }
 855   }
 856   else {
 857     if ($This->{ColMode} =~ /^ColNum$/i) {
 858       # Is it a valid column number?
 859       if ($CompoundIDCol > scalar @{$This->{DataColLabels}}) {
 860         carp "Warning: ${ClassName}->_ValidateReadCompoundIDCol: Column number, $CompoundIDCol, specified using CompoundIDCol doesn't exist...";
 861         return 0;
 862       }
 863       $CompoundIDColNum = $CompoundIDCol - 1;
 864     }
 865     elsif ($This->{ColMode} =~ /^ColLabel$/i) {
 866       # Does this column exists?
 867       if (!exists $This->{DataColLabelToNumMap}{$CompoundIDCol}) {
 868         carp "Warning: ${ClassName}->_ValidateReadCompoundIDCol: Column name, $CompoundIDCol, specified using CompoundIDCol doesn't exist...";
 869         return 0;
 870       }
 871       $CompoundIDColNum = $This->{DataColLabelToNumMap}{$CompoundIDCol};
 872     }
 873   }
 874 
 875   $This->{ValidCompoundIDCol} = 1;
 876   $This->{CompoundIDColNum} = $CompoundIDColNum;
 877   $This->{UseSequentialCompoundIDs} = $UseSequentialCompoundIDs;
 878 
 879   return 1;
 880 }
 881 
 882 # Validate fingerprints string column information...
 883 #
 884 sub _ValidateReadFingerprintsCol {
 885   my($This) = @_;
 886   my($FingerprintsColNum, $FingerprintsCol, $ColFound, $ColLabel, $ColNum);
 887 
 888   $This->{ValidFingerprintsCol} = 0;
 889   $This->{FingerprintsColNum} = undef;
 890 
 891   $FingerprintsColNum = undef;
 892   $FingerprintsCol = $This->{FingerprintsCol};
 893 
 894   if ($FingerprintsCol =~ /^AutoDetect$/i) {
 895     # First column containing the word Fingerprints in its label...
 896 
 897     $ColFound = 0;
 898     COLLABEL: for $ColLabel (@{$This->{DataColLabels}}) {
 899       if ($ColLabel =~ /Fingerprints/i) {
 900         $ColFound = 1;
 901         $ColNum = $This->{DataColLabelToNumMap}{$ColLabel};
 902         last COLLABEL;
 903       }
 904     }
 905     if (!$ColFound) {
 906       carp "Warning: ${ClassName}->_ValidateReadFingerprintsCol: Column label containing \"Fingerprints\" string in its name doesn't exist...";
 907       return 0;
 908     }
 909     $FingerprintsColNum = $ColNum;
 910   }
 911   else {
 912     if ($This->{ColMode} =~ /^ColNum$/i) {
 913       # Is it a valid column number?
 914       if ($FingerprintsCol > scalar @{$This->{DataColLabels}}) {
 915         carp "Warning: ${ClassName}->_ValidateReadFingerprintsCol: Column number, $FingerprintsCol, specified using FingerprintsCol doesn't exist...";
 916         return 0;
 917       }
 918       $FingerprintsColNum = $FingerprintsCol - 1;
 919     }
 920     elsif ($This->{ColMode} =~ /^ColLabel$/i) {
 921       # Does this column exists?
 922       if (!exists $This->{DataColLabelToNumMap}{$FingerprintsCol}) {
 923         carp "Warning: ${ClassName}->_ValidateReadFingerprintsCol: Column label, $FingerprintsCol, specified using FingerprintsCol doesn't exist...";
 924         return 0;
 925       }
 926       $FingerprintsColNum = $This->{DataColLabelToNumMap}{$FingerprintsCol};
 927     }
 928   }
 929 
 930   $This->{ValidFingerprintsCol} = 1;
 931   $This->{FingerprintsColNum} = $FingerprintsColNum;
 932 
 933   return 1;
 934 }
 935 
 936 # Validate fingerprints string mode information...
 937 #
 938 sub _ValidateReadFingerprintsStringMode {
 939   my($This) = @_;
 940   my($FingerprintsBitVectorStringMode, $FingerprintsVectorStringMode, $FirstFingerprintsStringType, $FirstFingerprintsStringDescription, $TextFile, $Line, $FingerprintsColNum, $InDelim, $FingerprintsType, $FingerprintsDescription, @LineWords);
 941 
 942   $This->{ValidFingerprintsStringMode} = 0;
 943 
 944   $This->{FingerprintsBitVectorStringMode} = 0;
 945   $This->{FingerprintsVectorStringMode} = 0;
 946 
 947   $This->{FirstFingerprintsStringType} = '';
 948   $This->{FirstFingerprintsStringDescription} = '';
 949 
 950   $FingerprintsBitVectorStringMode = 0;
 951   $FingerprintsVectorStringMode = 0;
 952 
 953   $FirstFingerprintsStringType = '';
 954   $FirstFingerprintsStringDescription = '';
 955 
 956   $TextFile = $This->{Name};
 957 
 958   if (!open TEXTFILE, "$TextFile") {
 959     croak "Error: ${ClassName}->New: Object can't be instantiated: Couldn't open input text file $TextFile: $! ...";
 960   }
 961 
 962   # Skip column label line...
 963   $Line = TextUtil::GetTextLine(\*TEXTFILE);
 964 
 965   # First first fingerprints data line...
 966   $Line = TextUtil::GetTextLine(\*TEXTFILE);
 967 
 968   close TEXTFILE;
 969 
 970   # Get first fingerprints type and description...
 971   $InDelim = $This->{Delim};
 972   @LineWords = TextUtil::SplitWords($Line, $InDelim);
 973 
 974   $FingerprintsColNum = $This->{FingerprintsColNum};
 975 
 976   ($FingerprintsType, $FingerprintsDescription) = Fingerprints::FingerprintsStringUtil::GetFingerprintsStringTypeAndDescription($LineWords[$FingerprintsColNum]);
 977 
 978   if ($This->{FingerprintsStringMode} =~ /^FingerprintsBitVectorString$/i) {
 979     if ($FingerprintsType !~ /^FingerprintsBitVector$/i) {
 980       carp "Warning: ${ClassName}->_ValidateReadFingerprintsStringMode: First fingerprint string data type, $FingerprintsType, doesn't match value, FingerprintsBitVectorString, specified using \"FingerprintsStringMode\"...";
 981       return 0;
 982     }
 983     $FingerprintsBitVectorStringMode = 1;
 984     $FirstFingerprintsStringType = 'FingerprintsBitVector';
 985     $FirstFingerprintsStringDescription = $FingerprintsDescription;
 986   }
 987   elsif ($This->{FingerprintsStringMode} =~ /^FingerprintsVectorString$/i) {
 988     if ($FingerprintsType !~ /^FingerprintsVector$/i) {
 989       carp "Warning: ${ClassName}->_ValidateReadFingerprintsStringMode: First fingerprint string data type, $FingerprintsType, doesn't match value, FingerprintsVectorString, specified using \"FingerprintsStringMode\"...";
 990       return 0;
 991     }
 992     $FingerprintsVectorStringMode = 1;
 993     $FirstFingerprintsStringType = 'FingerprintsVector';
 994     $FirstFingerprintsStringDescription = $FingerprintsDescription;
 995   }
 996   else {
 997     # AutoDetect mode...
 998     if ($FingerprintsType =~ /^FingerprintsBitVector$/i) {
 999       $FingerprintsBitVectorStringMode = 1;
1000     }
1001     elsif ($FingerprintsType =~ /^FingerprintsVector$/i) {
1002       $FingerprintsVectorStringMode = 1;
1003     }
1004     else {
1005       carp "Warning: ${ClassName}->_ValidateReadFingerprintsStringMode: First fingerprint string data type, $FingerprintsType, identified during, AutoDetect, value of \"FingerprintsStringMode\" is not valid; Supported fingerprints types: FingerprintBitVector or FingerprintsVector...";
1006       return 0;
1007     }
1008     $FirstFingerprintsStringType = $FingerprintsType;
1009     $FirstFingerprintsStringDescription = $FingerprintsDescription;
1010   }
1011 
1012   $This->{ValidFingerprintsStringMode} = 1;
1013 
1014   $This->{FingerprintsBitVectorStringMode} = $FingerprintsBitVectorStringMode;
1015   $This->{FingerprintsVectorStringMode} = $FingerprintsVectorStringMode;
1016 
1017   $This->{FirstFingerprintsStringType} = $FirstFingerprintsStringType;
1018   $This->{FirstFingerprintsStringDescription} = $FirstFingerprintsStringDescription;
1019 
1020   return 1;
1021 }
1022 
1023 # Write fingerprints string generated from specified fingerprints, fingerprints-bit vector, or
1024 # fingerprints vector object and other data to text file...
1025 #
1026 sub WriteFingerprints {
1027   my($This, $FingerprintsObject, @DataColValues) = @_;
1028 
1029   # Initialize data for current line...
1030   $This->_InitializeWriteDataLine();
1031 
1032   # Set fingerprints object...
1033   $This->{FingerprintsObject} = $FingerprintsObject;
1034 
1035   # Generate fingerprints string...
1036   $This->_GenerateFingerprintsString();
1037 
1038   # Set data line words...
1039   $This->SetDataLineWords(@DataColValues);
1040   push @{$This->{DataLineWords}}, $This->{FingerprintsString};
1041 
1042   # Write data line..
1043   $This->_WriteDataLine();
1044 
1045   return $This;
1046 }
1047 
1048 # Write fingerprints string and other data to text file...
1049 #
1050 # Note:
1051 #   o FingerprintsStringMode, BitStringFormat, BitsOrder, VectorStringFormat values
1052 #     are ignored during writing of fingerprints and it's written to the file as it is.
1053 #
1054 #
1055 sub WriteFingerprintsString {
1056   my($This, $FingerprintsString, @DataColValues) = @_;
1057 
1058   # Initialize data for current line...
1059   $This->_InitializeWriteDataLine();
1060 
1061   # Set fingerprints string...
1062   $This->{FingerprintsString} = $FingerprintsString;
1063 
1064   # Generate fingerprints object...
1065   $This->_GenerateFingerprintsObject();
1066 
1067   # Set data line words...
1068   $This->SetDataLineWords(@DataColValues);
1069   push @{$This->{DataLineWords}}, $FingerprintsString;
1070 
1071   # Write data line..
1072   $This->_WriteDataLine();
1073 
1074   return $This;
1075 }
1076 
1077 # Initialize data line for reading...
1078 #
1079 sub _InitializeWriteDataLine {
1080   my($This) = @_;
1081 
1082   $This->{DataLine} = undef;
1083   @{$This->{DataLineWords}} = ();
1084 
1085   $This->{FingerprintsObject} = undef;
1086   $This->{FingerprintsString} = undef;
1087 
1088   return $This;
1089 }
1090 
1091 # Write fingerprints data line line...
1092 #
1093 sub _WriteDataLine {
1094   my($This) = @_;
1095   my($FileHandle, $Line);
1096 
1097   if ($This->{FirstDataLineIO}) {
1098     $This->_ProcessFirstDataLineWrite();
1099   }
1100 
1101   # Write out line words...
1102   $Line = TextUtil::JoinWords(\@{$This->{DataLineWords}}, $This->{Delim}, $This->{OutQuote});
1103 
1104   $This->{LineNum} += 1;
1105   $FileHandle = $This->{FileHandle};
1106   print $FileHandle "$Line\n";
1107 
1108   $This->{DataLine} = $Line;
1109 
1110   return $This;
1111 }
1112 
1113 # Process first write...
1114 #
1115 sub _ProcessFirstDataLineWrite {
1116   my($This) = @_;
1117   my($Line, $FileHandle);
1118 
1119   $This->{FirstDataLineIO} = 0;
1120 
1121   if ($This->GetMode() =~ /^Write$/i) {
1122     # Write out column label line...
1123     $Line = TextUtil::JoinWords(\@{$This->{DataColLabels}}, $This->{Delim}, $This->{OutQuote});
1124 
1125     $This->{LineNum} += 1;
1126     $FileHandle = $This->{FileHandle};
1127     print $FileHandle "$Line\n";
1128   }
1129 
1130   return $This;
1131 }
1132 
1133 # Get ready for writing fingerprints text file...
1134 #
1135 sub _PrepareForWritingFingerprintsTextFileData {
1136   my($This) = @_;
1137   my($TextFile, $FileDir, $FileName, $FileExt, $OutDelim);
1138 
1139   $TextFile = $This->{Name};
1140   if (!$This->{Overwrite}) {
1141     if (-e $TextFile) {
1142       croak "Error: ${ClassName}->New: Object can't be instantiated: File, $TextFile, already exist. Use overwrite option...";
1143     }
1144   }
1145 
1146   # Set up delimiter for writing file...
1147 
1148   $FileDir = ""; $FileName = ""; $FileExt = "";
1149   ($FileDir, $FileName, $FileExt) = FileUtil::ParseFileName($TextFile);
1150 
1151   $OutDelim = ($FileExt =~ /^tsv$/i) ? "\t" : ($This->{OutDelim} =~ /semicolon/i ? "\;" : "\,");
1152   $This->{Delim} = $OutDelim;
1153 
1154   # Setup FingerprintsStringMode status...
1155 
1156   $This->{FingerprintsBitVectorStringMode} = 0;
1157   $This->{FingerprintsVectorStringMode} = 0;
1158   $This->{ValidFingerprintsStringMode} = 0;
1159 
1160   if ($This->{FingerprintsStringMode} =~ /^FingerprintsBitVectorString$/i) {
1161     $This->{FingerprintsBitVectorStringMode} = 1;
1162   }
1163   elsif ($This->{FingerprintsStringMode} =~ /^FingerprintsVectorString$/i) {
1164     $This->{FingerprintsVectorStringMode} = 1;
1165   }
1166 
1167   $This->{ValidFingerprintsStringMode} = ($This->{FingerprintsBitVectorStringMode} || $This->{FingerprintsVectorStringMode}) ? 1 : 0;
1168 
1169   if ($This->{FingerprintsBitVectorStringMode}) {
1170     $This->_SetDefaultBitStringFormat();
1171     $This->_SetDefaultBitsOrder();
1172   }
1173   elsif ($This->{FingerprintsVectorStringMode}) {
1174     $This->_SetDefaultVectorStringFormat();
1175   }
1176 
1177   return $This;
1178 }
1179 
1180 # Set default value for bit string format...
1181 #
1182 sub _SetDefaultBitStringFormat {
1183   my($This) = @_;
1184 
1185   if (!$This->{BitStringFormat}) {
1186     $This->{BitStringFormat} = Fingerprints::FingerprintsStringUtil::GetDefaultBitStringFormat();
1187   }
1188 
1189   return $This;
1190 }
1191 
1192 # Set default value for bit string format...
1193 #
1194 sub _SetDefaultBitsOrder {
1195   my($This) = @_;
1196 
1197   if (!$This->{BitsOrder}) {
1198     $This->{BitsOrder} = Fingerprints::FingerprintsStringUtil::GetDefaultBitsOrder();
1199   }
1200 
1201   return $This;
1202 }
1203 
1204 # Set default value for vector string format...
1205 #
1206 sub _SetDefaultVectorStringFormat {
1207   my($This) = @_;
1208 
1209   if (!$This->{VectorStringFormat} && $This->{FingerprintsObject}) {
1210     $This->{VectorStringFormat} = Fingerprints::FingerprintsStringUtil::GetDefaultVectorStringFormat($This->{FingerprintsObject});
1211   }
1212 
1213   return $This;
1214 }
1215 
1216 # Generate fingerprints object using current fingerprints string...
1217 #
1218 sub _GenerateFingerprintsObject {
1219   my($This) = @_;
1220 
1221   $This->{FingerprintsObject} = undef;
1222 
1223   if (!$This->{FingerprintsString}) {
1224     return $This;
1225   }
1226 
1227   if ($This->{FingerprintsBitVectorStringMode}) {
1228     $This->{FingerprintsObject} = Fingerprints::FingerprintsStringUtil::ParseFingerprintsBitVectorString($This->{FingerprintsString});
1229   }
1230   elsif ($This->{FingerprintsVectorStringMode}) {
1231     $This->{FingerprintsObject} = Fingerprints::FingerprintsStringUtil::ParseFingerprintsVectorString($This->{FingerprintsString});
1232   }
1233   else {
1234     return undef;
1235   }
1236 
1237   return $This;
1238 }
1239 
1240 # Generate fingerprints string using current fingerprints object...
1241 #
1242 sub _GenerateFingerprintsString {
1243   my($This) = @_;
1244 
1245   $This->{FingerprintsString} = '';
1246 
1247   if (!$This->{FingerprintsObject}) {
1248     return $This;
1249   }
1250 
1251   if ($This->{FingerprintsBitVectorStringMode}) {
1252     $This->{FingerprintsString} = Fingerprints::FingerprintsStringUtil::GenerateFingerprintsString($This->{FingerprintsObject}, $This->{BitStringFormat}, $This->{BitsOrder});
1253   }
1254   elsif ($This->{FingerprintsVectorStringMode}) {
1255     $This->{FingerprintsString} = Fingerprints::FingerprintsStringUtil::GenerateFingerprintsString($This->{FingerprintsObject}, $This->{VectorStringFormat});
1256   }
1257 
1258   return $This;
1259 }
1260 
1261 # Is it a fingerprints file?
1262 sub IsFingerprintsTextFile ($;$) {
1263   my($FirstParameter, $SecondParameter) = @_;
1264   my($This, $FileName, $Status);
1265 
1266   if ((@_ == 2) && (_IsFingerprintsTextFileIO($FirstParameter))) {
1267     ($This, $FileName) = ($FirstParameter, $SecondParameter);
1268   }
1269   else {
1270     $FileName = $FirstParameter;
1271   }
1272 
1273   # Check file extension...
1274   $Status = FileUtil::CheckFileType($FileName, "csv tsv");
1275 
1276   return $Status;
1277 }
1278 
1279 # Is it a FingerprintsTextFileIO object?
1280 sub _IsFingerprintsTextFileIO {
1281   my($Object) = @_;
1282 
1283   return (Scalar::Util::blessed($Object) && $Object->isa($ClassName)) ? 1 : 0;
1284 }
1285