package lib_module_db;

########## Confixx(R) 3.0 Professional ############
####### Copyright SWsoft, Inc. 2004-2005 ##########
#### http://www.sw-soft.com - info@sw-soft.com ####

use DBI;
use Sys::Hostname;

use strict;

use vars qw/@ISA @EXPORT/;

@ISA = qw(Exporter);

@EXPORT = qw(&makeDSN &makeCmdLine &getMysqlInfo &getMysqlVersion &parseMyCnf &getMysqlHost);

my $defaultPgPort = 5432;
my $defaultMysqlPort = 3306;

sub makeDSN {
	my ( $dbtype, $dbserver, $dbname, $dbport ) = @_;
	my $conn = "DBI:$dbtype";

	$dbserver ||= 'localhost';
	$dbname ||= ($dbtype eq 'mysql')? 'mysql': 'test'; 

	if ( $dbtype eq 'Pg' ) {
		$conn .= ":dbname=$dbname;host=$dbserver";
		if ( $dbport && ( $dbport ne $defaultPgPort ) ) {
			if ( $dbport =~ /^\d+$/ ) {
				$conn .= ";port=$dbport";
			}
		}
	} else { ## MySQL
		$conn .= ":$dbname:$dbserver";
		if ( $dbport && ( $dbport ne $defaultMysqlPort ) ) {
			if ( $dbserver eq 'localhost' && -S $dbport ){
				$conn .= ";mysql_socket=$dbport";
			} elsif ( $dbport =~ /^\d+$/ ) {
				$conn .= ";port=$dbport";
			}
		}
	}
	return $conn;
}

sub cmdLine2DSN {
	my ( $server, $db, $port, $user, $pswd ) = @_;
	my (@args);

	if ( ref($server) =~ /HASH/ ) {
		my %hash = %{$server};
		($server, $db, $port, $user, $pswd ) = @hash{'server','dbname','port','user','password'};
		$server ||= $hash{'host'};
		$db ||= $hash{'name'};
		$port ||= $hash{'socket'};
		$pswd = $hash{'paswd'} unless defined($pswd);
	}
	my $dsn = &makeDSN('mysql',$server,$db,$port);

	return ($dsn,$user,$pswd,$server);

}

sub makeCmdLine {
	my ( $server, $db, $port, $user, $pswd ) = @_;
	my (@args);

	if ( ref($server) =~ /HASH/ ) {
		my %hash = %{$server};
		($server, $db, $port, $user, $pswd ) = @hash{'server','dbname','port','user','password'};
		$server ||= $hash{'host'};
		$db ||= $hash{'name'};
		$port ||= $hash{'socket'};
		$pswd = $hash{'paswd'} unless defined($pswd);
	}

	push @args, '-h'.$server if $server;

	if ( $port ) {

		if ( -S $port ) { ## socket
			push @args, '-S'.$port;

		} elsif ( $port =~ /^\d+$/ ) { ## tcp port
			push @args, '-P'.$port;
		}
	}
	if ( defined $user ) {
		push @args, '-u'.$user;
	}
	if ( $pswd = &prepArg( $pswd ) ) {
		push @args, '-p'.$pswd;
	}

	push @args, $db if $db;
	
	return join(' ',@args);
}

sub prepArg {
	my $arg = shift;
	if ( defined $arg ) {
		if ( $arg =~ /^('|")(.*)\1$/ ) {
			$arg = $2; ## remove slashes
		}
		$arg =~ s/"/\\"/g;
		$arg = '"'.$arg.'"';
	}
	return $arg;
}

sub getMysqlInfo {

	my $args = &makeCmdLine( @_ );
	my ($dsn,$user,$paswd,$server) = &cmdLine2DSN( @_ );

	my ($ret,$errmsg,$clientVer, $clientMajVer, $serverVer, $serverMajVer );

	$::bin_mysql ||= $::bin{'mysql'} || 'mysql';

	my $out = `$::bin_mysql -V`;
	if ($out =~ /((\d+)\.\d+\.\d+)/) {
		$clientVer = $1;
		$clientMajVer = $2;
	}

	my $dbh = DBI->connect($dsn, $user, $paswd);
	if ( $dbh ) {
		$out = $dbh->{'serverinfo'};
		if ( $out =~ /((\d+)\.\d+\.\d+)/ ){
			$serverVer = $1;
			$serverMajVer = $2;
		}
		$dbh->disconnect;
	}

	if ( $serverMajVer == $clientMajVer ) {

		my $cmd = "$::bin_mysql $args -e status";
		if ( open (OUT, "$cmd |") ) {
			$ret = {};
			my $state = 0;
			my ($key,$value);
			while ( <OUT> ) {
				chomp;
				if ( $state == 0 ){
					if ( /^\s*$/ ) {
						$state = 1;
					}
				} elsif ( $state == 1 ) {
					if ( /^\s*$/ ) {
						last;
				}
					($key,$value) = split( /\s*:\s*/, $_, 2 );
					$key =~ s/\s+/ /g;
					$key = lc( $key );
					$ret->{$key} = $value;
				}
			}
			close ( OUT );
		} else {
			$errmsg = $!;
		}

	} else { ## major version is not equal
		my ($host);

		if ($server && $server ne 'localhost') {
			$host = hostname();
		} else {
			$host = 'localhost';
		}
#
# emulate output of 'status'
#
		$ret = {'current user' => $user.'@'.$host }; ## make a hash
		$ret->{'server version'} = $serverVer if $serverVer;
	}

	if ( wantarray() ) {
		return ($ret,$errmsg);
	} else {
		return $ret;
	}
}

sub getMysqlVersion {
	my( $ret, $errmsg ) = &getMysqlInfo( @_ );
	if ( ref($ret) =~ /HASH/ ) {
		my $verStr = $ret->{'server version'};
		if ( defined($verStr) ) {
			if ( $verStr =~ /((\d+)\.(\d+)\.(\d+))/ ) {
				$errmsg = $1;
				$ret = $2 + $3*0.001 + $4*0.000001;
			} else {
				$ret = 0;
				$errmsg = $verStr;
			}
		} else {
			$ret = undef;
			$errmsg = 'server version is not found';
		}
	}

	if ( wantarray() ) {
		return ($ret, $errmsg);
	} else {
		return $ret;
	}
}

sub getMysqlHost {
	my( $ret, $errmsg ) = &getMysqlInfo( @_ );
	if ( ref($ret) =~ /HASH/ ) {
		my $userStr = $ret->{'current user'};
		if ( defined($userStr) ) {
		  (undef, $ret) = split(/@/,$userStr);
		  $errmsg = $userStr unless $ret;	
		} else {
			$ret = undef;
			$errmsg = 'current user is not found';
		}
	}

	if ( wantarray() ) {
		return $ret, $errmsg;
	} else {
		return $ret;
	}
}

sub parseMyCnf {
	my $path = shift;
	my @keys = @_;
	my ($ret,$errstr);

	if ( ref($keys[0])=~/HASH/ ){
		$ret = $keys[0];
	} else {
		$ret = {};
		map { $ret->{$_} = undef } @keys;
	}

	if ( $path && -T $path) {
		if ( open (CNF,'<'.$path) ) {
			my ($key,$value);
			while (<CNF>) {
				chomp;
				next if /^#/; ##skip comment

				($key,$value) = split(/\s*=\s*/,$_,2);

				$key =~ s/^\s+//; ## ltrim
				$value =~ s/\s+$//; ## rtrim
				if ( exists $ret->{$key} ) {
					$ret->{$key} = $value;
				}
			}
			
			close (CNF);
		} else {
			$errstr = "unable to open file '$path': $!";
			$ret = undef;
		}
	} else {
		$errstr = "a text file '$path' is not found";
		$ret = undef;
	}
	if ( wantarray() ) {
		return $ret, $errstr;
	} else {
		return $ret;
	}

}


1;
