# Copyright 2008-2014 Cumulus Systems Incorporated.
# All Rights Reserved.

# This class provides function to read property files containing probe related information.

# Name of the Package.
package commonPropFileModule;

# It is used for strict compilation.
use strict;

# It helps in debugging.
use warnings;

# This is required for logging information.
use commonLogModule;

# This is required for reading the base file name.
use File::Basename;

# ---------------------------------------------------------------------------------------------------------------------------------------------------
# GLOBAL Variables
# ---------------------------------------------------------------------------------------------------------------------------------------------------
# This Hashmap stores the probe specific property keys and its value.
my %probePropKeyToValue = ();

# This Hashmap stores the app property keys and its value.
my %appPropKeyToValue = ();

# This stores an instance of commonPropFileModule class.
my $commPropModule = undef;

# --------------------------------------------------------------------------------------------------------------------------------------------------
# Sub-routines
# --------------------------------------------------------------------------------------------------------------------------------------------------
# Constructor of class commonPropFileModule.
#
# @param :
#   $_[0] - [In] Class name.
#   $_[1] - [In] Base Folder.
#   $_[2] - [In] Probe Type like NetApp.
#   $_[3] - [In] Probe Id "192.168.20.100".
#   $_[4] - [In] Instance of commonLogModule.
#
# @affected global variables :
#   None
#
# @return :
#   Instance of commonPropFileModule class.
sub getInstance {
    # This variable stores package name.
    my $class = $_[0];

    # This variable stores MARS folder name.
    my $baseFolder = $_[1];

    # This variable stores probe type.
    my $probeType = $_[2];

    # This variable stores probe id.
    my $probeId = $_[3];

    # Get commonLogModule instance.
    my $logObject = $_[4];

    # Create class instance.
    $commPropModule = bless {
        probeType => $probeType,
        probeId => $probeId,
        logObj => $logObject,
        baseFolder => $baseFolder,
    }, shift unless $commPropModule;

    return $commPropModule;
}

# This function is used to return value of a Probe specific property. It reads the Property value from Probe's default properties file and then from Probe
# instance specific properties file.
#
# @param :
#   $_[0] - [In] Reference to the object.
#   $_[1] - [In] Property name
#   $_[2] - [Out] Property value
#
# @affected global variables :
#   None
#
# @return :
#   0 if found correct information.
#   1 if not found correct information.
sub getProbeProperty {
    # This variable is used to store the return value of function calls.
    my $retVal = 0;

    # Read input property name.
    my $propertyName = $_[1];

    # This variable stores property value.
    my $propertyValue = "";

    # Populate the map containing the property names and corresponding values, if found empty.
    if (!%probePropKeyToValue) {
        $_[0]->populateProbePropMap();
    }

    $propertyValue = $probePropKeyToValue{$propertyName};
    if ("" eq $propertyValue) {
        $_[0]->{logObj}->error("Property [$propertyName] not found.");

        $retVal = 1;
    } else {
        $_[0]->{logObj}->info("[$propertyName] value found as: [$propertyValue].");

        $_[2] = $propertyValue;
    }

EXIT:

    return $retVal;
}

# This function is used to read a property value from properties file. It read the properties files in following sequence:
#   app.properties
#   sys/*.properties
#   custom.properties
#   custom/*.properties
#
# @param :
#   $_[0] - [In] Reference to the object.
#   $_[1] - [In] Property name
#   $_[2] - [Out] Property value
#
# @affected global variables :
#   None
#
# @return :
#   0 if found correct information.
#   1 if not found correct information.
sub getAppProperty {
    # This variable is used to store the return value of function call.
    my $retVal = 0;

    # This variable stores probe type.
    my $probeType = lc($_[0]->{probeType});

    # This variable stores probe id.
    my $probeId = lc($_[0]->{probeId});

    # This variable stores the name of the property to be fetched.
    my $propertyName = $_[1];

    # This variable stores the value of the property to be fetched.
    my $propertyValue = "";

    # Populate the map containing the property names and corresponding values, if found empty.
    if (!%appPropKeyToValue) {
        $_[0]->populateAppPropertyMap();
    }

    $propertyValue = $appPropKeyToValue{$propertyName};
    if ("" eq $propertyValue) {
        $_[0]->{logObj}->error("[$propertyName] is not present in the properties files.");
        $retVal = 1;
    } else {
        $_[0]->{logObj}->info("[$propertyName] value found as: [$propertyValue].");
        $_[2] = $propertyValue;
    }

EXIT:

    return $retVal;
}

# This function is used to populate "appPropKeyToValue" map. It read the properties files in following sequence:
#   app.properties
#   sys/*.properties
#   custom.properties
#   custom/*.properties
#
# @param :
#   $_[0] - [In] Reference to the object.
#
# @affected global variables :
#   %appPropKeyToValue
#
# @return :
#   None.
sub populateAppPropertyMap {
    # This array stores the list of property files.
    my @propertyFileArray = ();

    # This variable stores MARS folder.
    my $baseFolder = $_[0]->{baseFolder};

    # Set the complete path of MARS app.properties file.
    my $appPropertiesFilePath = $baseFolder."/conf/app.properties";

    # Set sys folder name.
    my $sysFolderPath = $baseFolder."/conf/sys";

    # Set the complete path of MARS custom.properties file.
    my $customPropertiesFilePath = $baseFolder."/conf/custom.properties";

    # Set custom folder name.
    my $customFolderPath = $baseFolder."/conf/custom";

    # Put app.properties file at beginning of array since we need to search the property name in the given order.
    push(@propertyFileArray, $appPropertiesFilePath);

    # If "sys" folder exists then take all its property file in an array.
    if (-d $sysFolderPath) {
        push(@propertyFileArray, glob($sysFolderPath."/*.properties"));
    }

    # Put custom.properties file in the array.
    push(@propertyFileArray, $customPropertiesFilePath);

    # If custom folder exists then take all its property file in an array.
    if (-d $customFolderPath) {
        push(@propertyFileArray, glob($customFolderPath."/*.properties"));
    }

    foreach my $propertyFileName (@propertyFileArray) {
        $_[0]->{logObj}->debug("Reading property file: [$propertyFileName].");

        # Opening the property file.
        open(my $PROP_FILE, $propertyFileName) or die $_[0]->{logObj}->error("Not able to open the file: [$propertyFileName].");

        # Loop through the content of property file.
        while (<$PROP_FILE>) {
            # Remove the new line character.
            $_ =~ s/\r\n//g;
            $_ =~ s/\n//g;

            # Remove leading and trailing spaces from each line.
            $_ =~ s/^\s+|\s+$//g;

            # Look for the given property.
            if ($_ =~ /^(\s*)(.+)=(\s*)(.+)(\s*)$/) {
                $appPropKeyToValue{$2} = $4;
            } else {
                # Current line is of no use. So ignore it.
            }
        }

        close($PROP_FILE);
    }
}

# This function is used to populate "probePropKeyToValue" map.
#
# @param :
#   $_[0] - [In] Reference to the object.
#
# @affected global variables :
#   %probePropKeyToValue
#
# @return :
#   None.
sub populateProbePropMap {
    # Read input probe type.
    my $probeType = lc($_[0]->{probeType});

    # Read input probe id.
    my $probeId = $_[0]->{probeId};

    # Get property file name folder.
    my $propertyFileFolder = $_[0]->{baseFolder}."/conf/probe/";

    # This variable tells whether the given file is probe instance property file or not.
    my $isProbeInstanceFile = 0;

    # This variable is used to keep track of which property file needs to be parsed.
    my $isReadfile = 0;

    # This variable stores the base file name.
    my $baseFileName = "";

    my @files = glob($propertyFileFolder."*.properties");

    $_[0]->{logObj}->debug("Searching for Probe default property file.");

    foreach my $propertyFileName (@files) {
        $_[0]->{logObj}->debug("Probe specific property file: [$propertyFileName].");

        $baseFileName = basename($propertyFileName);

        if (($baseFileName =~ /^(?i)$probeType(_)default.properties(\s*)$/)) {
            $_[0]->{logObj}->debug("Reading Probe default property file: [$propertyFileName].");

            # Opening the probe specific property file.
            open(my $PROP_FILE, $propertyFileName) or die $_[0]->{logObj}->error("Not able to open the file: [$propertyFileName].");

            # Loop through the content of properties file.
            while (<$PROP_FILE>) {
                # Remove the new line character.
                $_ =~ s/\r\n//g;
                $_ =~ s/\n//g;

                # Remove leading and trailing spaces from each line.
                $_ =~ s/^\s+|\s+$//g;

                # Look for input property.
                if ($_ =~ /^(\s*)(.+)=(\s*)(.+)(\s*)$/) {
                    $probePropKeyToValue{$2} = $4;
                } else {
                    # Current line is of no use. So ignore it.
                }
            }

            close($PROP_FILE);

            last;
        }
    }

    $_[0]->{logObj}->debug("Searching for Probe instance property files.");

    foreach my $propertyFileName (@files) {
        $_[0]->{logObj}->debug("Probe specific property file: [$propertyFileName].");

        $baseFileName = basename($propertyFileName);

        if ($baseFileName =~ /^(?i)$probeType(_)(.+)_$probeId.properties(\s*)$/) {
            $_[0]->{logObj}->debug("Reading Probe instance property file: [$propertyFileName].");

            # Opening the probe specific property file.
            open(my $PROP_FILE, $propertyFileName) or die $_[0]->{logObj}->error("Not able to open the file: [$propertyFileName].");

            # Loop through the content of properties file.
            while (<$PROP_FILE>) {
                # Remove the new line character.
                $_ =~ s/\r\n//g;
                $_ =~ s/\n//g;

                # Remove leading and trailing spaces from each line.
                $_ =~ s/^\s+|\s+$//g;

                # Look for input property.
                if ($_ =~ /^(\s*)(.+)=(\s*)(.+)(\s*)$/) {
                    $probePropKeyToValue{$2} = $4;
                } else {
                    # Current line is of no use. So ignore it.
                }
            }

            close($PROP_FILE);

            last;
        }
    }
}

# The file must return true ("1") as the last statement to indicate successful execution of any initialization code. So it's customary to end such a
# file with 1 unless we are sure that we will return true otherwise. But it's better just to put the 1;, in case we add more statements.
1;