package Cyber::Base;
use strict;
use warnings;
no warnings 'uninitialized';

use CGI;
use Config::General;
use Data::Dumper;
use JSON;
use Template;
use DBIx::Abstract;
use CGI::Session;
use CGI::Cookie; 
use Cyber::Database;

use Crypt::CBC;
use Cache::Memcached::Fast;
use IO::Compress::Gzip;
use IO::Uncompress::Gunzip;
use Date::Calc qw(:all);
use MIME::Base64;
use Digest::MD5 qw(md5 md5_hex md5_base64);

our $ROOT_PATH = '/home/dell/Work/quotationfront';
if ( !defined $ENV{'DOCUMENT_ROOT'} || $ENV{'DOCUMENT_ROOT'} =~ /^\s*$/ || $ENV{'DOCUMENT_ROOT'} =~ /^\/$/ ) {
	$ENV{'DOCUMENT_ROOT'} = $ROOT_PATH;
}
if ( $ENV{'SERVER_NAME'} =~ /localhost/i && $ENV{'DOCUMENT_ROOT'} !~ /quotationfront/ ) {
	$ENV{'DOCUMENT_ROOT'} .= '/quotationfront';
}

my $configfile = $ENV{'DOCUMENT_ROOT'}.'/Conf/application.cfg';
$main::dbi_handles = (); # Global DBI handles
#%main::databases = (); # Global DBI handles
#$main::defaultdb = undef;
%main::config = ();
%main::lang = ();
$main::obj_cgi = undef;
$main::digit_month = undef;
$main::digit_dow = undef;
$main::single_digit_dow = undef;
$main::obj_memcached = undef;
#$main::obj_template = {};
$main::session_data = {};
#$main::country_list = {};
#$mail::config_master = {};

#create memcached object
sub main::create_memcached_obj {
	$main::obj_memcached = new Cache::Memcached::Fast({
	   servers => [ { address => 'localhost:11211', weight => 2.5 } ],
	   namespace => 'my:',
	   connect_timeout => 0.2,
	   io_timeout => 0.5,
	   close_on_error => 1,
	   compress_threshold => 100_000,
	   compress_ratio => 0.9,
	   compress_methods => [ \&IO::Compress::Gzip::gzip,
	                         \&IO::Uncompress::Gunzip::gunzip ],
	   max_failures => 3,
	   failure_timeout => 2,
	   ketama_points => 150,
	   nowait => 1,
	   hash_namespace => 1,
	   serialize_methods => [ \&Storable::freeze, \&Storable::thaw ],
	   utf8 => ($^V ge v5.8.1 ? 1 : 0),
	   max_size => 1024 * 1024,
	});
}

#Collect all config parameters
sub main::config_params {
	##if config file not found
	unless ( -e $configfile ) {
		if ( !defined $ENV{'DOCUMENT_ROOT'} || $ENV{'DOCUMENT_ROOT'} =~ /^\s*$/ || $ENV{'DOCUMENT_ROOT'} =~ /^\/$/ ) {
			$ENV{'DOCUMENT_ROOT'} = $ROOT_PATH;
		}
		if ( $ENV{'SERVER_NAME'} =~ /localhost/i && $ENV{'DOCUMENT_ROOT'} !~ /quotationfront/ ) {
			$ENV{'DOCUMENT_ROOT'} .= '/quotationfront';
		}

		$configfile = $ENV{'DOCUMENT_ROOT'}.'/Conf/application.cfg';
	}

	my $cg = new Config::General($configfile);
	my %config = %::config = $cg->getall();

	foreach my $key ( keys %config ) {
		my $sub_config = $config{$key};
		foreach my $key2 ( keys %$sub_config ) {
			if ( $sub_config->{$key2} ) {
				my $temp = $sub_config->{$key2};
				if ( $temp =~ /DOCROOT/i ) {
					$temp =~ s/DOCROOT/$ENV{'DOCUMENT_ROOT'}/g;
				}
				$sub_config->{$key2} = $temp;
			}
		}
	}

	my $lang_file = $ENV{'DOCUMENT_ROOT'}.'/Conf/en.cfg';

	my $lang = new Config::General($lang_file);
	my %lang = %::lang = $lang->getall();
}

#Collect all CGI Params
sub main::cgi_params {
	my $obj_cgi = $main::obj_cgi = CGI->new;
	
	my $img_handle = $obj_cgi->upload('image');
	my $cgi_params = {};
	
	if ( $ENV{'REQUEST_METHOD'} =~ /GET/i ) {
		for my $name ( $obj_cgi->url_param ) {
			for my $val ( $obj_cgi->url_param($name) ) {
				$cgi_params->{$name} = $val;
			}
		}
	}
	elsif ( $ENV{'REQUEST_METHOD'} =~ /POST/i ) {
		for my $name ( $obj_cgi->param ) {
			for my $val ( $obj_cgi->param($name) ) {
				$cgi_params->{$name} = $val;
			}
		}

		for my $name ( $obj_cgi->url_param ) {
			for my $val ( $obj_cgi->url_param($name) ) {
				unless ( exists $cgi_params->{$name} ) {
					$cgi_params->{$name} = $val;
				}
			}
		}
	}
	else {
		for my $name ( $obj_cgi->param ) {
			for my $val ( $obj_cgi->param($name) ) {
				$cgi_params->{$name} = $val;
			}
		}
		
		for my $name ( $obj_cgi->url_param ) {
			for my $val ( $obj_cgi->url_param($name) ) {
				$cgi_params->{$name} = $val;
			}
		}
	}
	
	$obj_cgi->{'params'} = $cgi_params;
	
	##Validate Params
	##Craete Databae Object
	#my $obj_valid = new Cyber::Valid;
	#
	#$obj_valid->valid_param();
	#
	#if ( exists $obj_valid->{'error'} ) {
	#	::log($obj_valid->{'error'});
	#}
	#
	$cgi_params->{'cgi_object'} = $obj_cgi;
	
	return $cgi_params;
}

#Create Template Constructor
sub main::template {
	#Create Template Objects
	
	my $config_template = {
		INCLUDE_PATH => $ENV{'DOCUMENT_ROOT'}."/Templates",  # or list ref
		INTERPOLATE  => 1,               # expand "$var" in plain text
		POST_CHOMP   => 1,               # cleanup whitespace
		PRE_PROCESS  => '',              # prefix each template
		EVAL_PERL    => 1,               # evaluate Perl code blocks
	};
	
	my $constant = {
		'root' => $::config{'root'},
		'root_path' => $::config{'root_path'}
	};
	$main::obj_template = Template->new($config_template, CONSTANTS => $constant);
	
	#Absoulute path
	#Create Template Objects
	my $config_abs_template = {
		INCLUDE_PATH => '',  # or list ref
		INTERPOLATE  => 1,               # expand "$var" in plain text
		POST_CHOMP   => 1,               # cleanup whitespace
		PRE_PROCESS  => '',              # prefix each template
		EVAL_PERL    => 1,               # evaluate Perl code blocks
		ABSOLUTE     => 1
	};
	
	$main::obj_abs_template = Template->new($config_abs_template, CONSTANTS => $constant);
}

#Create Template Constructor
sub main::channel_template {
	#Create Template Objects
	
	my $config_template = {
		INCLUDE_PATH => $ENV{'DOCUMENT_ROOT'}."/Channel/Templates",  # or list ref
		INTERPOLATE  => 1,               # expand "$var" in plain text
		POST_CHOMP   => 1,               # cleanup whitespace
		PRE_PROCESS  => '',              # prefix each template
		EVAL_PERL    => 1,               # evaluate Perl code blocks
	};

	$main::obj_channel_template = Template->new($config_template);
}

#Global Variable
sub main::render_template {
	my $template = shift;
	my $vars     = shift;

	unless ( defined $::obj_template ) {
		::template();
	}
	
	$::obj_template->process($template, $vars) ||
		die "Template process failed: ", $::obj_template->error(), "\n";
}

#Global Variable
sub main::process_template {
	my $template = shift;
	my $vars     = shift;
	my $output_content = '';
	
	unless ( defined $::obj_template ) {
		::template();
	}

	$::obj_template->process($template, $vars, \$output_content) ||
		die "Template process failed: ", $::obj_template->error(), "\n";
		
	return $output_content;
}

#Global Variable
sub main::process_channel_template {
	my $template = shift;
	my $vars     = shift;
	my $output_content = '';
	
	unless ( defined $::obj_channel_template ) {
		::channel_template();
	}

	$::obj_channel_template->process($template, $vars, \$output_content) ||
		die "Template process failed: ", $::obj_channel_template->error(), "\n";
		
	return $output_content;
}

#Database Connection
sub main::connect_database {
	my $dbi = $::config{'dbi'};

	my $dsn = "DBI:mysql:database=$dbi->{'database'};host=$dbi->{'host'};";

	my $dbh = DBIx::Abstract->connect({
		'dbname'   => $dbi->{'database'},
		'dsn'      => $dsn, 
		'user'     => $dbi->{'user'}, 
		'password' => $dbi->{'password'},
	});
	
	$::dbi_handles->{'main_dbh'} = $dbh;
}

#Convert Date Format
sub convert_date_format {
	my $date = shift;
	my $current_format = shift;
	my $required_format = shift;
	
	my ($current_split) = $current_format =~ /[^0-9a-zA-Z]/g;
	my ($required_split) = $required_format =~ /[^0-9a-zA-Z]/g;

	my $converted_date = '';
	if ( $current_split !~ /^\s*$/ ) {
		my ($f1, $f2, $f3) = split($current_split, $current_format);

		my ($d1, $d2, $d3) = split($current_split, $date);
		
		my $format = {
			$f1 => $d1,
			$f2 => $d2,
			$f3 => $d3
		};

		my @rfs = split($required_split, $required_format);
		if ( scalar @rfs ) {
			foreach my $rf ( @rfs ) {
				$converted_date .= $format->{$rf}.$required_split;
			}
		}
		chop($converted_date);
	}
	return $converted_date;
}

sub main::create_session {
	my $obj_cgi = CGI->new();

	my $session = new CGI::Session($obj_cgi);
	
	print $session->header();
	
	#setting session to expire in 1 hour                              
	# $session->expire(120);
	
	#store something                         
	$session->param( "config_param", {%::config} );
	
	# write to disk                                 
	# $session->flush();                           
	
	# my $cookie1 = new CGI::Cookie(-name=>'CGISESSID', -value=>$session->id);

	# print $::obj_cgi->header(-cookie => $cookie1);

}

sub main::save_session_param {
	my $response_hash = shift;
	
	if ( ref $response_hash ne 'HASH' ) {
		die "Pass Hash value in store session param";
	}
	
	my $sid = $::obj_cgi->cookie('CGISESSID') || $::obj_cgi->param('CGISESSID') || undef;

	my $session = load CGI::Session(undef, $sid, { Directory=>"/tmp" });
	
	#store something
	if ( defined $session->param("session_param") ) {
		my $temp_data =$session->param("session_param");
		foreach my $key ( keys %$response_hash ) {
			$temp_data->{$key} = $response_hash->{$key};
		}
		$session->param( "session_param", $temp_data );
	}
	else {
		$session->param( "session_param", $response_hash );
	}
	
	#setting session to expire in 1 hour                              
	# $session->expire(120);
	
	#write to disk                                 
	$session->flush();                           
	
	my $cookie1 = new CGI::Cookie(-name=>'CGISESSID', -value=>$session->id);

	$::obj_cgi->header(-cookie => $cookie1);
}

sub main::collect_session_param {
	my $key = shift;
	
	my $sid = $::obj_cgi->cookie('CGISESSID') || $::obj_cgi->param('CGISESSID') || undef;

	my $session = load CGI::Session(undef, $sid, { Directory=>"/tmp" });

	if ( defined $session->param("session_param") ) {
		if ( defined $key ) {
			return $session->param("session_param")->{$key};
		}
		else {
			$::session_data = $session->param("session_param");
		}
	}
	else {
		return undef;
	}
}

sub main::jquery_json_response {
	my $response_hash = shift;
	
	eval {
		my $json_response = to_json($response_hash);
		$main::obj_cgi->header(-type => "application/json", -charset => "utf-8");
		print $json_response;
	};
	if ( $@ ) {
		::log("error", $@);
		print 'system error';
	}
}

sub main::decode_json_data {
	my $response_json = shift;
	
	my $hash_response = {};
	eval {
		$hash_response = from_json($response_json);
	};
	if ( $@ ) {

	}
	return $hash_response;
}

sub main::encode_json_data {
	my $response_hash = shift;
	
	my $response_json = undef;
	eval {
		$response_json = to_json($response_hash);
	};
	if ( $@ ) {

	}
	return $response_json;
}

sub main::log {
	my (@data) = @_;
	my $log = '';
	foreach my $i (@data)
	{
		if (ref($i))
		{
			$log .= Dumper($i);
		}
		else
		{
			$i =~ s/\n$//;
			$log .= "$i\n";
		}
	}
	
	open(my $fh, '>>', $ENV{'DOCUMENT_ROOT'}."/logs/log.txt");
	print $fh $log;
	close $fh;
	# print STDERR $log;
}

#Fetch Data from memcached
sub main::fetch_memcached_data {
	my $parent_key = shift;
	my @keys = @_;

	unless ( defined $::obj_memcached ) {
		::create_memcached_obj();
	}
	
	# $::obj_memcached->flush_all;

	my $temp;
	if ( defined $::obj_memcached->get($parent_key) ) {
		$temp = $::obj_memcached->get($parent_key);
	}
	
    if ( scalar @keys ) {
        foreach my $key ( @keys ) {
            if ( exists $temp->{$key} ) {
                $temp = $temp->{$key};
            }
            else {
                return undef;
            }
        }
        return $temp;
    }
    else {
        return $temp;
    }
}

sub main::store_memcached_data {
	my $parent_key = shift;
	my $child_key  = shift;
    my $data       = shift;

    unless ( defined $::obj_memcached ) {
		::create_memcached_obj();
	}

	# $::obj_memcached->flush_all;
	
    if ( defined $child_key && $child_key !~ /^\s*$/ ) {
        if ( defined $::obj_memcached->get($parent_key) ) {
            my $temp = $::obj_memcached->get($parent_key);
            if ( ref $temp eq 'HASH' ) {
                $temp->{$child_key} = $data;
            }
           
            $::obj_memcached->set($parent_key, $temp);
        }
        else {
            $::obj_memcached->set($parent_key, {$child_key => $data});
        }
    }
    else {
        if ( defined $::obj_memcached->get($parent_key) ) {
            $::obj_memcached->replace($parent_key, $data);
        }
        else {
            $::obj_memcached->set($parent_key, $data);
        }
    }
}

# This method uses Crypt::CBC module for encrypting the CCNumber.
sub main::encrypt_string {
	my $string = shift;
	$string =~ s/^\s*//g;
	$string =~ s/\s*$//g;
	
	$string = encode_base64($string);
	
	my $DEK = "fai._o1la3DmLd,lok1qx7986nsdk.aX";
	
	my $cipher_text = Crypt::CBC->new({
		key         => $DEK, # 256 bits
		cipher      => "Crypt::Rijndael",
		header      => "salt",
		padding     => "space",
		pcbc        => 1,
	});
		
	my $encrypt_string = $cipher_text->encrypt($string);
	
	my $encoded_encrypt_string = encode_base64($encrypt_string);
	
	return $encoded_encrypt_string;
}

# This method uses Crypt::CBC module for Decrypting the CCNumber.
sub main::decrypt_string {
	my $string = shift;
	
	my $original_string = $string;

	$string = decode_base64($string);
	
	my $DEK = "fai._o1la3DmLd,lok1qx7986nsdk.aX";
	
	my $cipher_text = Crypt::CBC->new({
		key         => $DEK, # 256 bits
		cipher      => "Crypt::Rijndael",
		header      => "salt",
		padding     => "space",
		pcbc        => 1,
	});
		
	my $decoded_decrypt_string = undef;
	eval {
		my $decrypt_string = $cipher_text->decrypt($string);
		
		$decoded_decrypt_string = decode_base64($decrypt_string);
		
		$decoded_decrypt_string =~ s/^\s*//g;
		$decoded_decrypt_string =~ s/\s*$//g;
	};
	if ( $@ ) {
		$decoded_decrypt_string = $original_string;
	}
	return $decoded_decrypt_string;
}

sub main::encrypt_second_level {
	my $master_key = shift;
	my $string1    = shift;
	my $string2    = shift;

	# ##Static 32 bit MEK
    # my $master_key = 'fai._o1la3DmLd,lok1qx7986nsdk.aX';

    ##Generate 32 bit dynamic key
    my $string_gen  = String::Random->new;
    my $dynamic_key = $string_gen->randregex('.{32}');

    my $encrypted_string1 = undef;
    my $encrypted_string2 = undef;
    my $encrypted_string3 = undef;

    eval {
	    my $cbc_object1 = Crypt::CBC->new({
	        key         => $dynamic_key,
	        cipher      => "Crypt::Rijndael",
	        header      => "salt",
	        padding     => "space",
	        pcbc        => 1,
	    });

	    $encrypted_string1 = encode_base64($cbc_object1->encrypt($string1));
	};

	eval {
	    if ( $string2 !~ /^\s*$/ ) {
	    	my $cbc_object2 = Crypt::CBC->new({
		        key         => $dynamic_key,
		        cipher      => "Crypt::Rijndael",
		        header      => "salt",
		        padding     => "space",
		        pcbc        => 1,
		    });

		    $encrypted_string2 = encode_base64($cbc_object2->encrypt($string2));
	    }
	};
    
    eval {
	    my $cbc_object3 = Crypt::CBC->new({
	        key         => $master_key,
	        cipher      => "Crypt::Rijndael",
	        header      => "salt",
	        padding     => "space",
	        pcbc        => 1,
	    });

	    $encrypted_string3 = encode_base64($cbc_object3->encrypt($dynamic_key));
	};

    return ( $encrypted_string1, $encrypted_string2, $encrypted_string3 );
}

sub main::decrypt_second_level {
	my $master_key = shift;
	my $encrypted_string1 = shift;
	my $encrypted_string2 = shift;
	my $encrypted_string3 = shift;

	my $string1 = undef;
	my $string2 = undef;
	my $string3 = undef;

	##Static 32 bit MEK
    # my $master_key = 'fai._o1la3DmLd,lok1qx7986nsdk.aX';

    if ( defined $encrypted_string3 && $encrypted_string3 !~ /^\s*$/ ) {
    	eval {
		    my $cbc_object3 = Crypt::CBC->new({
		        key         => $master_key, # 256 bits
		        cipher      => "Crypt::Rijndael",
		        header      => "salt",
		        padding     => "space",
		        pcbc        => 1,
		    });

		    $string3 = $cbc_object3->decrypt(decode_base64($encrypted_string3));
		        
		    $string3 =~ s/^\s*//g;
		    $string3 =~ s/\s*$//g;
		};
		if ( $@ ) {
			::log( $@ );
		}
	}
	
	if ( defined $string3 && defined $encrypted_string1 && $encrypted_string1 !~ /^\s*$/ ) {
		eval {
		    my $cbc_object1 = Crypt::CBC->new({
		        key         => $string3, # 256 bits
		        cipher      => "Crypt::Rijndael",
		        header      => "salt",
		        padding     => "space",
		        pcbc        => 1,
		    });
		        
		    $string1 = $cbc_object1->decrypt(decode_base64($encrypted_string1));
		        
		    $string1 =~ s/^\s*//g;
		    $string1 =~ s/\s*$//g;
		};
		if ( $@ ) {
			::log( $@ );
		}
	}
	
	if ( defined $string3 && defined $encrypted_string2 && $encrypted_string2 !~ /^\s*$/ ) {
		eval {
		    my $cbc_object2 = Crypt::CBC->new({
		        key         => $string3, # 256 bits
		        cipher      => "Crypt::Rijndael",
		        header      => "salt",
		        padding     => "space",
		        pcbc        => 1,
		    });
		        
		    $string2 = $cbc_object2->decrypt(decode_base64($encrypted_string2));
		        
		    $string2 =~ s/^\s*//g;
		    $string2 =~ s/\s*$//g;
		};
		if ( $@ ) {
			::log( $@ );
		}
	}

	return ( $string1, $string2 );
}

sub main::generate_random_key {
	my $string_rand = new String::Random();
	
	my $random_key = $string_rand->randregex('[0-9]{12}');
	$random_key .= time();
	
	$random_key =~ s/^0+//;
	
	return $random_key;
}

sub main::generate_channel_update_queue {
	my $updated_hash = shift;

	#Collect all files
	my $update_string_path = $::config{'update_string'}->{'path'};

	eval{
		my $today = ::get_today_day();
		my $fn = "rate_update_log_".$today.".txt";
		my $rate_file_path = $ENV{'DOCUMENT_ROOT'}."/logs/$fn";
		my $server_time = ::get_server_time();

        open(FHR, ">>", $rate_file_path);
        print FHR "Time: $server_time :::";
        print FHR Dumper $updated_hash;
        print FHR "Updated path: $update_string_path";
        print FHR "\n";
        close(FHR);
    };

	my $file_path = undef;
	my $ticket_number = undef;
	while ( 1 ) {
	    #Create random number
	    my $time = time();

	    my $string_rand = new String::Random();
	    my $random_number = $string_rand->randregex('[0-9]{6}');

	    $ticket_number = $time.$random_number;

	    $file_path = $update_string_path."/$ticket_number.xml";

	    unless ( -e $file_path ) {
	        last;
	    }
	}
	
	eval{
		my $today = ::get_today_day();
		my $fn = "rate_update_log_".$today.".txt";
		my $rate_file_path = $ENV{'DOCUMENT_ROOT'}."/logs/$fn";
		my $server_time = ::get_server_time();

        open(FHR, ">>", $rate_file_path);
        print FHR "Time: $server_time :::";
        print FHR "Ticket Number: $ticket_number";
        print FHR "\n";
        close(FHR);
    };

	#Store in text string
	if ( scalar keys %$updated_hash ) {
	    foreach my $property_id ( sort keys %$updated_hash ) {

	        my $room_type_data = $updated_hash->{$property_id};

	        foreach my $room_type_id ( sort keys %$room_type_data ) {
	            my $update_type_data = $room_type_data->{$room_type_id};

	            foreach my $update_type ( sort keys %$update_type_data ) {
	                if ( $update_type =~ /^A$/i ) {
	                    my $channel_id_data = $update_type_data->{$update_type};
	                    my $rate_plan_id = 0;
	                    
	                    foreach my $channel_id ( sort keys %$channel_id_data ) {
	                        my $date_string = $channel_id_data->{$channel_id};
	                        $date_string =~ s/,$//;

	                        my $string = $property_id.'::'.$room_type_id.'::'.$update_type.'::'.$rate_plan_id.'::'.$channel_id.'::'.$date_string;
	                        eval{
	                            open(FH, ">>", $file_path);
	                            print FH $string;
	                            print FH "\n";
	                            close(FH);
	                        };
	                    }
	                }
	                else {
	                    my $rate_plan_data = $update_type_data->{$update_type};

	                    foreach my $rate_plan_id ( sort keys %$rate_plan_data ) {
	                        my $channel_id_data = $rate_plan_data->{$rate_plan_id};

	                        foreach my $channel_id ( sort keys %$channel_id_data ) {
	                            my $date_string = $channel_id_data->{$channel_id};
	                            $date_string =~ s/,$//;

	                            my $string = $property_id.'::'.$room_type_id.'::'.$update_type.'::'.$rate_plan_id.'::'.$channel_id.'::'.$date_string;
	                            eval{
	                                open(FH, ">>", $file_path);
	                                print FH $string;
	                                print FH "\n";
	                                close(FH);
	                            };
	                        }
	                    }
	                }
	            }
	        }
	    }
	}

	return $ticket_number;
}

sub main::get_server_time {
	my ($year,$month,$day, $hour,$min,$sec)=Today_and_Now();
	$month = sprintf("%02d", $month);
	$day   = sprintf("%02d", $day);
	$hour  = sprintf("%02d", $hour);
	$min   = sprintf("%02d", $min);
	$sec   = sprintf("%02d", $sec);

	$::server_time = $year."-".$month."-".$day."T".$hour.":".$min.":".$sec;

	return $::server_time;
}

sub main::get_prev_day {
	my @today = Today();
	my @prev_day = Add_Delta_Days( @today, -1 );

	my $month = sprintf("%02d", $prev_day[1]);
	my $day   = sprintf("%02d", $prev_day[2]);
	my $year  = $prev_day[0];

	my $prev_day = $year."-".$month."-".$day;
	return $prev_day;
}

sub main::get_next_day {
	my @today = Today();
	my @next_day = Add_Delta_Days( @today, +1 );

	my $month = sprintf("%02d", $next_day[1]);
	my $day   = sprintf("%02d", $next_day[2]);
	my $year  = $next_day[0];

	my $next_day = $year."-".$month."-".$day;
	return $next_day;
}

sub main::add_one_day {
	my $date = shift;
	if ( $date =~ /\d{4}-\d{2}-\d{2}/ ) {
		my @next_day = Add_Delta_Days( split('-', $date), +1 );

		my $month = sprintf("%02d", $next_day[1]);
		my $day   = sprintf("%02d", $next_day[2]);
		my $year  = $next_day[0];

		my $next_day = $year."-".$month."-".$day;
		return $next_day;
	}
	else {
		return $date;
	}
}

sub main::add_number_of_day {
	my $date = shift;
	my $day_count = shift;
	if ( $date =~ /\d{4}-\d{2}-\d{2}/ ) {
		my @next_day = Add_Delta_Days( split('-', $date), +$day_count );

		my $month = sprintf("%02d", $next_day[1]);
		my $day   = sprintf("%02d", $next_day[2]);
		my $year  = $next_day[0];

		my $next_day = $year."-".$month."-".$day;
		return $next_day;
	}
	else {
		return $date;
	}
}

sub main::get_today_day {
	my @today = Today();

	my $month = sprintf("%02d", $today[1]);
	my $day   = sprintf("%02d", $today[2]);
	my $year  = $today[0];

	my $today = $year."-".$month."-".$day;
	return $today;
}

sub main::get_delta_days {
	my $start_date = shift;
	my $end_date = shift;

	my $no_of_days = 0;
	if ( $start_date =~ /\d{4}-\d{2}-\d{2}/ && $end_date =~ /\d{4}-\d{2}-\d{2}/ ) {
		$no_of_days = Delta_Days( split('-', $start_date), split('-', $end_date) );
	}
	# if ( $no_of_days == 0 ) {
	# 	$no_of_days = 1;
	# }
	
	return $no_of_days;
}

sub main::get_day_of_week {
	my $start_date = shift;

	my $day_of_week = undef;
	if ( $start_date =~ /\d{4}-\d{2}-\d{2}/ ) {
		$day_of_week = Day_of_Week( split('-', $start_date) );
	}
	
	return $day_of_week;
}

sub main::store_update_log_string {
	my $updated_hash = shift;

	#Collect file path
	my $update_string_path = $::config{'log'}->{'update_log'};
	
	eval{
		my $today = ::get_today_day();
		my $fn = "rate_update_log_".$today.".txt";
		my $rate_file_path = $ENV{'DOCUMENT_ROOT'}."/logs/$fn";
		my $server_time = ::get_server_time();

        open(FHR, ">>", $rate_file_path);
        print FHR "Time: $server_time ::: Updated Hash:";
        print FHR Dumper $updated_hash;;
        print FHR "\n";
        close(FHR);
    };

	#Store in text string
	if ( scalar keys %$updated_hash ) {
	    foreach my $property_id ( sort keys %$updated_hash ) {
	    	
	        my $room_type_data = $updated_hash->{$property_id};

	        foreach my $room_dir_name ( sort keys %$room_type_data ) {
	        	
	            my $updated_dates = $room_type_data->{$room_dir_name};

	            my $property_dir = $update_string_path."/$property_id";
	            
                eval {
					if( !-d $property_dir ){
						`mkdir $property_dir`;
						`chown www-data:www-data $property_dir`;
						# system("chmod 777 ${property_dir}");
					}
				};
				if ( $@ ) {
					::log($@);
				}

				my $room_dir = $property_dir."/$room_dir_name";
                eval {
					if( !-d $room_dir ){
						`mkdir $room_dir`;
						`chown www-data:www-data $room_dir`;
						# system("chmod 777 ${room_dir}");
					}
				};
				if ( $@ ) {
					::log($@);
				}

				eval{
					my $today = ::get_today_day();
					my $fn = "rate_update_log_".$today.".txt";
					my $rate_file_path = $ENV{'DOCUMENT_ROOT'}."/logs/$fn";
					my $server_time = ::get_server_time();

			        open(FHR, ">>", $rate_file_path);
			        print FHR "Time: $server_time ::: Updated dates:";
			        print FHR Dumper $updated_dates;
			        print FHR "\n";
			        close(FHR);
			    };

	            foreach my $date ( sort keys %$updated_dates ) {
					my $server_time = ::get_server_time();
					my $date_string = $updated_dates->{$date};

					open(LOG,">>".$room_dir."/$date.txt");
					
					my $final_file = "$room_dir/$date.txt";
					`chown www-data:www-data $final_file`;

					print LOG $date_string."\n";
					close(LOG);
	            }
	        }
	    }
	}
}

sub main::store_temp_booking_json_log {
	my $property_id    = shift;
	my $ref_id         = shift;
	my $booking_status = shift;
	my $booking_json   = shift;

	#Collect file path
	my $temp_booking_json_path = $::config{'log'}->{'temp_booking_json'};

	#Store in text string
	eval {
		if( !-d $temp_booking_json_path ){
			`mkdir $temp_booking_json_path`;
		}
	};

	my $file_path = $property_id.'_'.$ref_id.'_'.$booking_status.".txt";
	
	eval {
		open(LOG,">".$temp_booking_json_path.'/'.$file_path);
		print LOG $booking_json;
		close(LOG);
	};
	if ( $@ ) {
		print $@;
	}
}

$::digit_month = {
	'01' => 'Jan',
	'02' => 'Feb',
	'03' => 'Mar',
	'04' => 'Apr',
	'05' => 'May',
	'06' => 'Jun',
	'07' => 'Jul',
	'08' => 'Aug',
	'09' => 'Sep',
	'10' => 'Oct',
	'11' => 'Nov',
	'12' => 'Dec',
};

$::single_digit_month = {
	'1' => 'Jan',
	'2' => 'Feb',
	'3' => 'Mar',
	'4' => 'Apr',
	'5' => 'May',
	'6' => 'Jun',
	'7' => 'Jul',
	'8' => 'Aug',
	'9' => 'Sep',
	'10' => 'Oct',
	'11' => 'Nov',
	'12' => 'Dec',
};

$::days_in_month = {
	'1' => 31,
	'2' => 28,
	'3' => 31,
	'4' => 30,
	'5' => 31,
	'6' => 30,
	'7' => 31,
	'8' => 31,
	'9' => 30,
	'10' => 31,
	'11' => 30,
	'12' => 31,
};

$::text_month = {
	'1' => 'January',
	'2' => 'February',
	'3' => 'March',
	'4' => 'April',
	'5' => 'May',
	'6' => 'June',
	'7' => 'July',
	'8' => 'August',
	'9' => 'September',
	'10' => 'October',
	'11' => 'November',
	'12' => 'December',
};

$::digit_dow = {
	'01' => 'Mon',
	'02' => 'Tue',
	'03' => 'Wed',
	'04' => 'Thu',
	'05' => 'Fri',
	'06' => 'Sat',
	'07' => 'Sun',
};

$::single_digit_dow = {
	'1' => 'Monday',
	'2' => 'Tuesday',
	'3' => 'Wednesday',
	'4' => 'Thursday',
	'5' => 'Friday',
	'6' => 'Saturday',
	'7' => 'Sunday',
};

$::single_digit_dow_short = {
	'1' => 'Mon',
	'2' => 'Tue',
	'3' => 'Wed',
	'4' => 'Thu',
	'5' => 'Fri',
	'6' => 'Sat',
	'7' => 'Sun',
};


$::single_digit_dow_single_char = {
	'1' => 'M',
	'2' => 'T',
	'3' => 'W',
	'4' => 'T',
	'5' => 'F',
	'6' => 'S',
	'7' => 'S',
};

#Generate Echo Token
sub main::gen_GUID {
    my $seed = localtime(time)."-".int(rand(100));
    
    my $md5 = uc md5_hex ($seed);
    my @octets = $md5 =~ /(.{2})/g;
    
    substr $octets[6], 0, 1, '4'; # GUID Version 4
    substr $octets[8], 0, 1, '8'; # draft-leach-uuids-guids-01.txt GUI+D variant 
    my $GUID = "@octets[0..3]-@octets[4..5]-@octets[6..7]-@octets[8..+9]-@octets[10..15]";
    
    $GUID =~ s/ //g;
    return $GUID;
}

#sub main::fetch_country_list {
#	
#	$main::country_list = $::dbi_handles->{'main_dbh'}->get({
#		'table'  => 'country_master',
#		'hash'   => 1,
#		'select' => 'id as country_id, name, code, iso_code, currency',
#	});
#}

sub main::convert_date_to_string {
	my $date = shift;
	my $selected_lang = shift;

	my $string = Date_to_Text(split('-', $date));
	my ($day, $dt, $mm, $yy ) = $string =~ /(.*?)\s+(.*?)\-(.*?)\-(.*)/;
	
	if ( defined $selected_lang ) {
		my $mday = lc($day);
		$day = $::lang{$selected_lang}->{$mday};

		my $mmm = lc($mm);
		$mm = $::lang{$selected_lang}->{$mmm};

		$string = $day.", ".$mm." ".$dt.", ".$yy;
	}
	else {
		$string = $day.", ".$mm." ".$dt.", ".$yy;
	}
	return $string;
}

sub main::convert_date_to_string_dd_mmm_yy {
	my $date = shift;
	my $selected_lang = shift;

	my $string = Date_to_Text(split('-', $date));
	my ($day, $dt, $mm, $yy ) = $string =~ /(.*?)\s+(.*?)\-(.*?)\-(.*)/;
	
	if ( defined $selected_lang ) {
		my $mday = lc($day);
		$day = $::lang{$selected_lang}->{$mday};

		my $mmm = lc($mm);
		$mm = $::lang{$selected_lang}->{$mmm};

		$string = $dt." ".$mm." ".$yy;
	}
	else {
		$string = $dt.", ".$mm." ".$yy;
	}
	return $string;
}


sub main::store_json_log {
	my $provider = shift;
	my $type     = shift;
	my $data     = shift;
	my $session_id = shift;
	
	if ( defined $session_id ) {

		#Collect file path
		my $log_path = $::config{'log'}->{$provider};
		
		my $file_name = $type.'_'.$session_id.'.txt';

		eval {
			open( LOG,">".$log_path.'/'.$file_name );
			print LOG $data;
			close(LOG);
		};
		if ( $@ ) {
			print $@;
		}
	}
}

sub main::read_json_log {
	my $provider = shift;
	my $type     = shift;
	my $session_id = shift;

	my $data = undef;

	if ( defined $session_id ) {

		#Collect file path
		my $log_path = $::config{'log'}->{$provider};
		
		my $file_name = $type.'_'.$session_id.'.txt';
		
		eval {
			open( LOG,"<".$log_path.'/'.$file_name );
			$data = <LOG>;
			close(LOG);
		};
		if ( $@ ) {
			print $@;
		}
	}
	
	return $data;
}


sub main::remove_json_log {
	my $provider = shift;
	my $type     = shift;
	my $session_id = shift;

	my $data = undef;

	if ( defined $session_id ) {

		#Collect file path
		my $log_path = $::config{'log'}->{$provider};
		
		my $file_name = $type.'_'.$session_id.'.txt';
		
		eval {
			my $path = $log_path.'/'.$file_name;
			unlink $path; 
		};
		if ( $@ ) {
			print $@;
		}
	}
	
	return $data;
}

1;