#
# SILock.pm
#
# Module for doing row locking
#
# Author: Jennifer Liddle (js10)
#
# $Id: SILock.pm,v 1.2 2006/09/15 18:30:42 js10 Exp $
#
# $Log: SILock.pm,v $
# Revision 1.2  2006/09/15 18:30:42  js10
# installed version
#
# Revision 1.1.1.1  2006/09/13 16:50:17  js10
# A module for locking
#
#

package SILock;
use warnings;
use strict;
use Carp;
                                                                                                                     
use FindBin;
use lib "$FindBin::Bin";

use SqlEngine2;

my $savepoint = 1;

sub new
{
    my ($pkg,$dbh,$user,$session) = @_;
	my %self;

    $SqlEngine2::verbosity=0;
	confess "you must supply a dbh to SILock\n" unless $dbh =~ /::db=HASH/;

	$self{se} = new SqlEngine2();
	my $instance = $self{se}->getRow('SILock::getInstance', [], $dbh);
	$self{lockDbh} = SqlEngine2::getDbh("lock_$instance");
	$self{dbh} = $dbh;
	$self{user} = $user;
	$self{session} = $session;
	$self{HOSTNAME} = `hostname`;
	$self{se}->loadSqlLib(['SILock']);

    bless (\%self, $pkg);
    return \%self;
}

sub unlockAll
{
	my $self = shift;
	$self->{se}->do('SILock::delAllLocks', [$self->{session}], $self->{lockDbh});
	$self->{se}->commitTransaction($self->{lockDbh});
}

sub lockRow
{
	my ($self, $table, $key, $id) = @_;
	
	# attempt an oracle lock
	$savepoint++;
	my $q = $self->{se}->virtualSqlLib('lock','savepoint',"savepoint LOCK_$savepoint");
	$self->{se}->do($q, [], $self->{dbh});
	$q = $self->{se}->virtualSqlLib('lock',$table, "select * from $table where $key = $id for update nowait");
	eval { $self->{se}->do($q, [], $self->{dbh}, 1); };
	if ($@) {
		# locking failed - get details of other locks
		my @row = $self->{se}->getRow('SILock::getLockDetails', [$table, $id], $self->{lockDbh});
		$self->{email} = $row[0];
		$self->{date} = $row[1];
		$self->{time} = $row[2];
		$self->{today} = $row[3];
		$self->{yesterday} = $row[4];
		$self->{program} = $row[5];
		$self->{name} = $self->{se}->getRow('SILock::email2name', [$self->{email}], $self->{dbh});
		$self->{date} = 'Today' if ($self->{date} eq $self->{today});
		$self->{date} = 'Yesterday' if ($self->{date} eq $self->{yesterday});
		# make it look a little nicer
		$self->{date} =~ s/^MON /on Monday /;
		$self->{date} =~ s/^TUE /on Tuesday /;
		$self->{date} =~ s/^WED /on Wednesday /;
		$self->{date} =~ s/^THU /on Thursday /;
		$self->{date} =~ s/^FRI /on Friday /;
		$self->{date} =~ s/^SAT /on Saturday /;
		$self->{date} =~ s/^SUN /on Sunday /;
		$self->{date} =~ s/JANUARY/January/;
		$self->{date} =~ s/FEBRUARY/February/;
		$self->{date} =~ s/MARCH/March/;
		$self->{date} =~ s/APRIL/April/;
		$self->{date} =~ s/MAY/May/;
		$self->{date} =~ s/JUNE/June/;
		$self->{date} =~ s/JULY/July/;
		$self->{date} =~ s/AUGUST/August/;
		$self->{date} =~ s/SEPTEMBER/September/;
		$self->{date} =~ s/OCTOBER/October/;
		$self->{date} =~ s/NOVEMBER/November/;
		$self->{date} =~ s/DECEMBER/December/;

		return 0;
	} else {
		# locking worked - record the fact
		my ($owner) = $self->{se}->getRow('SILock::getTableOwner', [$table], $self->{dbh});
		$self->{se}->do('SILock::delLockDetails', [$owner,$table, $id], $self->{lockDbh});
		$self->{se}->do('SILock::addLockDetails', [$owner,$table,$id,$self->{user},$0,$self->{HOSTNAME},$$,$ENV{DISPLAY},$self->{session}], $self->{lockDbh});
		$self->{se}->commitTransaction($self->{lockDbh});
		return 1;
	}
}

sub unlockRow
{
	my $self = shift;
	my $q = $self->{se}->virtualSqlLib('lock','unsavepoint',"rollback to LOCK_$savepoint");
	$self->{se}->do($q, [], $self->{dbh});
	$savepoint--;
}


1;

