#!/usr/bin/perl -w
#
# poke.pl
#
# J. Uckelman (uckelman@iastate.edu)
# 10 June 2001
#

require 5.005;
use DBI;

# Configuration
my ($prog, $ver) = ('poke.pl', 0.2);
my ($scripts_conf, $subs, $mysql_conf, $mysql_subs) = ('/home/g1/bin/subs.pl', '/home/g1/bin/scripts.conf', '/home/g1/bin/mysql.conf', '/home/g1/bin/mysql.pl');

print "$prog version $ver\n";

# Assign to some variables in the config to avoid a warning about using them only once
$database = $password = $port = $host = $user = '';

# Load the subs and config files 
eval { require $scripts_conf; };
die "\n$0: $scripts_conf: $@\n" if $@;
eval { require $subs; };
die "\n$0: $subs: $@\n" if $@;
eval { require $mysql_conf; };
die "\n$0: $mysql_conf: $@\n" if $@;
eval { require $mysql_subs; };
die "\n$0: $mysql_subs: $@\n" if $@;

sub agent_add ($);
sub award_set ($);
sub motion_add ($$);
sub motion_status ($$$);
sub motion_rescind ($$);
sub motion_request ($);
sub motion_object ($);
sub motion_grant ($);
sub motion_voting ($$);
sub player_change ($$);
sub rfj_add ($);
sub rfj_judge ($$);
sub rfj_ruling ($);
sub rule_add ($);
sub rule_repeal ($);

# Connect to game database
$db = DBI->connect("DBI:mysql:database=$database;host=$host;port=$port", $user, $password) or die "\n$prog: database connect failed: $DBI::errstr";

# Set Dave.
$dave = "I can't let you do that, Dave,";

# Get grist...
my $grist = read_file($ARGV[0]);
my $save = $grist;

my $dry = 1;
print "Dry run...\n";

# ...for the mill
while ($grist) {
	
	# Get command
	my ($type, $command) = $grist =~ m/^(.*?) (.*?)\n/ or die "\n$prog: '$&' unrecognized";
	$grist = $';

	# Get data
	my ($data) = $grist =~ m/^(.*?)\n\n-{4}\n/s or die "\n$prog: bad data for '$type $command'";
	$grist = $';

	# Process command
	if ($type eq 'proposal') {
		if ($command eq 'add') { motion_add('proposal', $data); }
		elsif ($command =~ m/^(withdraw|activate|deactivate)$/) { motion_status($type, $command, $data); }
		elsif ($command eq 'rescind') { motion_rescind('proposal', $data); }
		elsif ($command eq 'voting') { motion_voting('proposal', $data); }
		else { die "\n$prog: '$command' unrecognized command"; }
	}
	elsif ($type eq 'motion') {
		if ($command eq 'add') { motion_add('motion', $data); }
		elsif ($command =~ m/^(withdraw|activate|deactivate)$/) { motion_status($type, $command, $data); }
		elsif ($command eq 'rescind') { motion_rescind('motion', $data); }
		elsif ($command eq 'request') { motion_request($data); }
		elsif ($command eq 'object') { motion_object($data); }
		elsif ($command eq 'grant') { motion_grant($data); }
		elsif ($command eq 'voting') { motion_voting('motion', $data); }
		else { die "\n$prog: '$command' unrecognized command"; }
	}
	elsif ($type eq 'rfj') {
		if ($command eq 'add') { rfj_add($data); }
		elsif ($command eq 'assign') { rfj_judge('assign', $data); }
		elsif ($command eq 'recuse') { rfj_judge('recuse', $data); }
		elsif ($command eq 'ruling') { rfj_ruling($data); }
		else { die "\n$prog: '$command' unrecognized command"; }
	}
	elsif ($type eq 'rule') {
		if ($command eq 'add') { rule_add($data); }
		elsif ($command eq 'repeal') { rule_repeal($data); }
		else { die "\n$prog: '$command' unrecognized command"; }
	}
	elsif ($type eq 'agent') {
		if ($command eq 'add') { agent_add($data); }
		else { die "\n$prog: '$command' unrecognized command"; }
	}
	elsif ($type eq 'player') {
		if ($command =~ m/^(add|forfeit)$/) { player_change($command, $data); }
		elsif ($command eq 'remove') {}
		else { die "\n$prog: '$command' unrecognized command"; }
	}
	elsif ($type eq 'office') {
		if ($command eq 'nominate') {}
		elsif ($command eq 'decline') {}
		elsif ($command eq 'tie') {}
		else { die "\n$prog: '$command' unrecognized command"; }
	}
	elsif ($type eq 'award') {
		if ($command eq 'set') { award_set($data); }
		else { die "\n$prog: '$command' unrecognized command"; }
	}
	else { die "\n$prog: '$type' unrecognized command type"; }

	if ($dry and !$grist) {
		# Dry run is over; do more?
		$| = 1;
		print "Continue? ";
		my $answer = <STDIN>;
		$| = 0;
		if (lc($answer) =~ m/y/) {
			$dry = 0;
			# Reset data
			$grist = $save;
			print "Damn the torpedoes...\n";
		}
		else { print "Make it stop! Make it stop!\n"; }
	}
}

$db->disconnect;

exit 0;

#
# agent_add: add an Agent to the database
#
sub agent_add ($) {
	my ($data) = @_;

	# name
	# address
	# date

	my ($name, $address, $date) = $data =~ m/^(.*?)\n(.*?@.*?)\n(.*)/s or die "\n$prog: bad '$type $command'";

	$date = convdate($date);
	my ($entity_id) = query("select max(id) from entity");
	$entity_id++;

	$name = quotemeta($name);
	
	unless ($dry) {
		$db->do("insert into entity (id, activity, vitality) values ($entity_id, 1, 1)");
		$db->do("insert into name (id, name, start) values ($entity_id, '$name', '$date')");
		$db->do("insert into mail (id, address, start) values ($entity_id, '$address', '$date')");
	}

	print "Agent $name added\n";
}

#
# award_set: set Awards or Salaries
#
sub award_set ($) {
	my ($data) = @_;

	# award
	# value
	# date

	my ($award, $value, $date) = $data =~ m/^(.*?)\n(\d+)\n(.*)/s or die "\n$prog: bad '$type $command'";

	$date = convdate($date);

	my $officer;
	if ($award eq 'Adopted Proposal Award' or $award eq 'Opposed Minority Award' or $award eq 'Official Salary' or $award eq 'Judicial Salary') { $officer = 'Banker'; }
	elsif ($award eq 'Failed Proposal Fine') { $officer = 'Tax Collector'; }
	else { die "\n$prog: unrecognized Officer '$officer'"; }

	unless ($dry) { 
		$db->do("insert into event (date, event) values ('$date', '$officer set $award to $value Point@{[$value == 1 ? '' : 's']}')");
	}

	print "$officer set $award to $value\n";
}

#
# motion_add: add a Motion to the database
#
sub motion_add ($$) {
	my ($type, $data) = @_;

	# number/revision
	# mdate
	# rdate
	# owner
	# title
	#
	# text

	my ($number, $revision, $mdate, $rdate, $owner, $title, $text) = $data =~ m/^(\d+)\/(\d+)\n(.*?)\n(.*?)\n(.*?)\n(.*?)\n\n(.*)/s or die "\n$prog: bad `$type $command`";

	$mdate = convdate($mdate);
	$rdate = convdate($rdate);

	$owner = quotemeta($owner);
	my $owner_id = getid($owner, $mdate);

	$title = quotemeta($title);
	$text = quotemeta($text);

	unless ($dry) {
		$db->do("insert into $type (number, revision, activity, owner, title, text, start) values ($number, $revision, 1, $owner_id, '$title', '$text', '$mdate')") or die $dave;
		
		if ($revision == 0) { 
			my $what = $type eq 'proposal' ? "Proposal" : $title;
			$db->do("insert into event (date, event) values ('$mdate', '$owner made a $what [$number]')");
		}	
		else {
			$db->do("insert into event (date, event) values ('$mdate', '$owner revised \u$type $number')");
			$db->do("update $type set end = '$mdate' where number = $number and revision = $revision - 1");
		}

		$db->do("insert into ${type}0history (number, revision, id) values ($number, $revision, last_insert_id())");
		$db->do("insert into event (date, event) values ('$rdate', 'Administrator recognized \u$type $number/$revision')");
		$db->do("insert into ${type}0history (number, revision, id) values ($number, $revision, last_insert_id())");
	}
	
	print $type eq 'proposal' ? 'P' : 'M', "$number/$revision added\n";
}

#
# motion_status: change status of an existing Motion
#
sub motion_status ($$$) {
	my ($type, $change, $data) = @_;

	# number/revision
	# date
	
	my ($number, $revision, $date) = $data =~ m/^(\d+)\/(\d+)\n(.*)/s or die "\n$prog: bad '$type $command'";

	$date = &convdate($date);

	my $owner = quotemeta(getname((query("select owner from $type where $type.number = $number and $type.revision = $revision"))[0], $date));

	if ($change eq 'withdraw') {
		unless ($dry) {
			$db->do("update $type set end = '$date', activity = 2 where number = $number and revision = $revision") or die $dave;
			$db->do("insert into event (date, event) values ('$date', '$owner withdrew \u$type $number/$revision')");
			$db->do("insert into ${type}0history (number, revision, id) values ($number, $revision, last_insert_id())");
		}
		$change .= 'n';
	}
	elsif ($change eq 'activate' or $change eq 'deactivate') {
		unless ($dry) {
			my $activity = $change eq 'activate' ? 1 : 0;
			$db->do("update $type set activity = $activity where number = $number and revision = $revision") or die $dave;
			$db->do("insert into event (date, event) values ('$date', '$owner ${change}d \u$type $number/$revision')");
			$db->do("insert into ${type}0history (number, revision, id) values ($number, $revision, last_insert_id())");
		}
		$change .= 'd';
	}      
	         
	print $type eq 'proposal' ? 'P' : 'M', "$number/$revision $change\n";
}

#
# motion_rescind: rescind a Motion not yet in the database
#
sub motion_rescind ($$) {
	my ($type, $data) = @_;

	# mdate
	# rdate
	# owner
	# title

	my ($mdate, $rdate, $owner, $title) = $data =~ m/^(.*?)\n(.*?)\n(.*?)\n(.*)/s or die "\n$prog: bad '$type $command'";

	$mdate = &convdate($mdate);
	$rdate = &convdate($rdate);

	$owner = quotemeta($owner);
	$title = quotemeta($title);

	my $what = $type eq 'proposal' ? "\u$type" : $title;

	unless ($dry) {
		$db->do("insert into event (date, event) values ('$mdate', '$owner made a $what [rescinded]')");
		$db->do("insert into event (date, event) values ('$rdate', '$owner rescinded an unrecognized \u$type')");
	}

	print "unrecognized \u$type rescinded\n";
}

#
# motion_request: register a request for consent on a Motion
#
sub motion_request ($) {
	my ($data) = @_;

	# number/revision
	# date
	# owner

	my ($number, $revision, $date, $owner) = $data =~ m/^(\d+)\/(\d)\n(.*?)\n(.*)/s or die "\n$prog: bad '$type $command'";

	$date = &convdate($date);
		
	$owner = quotemeta($owner);

	unless ($dry) {
		$db->do("insert into event (date, event) values ('$date', '$owner requested unanimous consent for Motion $number/$revision')");
		$db->do("insert into motion0history (number, revision, id) values ($number, $revision, last_insert_id())");
	}

	print "M$number/$revision UC request registered\n";
}

#
# motion_object: register an objection to consent on a Motion
#
sub motion_object ($) {
	my ($data) = @_;

	# number/revision
	# date
	# objector
	# fails?
	
	my ($number, $revision, $date, $objector, $fails) = $data =~ m/^(\d+)\/(\d+)\n(.*?)\n(.*?)\n(.*)/s or die "\n$prog: bad '$type $command'";

	$date = &convdate($date);

	$objector = quotemeta($objector);

	unless ($dry) {
		$db->do("insert into event (date, event) values ('$date', '$objector objected to Motion $number/$revision')");
		$db->do("insert into motion0history (number, revision, id) values ($number, $revision, last_insert_id())");                             
		if ($fails eq 'fails') {
			$db->do("update motion set end = '$date' where number = $number and revision = $revision");
         $db->do("insert into event (date, event) values ('$date', 'Motion $number/$revision failed by objection')");
			$db->do("insert into motion0history (number, revision, id) values ($number, $revision, last_insert_id())");
		}
	}

	print "M$number/$revision UC ojbection registered\n";
}

#
# motion_grant: register granting of consent on a Motion
#
sub motion_grant ($) {
	my ($data) = @_;

	# number/revision
	# date

	my ($number, $revision, $date) = $data =~ m/^(\d+)\/(\d+)\n(.*)/s or die "\n$prog: bad '$type $command'";

	$date = &convdate($date);

	unless ($dry) {
		$db->do("update motion set end = '$date' where number = $number and revision = $revision");
		$db->do("insert into event (date, event) values ('$date', 'Motion $number/$revision passed by unanimous consent')");
		$db->do("insert into motion0history (number, revision, id) values ($number, $revision, last_insert_id())");
	}

	print "M$number/$revision passed by UC\n";
}

#
# motion_voting: get voting information for Motions, generate report
#
sub motion_voting ($$) {
	my ($type, $data) = @_;

	# bdate
	# edate
	# quorum
	# adopted opposed failed
	#
	# num/rev[ num/rev]...
	#
	# name
	# vote[ vote]...

	my ($bdate, $edate, $quorum, $adopted, $opposed, $failed, $nums, $votes) = $data =~ m/^(.*?)\n(.*?)\n(.*)\n(\d+) (\d+) (\d+)\n\n(.*?)\n\n(.*)/s or die "\n$prog: bad '$type $command'";

	# Get item numbers
	my (@tmp, $i);
	@tmp = split / /, $nums;
	for $i (0 .. $#tmp) { ($num[$i], $rev[$i]) = $tmp[$i] =~ m/(\d+)\/(\d+)/ or die "\n$prog: bad '$type $command'"; }

	$bdate = convdate($bdate);
	$edate = convdate($edate);

	# Get names and votes
	my @vote;
	@tmp = split /\n/, $votes;
	for $i (0 ..  int($#tmp / 2)) {
		$name[$i] = $tmp[2*$i];
		push @vote, [ split / /, $tmp[2*$i+1] ];
	}

	# Calculate quorum
	if ($quorum eq 'vote') {
		print "foo";
		$quorum = 0;
		for $i (0 .. $#vote) {
			VOTE: for $j (0 .. $#num) {
				if ($vote[$i][$j] ne '-') {
					$quorum++;
					last VOTE;
				}
			}
		}
	}

	# Put voting period into db if not already
	my ($tmp) = query("select event from event where date = '$bdate' and event = 'Voting began'");
	if (defined($tmp) and $tmp eq 'Voting began') { print "\nVoting exists, not added, quorum $quorum"; }
	else {
		unless ($dry) {
			$db->do("insert into event (date, event) values ('$bdate', 'Voting began')");
			$db->do("insert into event (date, event) values ('$edate', 'Voting ended, quorum was $quorum')");
		}
		print "\nVoting added, quorum $quorum";
	}

	my @score = ();
	
	# calculate passage
	for $i (0 .. $#num) {
		my ($yea, $nay, $abs, $not, $result) = (0, 0, 0, 0, 0);
		for $j (0 .. $#name) {
			$yea++ if $vote[$j][$i] eq 'y';
			$nay++ if $vote[$j][$i] eq 'n';
			$abs++ if $vote[$j][$i] eq 'a';
			$not++ if $vote[$j][$i] eq '-'; 
 
			# poke individual voting into db
			unless ($dry) {                         
			my $voter_id = &getid(quotemeta($name[$j]), $edate);
			$db->do("insert into ${type}0voting (number, revision, id, date, vote) values ($num[$i], $rev[$i], $voter_id, '$edate', '$vote[$j][$i]')");
			}
		}
                        
		$result = ($yea + $nay + $abs) >= $quorum ? ($yea > $nay ? "passed" : "failed") : "held";
		printf("\n%s%d/%d %s (%d-%d-%d-%d)", $type eq 'proposal' ? 'P' : 'M', $num[$i], $rev[$i], $result, $yea, $nay, $abs, $not);
                 
		# poke voting result into db
		unless ($dry) {
			$db->do("update $type set end = '$edate' where number = $num[$i] and revision = $rev[$i]") unless $result eq 'held';
			$db->do("insert into event (date, event) values ('$edate', '\u$type $num[$i]/$rev[$i] $result ($yea-$nay-$abs-$not)')") or die $dave;
			$db->do("insert into ${type}0history (number, revision, id) values ($num[$i], $rev[$i], last_insert_id())");
		}

		if ($type eq 'proposal' and $result ne 'held') {
			# calculate scoring
			my ($owner_id) = query("select owner from proposal where number = $num[$i] and revision = $rev[$i]");
                                       
			if ($result eq 'passed') {
				# Adopted Proposal Award
				push @score, [ $owner_id, $adopted ];
      
				for $j (0 .. $#name) {
					# Opposed Minority Award
					if ($vote[$j][$i] eq 'n') { push @score, [ &getid(quotemeta($name[$j]), $edate), $opposed ]; }
				}
			}
			elsif ($result eq 'failed') { push @score, [ $owner_id, -1 * $failed ]; } # Failed Proposal Fee
			else { die "Doh!"; }
		}
	}

	if ($type eq 'proposal') {
		# print scoring
		my @scored = ();
		for $i (0 .. $#score) {
			push @scored, $score[$i][0] if !(grep $_ == $score[$i][0], @scored);
		}

		print "\n\nScoring\n";

		for $i (0 .. $#scored) {
			my ($total, @breakdown) = ();
			for $j (0 .. $#score) {
				if ($score[$j][0] == $scored[$i]) { 
					push @breakdown, $score[$j][1];
					$total += $score[$j][1];
				}
			}

			print &getname($scored[$i], $edate), " $total (", (join ', ', @breakdown), ")\n";
		}
	}
}

#
# player_change: add or remove an Agent as a Player
#
sub player_change ($$) {
	my ($change, $data) = @_;

	# name
	# date

	my ($name, $date) = $data =~ m/^(.*?)\n(.*)/s or die "\n$prog: bad '$type $command'";

	$date = convdate($date);
	
	$name = quotemeta($name);
	my $entity_id = getid($name, $date);

	if ($change eq 'add') {
		unless ($dry) {
			$db->do("update entity set type = 'player', activity = 1, vitality = 1 where id = $entity_id");
			$db->do("insert into player (id, start) values ($entity_id, '$date')");
			$db->do("insert into event (date, event) values ('$date', '$name became a Player')");
		}
	}
	elsif($change eq 'forfeit') {	
		unless ($dry) {
			$db->do("update entity set vitality = 0 where id = $entity_id");
			$db->do("update player set end = '$date' where id = $entity_id");
			$db->do("insert into event (date, event) values ('$date', '$name forfeited')");
		}
	}

	$name = eval "sprintf(\"$name\")";
	print "Player $name ${change}ed\n";
}

#
# rfj_add: add a new RFJ to the database
#
sub rfj_add ($) {
	my ($data) = @_;
	
	# number/revision
	# date
	# plaintiff
	# statement
	#
	# analysis

	my ($number, $revision, $date, $plaintiff, $statement, $analysis) = $data =~ m/^(\d+)\/(\d+)\n(.*?)\n(.*?)\n(.*?)\n\n(.*)/s or die "\n$prog: bad '$type $command'";

	$date = convdate($date);

	$plaintiff = quotemeta($plaintiff);
	my $plaintiff_id = getid($plaintiff, $date);

	$statement = quotemeta($statement);
	$analysis = quotemeta($analysis);

	unless ($dry) {
		$db->do("insert into judgment (number, revision, plaintiff, statement, p_analysis, start) values ($number, $revision, $plaintiff_id, '$statement', '$analysis', '$date')") or die $dave;
		$db->do("insert into event (date, event) values ('$date', '$plaintiff made an RFJ [$number]')");
		$db->do("insert into judgment0history (number, revision, id) values ($number, $revision, last_insert_id())");
	}

	$plaintiff = eval "sprintf(\"$plaintiff\")";
	print "$plaintiff made RFJ [$number]\n";
}

#
# rfj_judge: assign a Judge to or recuse a Judge from an RFJ
#
sub rfj_judge ($$) {
	my ($command, $data) = @_;

	# number/revision
	# date
	# judge
	
	my ($number, $revision, $date, $judge) = $data =~ m/^(\d+)\/(\d+)\n(.*?)\n(.*)/s or die "\n$prog: bad '$type $command'";
	
	$date = convdate($date);
	
	$judge = quotemeta($judge);
	my $judge_id = getid($judge, $date);

	unless ($dry) {
		if ($command eq 'assign') {
			$db->do("insert into event (date, event) values ('$date', 'OSJ recognized RFJ $number/$revision')") or die $dave;
			$db->do("insert into judgment0history (number, revision, id) values ($number, $revision, last_insert_id())");
			$db->do("insert into event (date, event) values ('$date', 'OSJ selected $judge to judge RFJ $number/$revision')");
			$db->do("insert into judgment0history (number, revision, id) values ($number, $revision, last_insert_id())");
			$db->do("insert into judgment0judge (number, revision, id) values ($number, $revision, $judge_id)");
		}
		elsif ($command eq 'recuse') {
			$db->do("insert into event (date, event) values ('$date', 'OSJ recused $judge from RFJ $number/$revision')") or die $dave;
			$db->do("insert into judgment0history (number, revision, id) values ($number, $revision, last_insert_id())");
			$db->do("update judgment0judge set recused = 'y' where number = $number and revision = $revision and id = $judge_id");
		}
	}
	
	$judge = eval "sprintf(\"$judge\")";
	$command .= $command eq 'assign' ? 'ed to' : 'd from';
	print "$judge $command RFJ$number/$revision\n";
}

#
# rfj_ruling: add a Judgment to the database
#
sub rfj_ruling ($) {
	my ($data) = @_;

	# number/revision
	# date
	# judge
	# ruling
	#
	# analysis

	my ($number, $revision, $date, $judge, $ruling, $analysis) = $data =~ m/^(\d+)\/(\d+)\n(.*?)\n(.*?)\n(.*?)\n\n(.*)/s or die "\n$prog: bad '$type $command'";

	$date = convdate($date);
	
	$judge = quotemeta($judge);
	$ruling = quotemeta($ruling);
	$analysis = quotemeta($analysis);
	
	unless ($dry) {
		$db->do("update judgment set ruling='$ruling', j_analysis='$analysis', end = '$date' where number = $number and revision = $revision") or die $dave;
		$db->do("insert into event (date, event) values ('$date', '$judge ruled \"$ruling\" on RFJ $number/$revision')");
		$db->do("insert into judgment0history (number, revision, id) values ($number, $revision, last_insert_id())");
	}

	$judge = eval "sprintf(\"$judge\")";
	print "$judge issued J$number/$revision\n";
}

#
# rule_add: add a new Rule to the database
#
sub rule_add ($) {
	my ($data) = @_;

	# number/revision
	# (P|M)cnum/crev
	# date
	# category[ category]...
	# title
	# 
	# text

	my ($number, $revision, $ctype, $cnum, $crev, $date, $categories, $title, $text) = $data =~ m/^(\d+)\/(\d+)\n(\w)(\d+)\/(\d+)\n(.*?)\n(.*?)\n(.*?)\n\n(.*)/s or die "\n$prog: bad '$type $command'";

	die "\n$prog: bad '$type $command'" unless ($ctype eq 'P' or $ctype eq 'M');

	$date = &convdate($date);

	$title = quotemeta($title);
	$text = quotemeta($text);

	my $orevision = $revision - 1;

	my @category = split / /, $categories;

	unless ($dry) {
		$db->do("insert into rule (number, revision, title, text, start) values ($number, $revision, '$title', '$text', '$date')");
		$db->do("update rule set end = '$date' where number = $number and revision = $revision - 1");
           
		my $cat;
		foreach $cat (@category) {
			$db->do("insert into rule0category (number, revision, category) values ($number, $revision, $cat)");
		}
		
		if ($revision == 0) { $db->do("insert into event (date, event) values ('$date', 'Rule $number/0 created by P$cnum/$crev')"); }
		elsif ($ctype eq 'P') { $db->do("insert into event (date, event) values ('$date', 'Rule $number/$orevision amended by Proposal $cnum/$crev')"); }
		elsif ($ctype eq 'M') { $db->do("insert into event (date, event) values ('$date', 'Rule $number/$orevision trivially amended by Motion $cnum/$crev')"); }
              
		$db->do("insert into rule0history (number, revision, id) values ($number, $revision, last_insert_id())");
	}
	
	print "R$number/$revision added\n";
}

#
# rule_repeal: repeal existing Rule in the database
#
sub rule_repeal ($) {
	my ($data) = @_;

	# number/revision
	# Pcnum/crev
	# date
	
	my ($number, $revision, $cnum, $crev, $date) = $data =~ m/^(\d+)\/(\d)\nP(\d+)\/(\d+)\n(.*)/s or die "\n$prog: bad '$type $command'";

	$date = &convdate($date);

	unless ($dry) {
		$db->do("update rule set end = '$date' where number = $number and revision = $revision");
		$db->do("insert into event (date, event) values ('$date', 'Rule $number/0 repealed by Proposal $cnum/$crev')");
		$db->do("insert into rule0history (number, revision, id) values ($number, $revision, last_insert_id())");
	}
	
	print "R$number/$revision repealed\n";
}

#
# getid: gets id from name, date
#
sub getid ($$) {
	my ($name, $date) = @_;
	return (query("select id from name where name = '$name' and start <= '$date' and (isnull(end) or '$date' <= end)"))[0];
}

#
# getname: gets name from id, date
#
sub getname ($$) {
	my ($id, $date) = @_;
	return (query("select name from name where id = $id and start <= '$date' and (isnull(end) or '$date' <= end)"))[0];
}

#
# convdate: converts dates from 'DD MONTH YYYY HH:SS:MM' to 'YYYY-MM-DD HH:SS:MM'
#
sub convdate ($) {
	my ($date) = @_;
	($date = `date -d '$date' +"%Y-%m-%d %T"`) =~ s/\n//;
	return $date;
}



#########################################################

#	elsif ($type eq 'office') {
#		if ($command eq 'nominate') {
#
#			# Format:
#			#
#			# nweek
#			# nominator
#			# date
#			# nominee
#			# office
#			#
#			# ----
#			
#			# get parts
#			my ($nweek, $nominator, $date, $nominee, $office) = $data =~ m/^(\d+)\n(.*?)\n(.*?)\n(.*?)\n(.*?)\n\n-{4}\n/s or die "bad format";
#			$data = $';
#
#			# convert date
#			$date = &convdate($date);
#
#			# guard text
#			$nominator = quotemeta($nominator);
#			$nominee = quotemeta($nominee);
#			$office = quotemeta($office);
#			
#			# get id
#			my $nominee_id = &getid($nominee, $date);
#			my $nominator_id = &getid($nominator, $date);
#
#			# poke into db
#			unless ($dry) {
#				$db->do("insert into election (nweek, id, nominator, office) values ($nweek, $nominee_id, $nominator_id, '$office')");
#				$db->do("insert into event (date, event) values ('$date', '$nominator nominated $nominee for $office')");
#			}
#
#			print "Player $nominee nominated for $office\n";
#		}
#		elsif ($command eq 'decline') {
#
#			# Format:
#			#
#			# nweek
#			# nominee
#			# date
#			# office
#			#
#			# ----
#
#			# get parts
#			my ($nweek, $nominee, $date, $office) = $data =~ m/^(\d+)\n(.*?)\n(.*?)\n(.*?)\n\n-{4}\n/s or die "bad format";
#			$data = $';
#
#			# convert date
#			$date = &convdate($date);
#			
#			# guard text
#			$nominee = quotemeta($nominee);
#			$office = quotemeta($office);
#
#			# get nominee id
#			my $nominee_id = &getid($nominee, $date);
#
#			# poke into db
#			unless ($dry) {
#				$db->do("update election set vitality = 'd', decline = 'y' where id = $nominee_id and office = '$office' and nweek = $nweek");
#				$db->do("insert into event (date, event) values ('$date', '$nominee declined nomination for $office')");
#			}
#
#			print "Player $nominee declined nomination for $office\n";
#		}
#		elsif ($command eq 'tie') {
#
#			# Format:
#			#
#			# date
#			# office
#			# officer
#			#
#			# ----
#			
#			# get parts
#			my ($date, $office, $officer) = $data =~ m/^(.*?)\n(.*?)\n(.*?)\n\n-{4}\n/s or die "bad format";
#			$data = $';
#
#			# convert date
#			$date = &convdate($date);
#
#			# guard text
#			$office = quotemeta($office);
#			$officer = quotemeta($officer);
#
#			# get officer id
#			my $officer_id = &getid($officer, $date);
#
#			# poke into db
#			unless ($dry) {
#				$db->do("update officer set end = '$date' where office = '$office' and isnull(end)");
#				$db->do("insert into officer (id, office, start, admin) values ($officer_id, '$office', '$date', 0)");
#				$db->do("insert into event (date, event) values ('$date', 'Administrator selected $officer for $office')");
#			}
#
#			print "$officer selected for $office\n";
#		}
#		else { die "bad command"; }
#	}
#	elsif ($type eq 'voting') {
#		if ($command eq 'motion' or $command eq 'proposal' or $command eq 'election') {
#			my ($nweek, $bdate, $edate, $quorum, $nums, $offices, $votes, @num, @rev, @office, @tmp, @vote, @name, $adopted, $opposed, $failed);
#		
#			if ($command eq 'motion' or $command eq 'proposal') {
#
#				# Format:
#				#
#				# bdate
#				# edate
#				# quorum
#				# adopted opposed failed
#				#
#				# num/rev[ num/rev]...
#				#
#				# name
#				# vote[ vote]...
#				#
#				# ----
#
#				# get parts
#				($bdate, $edate, $quorum, $adopted, $opposed, $failed, $nums, $votes) = $data =~ m/^(.*?)\n(.*?)\n(.*)\n(\d+) (\d+) (\d+)\n\n(.*?)\n\n(.*?)\n\n-{4}\n/s or die "bad format";
#				$data = $';
#
#				# get prop numbers
#				@tmp = split / /, $nums;
#				for $i (0 .. $#tmp) { ($num[$i], $rev[$i]) = $tmp[$i] =~ m/(\d+)\/(\d+)/ or die "bad format"; } 
#
#			}
#			elsif ($command eq 'election') {	
#
#				# Format
#				#
#				# nweek
#				# bdate
#				# edate
#				# quorum
#				#
#				# office[, office]...
#				#
#				# name
#				# vote[, vote]...
#				#
#				# ----
#
#				# get parts
#				($nweek, $bdate, $edate, $quorum, $offices, $votes) = $data =~ m/^(\d+)\n(.*?)\n(.*?)\n(.*?)\n\n(.*?)\n\n(.*?)\n\n-{4}\n/s or die "bad format";
#				$data = $';
#
#				# get offices
#				@office = split /, /, $offices;								
#			}
#	
#			# convert dates
#			$bdate = &convdate($bdate);
#			$edate = &convdate($edate);
#
#			# get names and votes
#			@tmp = split /\n/, $votes;
#			for $i (0 ..  int($#tmp / 2)) {
#				$name[$i] = $tmp[2*$i];
#				my $spl = $command eq 'election' ? ', ' : ' ';
#				push @vote, [ split /$spl/, $tmp[2*$i+1] ];
#			}
#
#			# calculate quorum
#			if ($quorum eq 'vote') {
#				$quorum = 0;
#				for $i (0 .. $#vote) { 
#					VOTE: for $j (0 .. $#num) {
#						if ($vote[$i][$j] ne '-') {
#							$quorum++;
#							last VOTE;
#						}
#					}
#				}
#			}
#
#			# poke voting period into db if not already
#			my ($tmp) = query("select event from event where date = '$bdate' and event = 'Voting began'");
#			if (defined($tmp) and $tmp eq 'Voting began') { print "\nVoting exists, not added"; }
#			else {
#				unless ($dry) {
#					$db->do("insert into event (date, event) values ('$bdate', 'Voting began')");
#					$db->do("insert into event (date, event) values ('$edate', 'Voting ended, quorum was $quorum')");
#				}
#				print "\nVoting added";
#			}
#			
#			if ($command eq 'proposal' or $command eq 'motion') {
#				my @score = ();
#	
#				# calculate passage
#				for $i (0 .. $#num) {
#					my ($yea, $nay, $abs, $not, $result) = (0, 0, 0, 0, 0);
#					for $j (0 .. $#name) {
#						$yea++ if $vote[$j][$i] eq 'y';
#						$nay++ if $vote[$j][$i] eq 'n';
#						$abs++ if $vote[$j][$i] eq 'a';
#						$not++ if $vote[$j][$i] eq '-';	
#				
#						# poke individual voting into db
#						unless ($dry) {				
#							my $voter_id = &getid(quotemeta($name[$j]), $edate);
#							$db->do("insert into ${command}0voting (number, revision, id, date, vote) values ($num[$i], $rev[$i], $voter_id, '$edate', '$vote[$j][$i]')");
#						}
#					}
#					
#					$result = ($yea + $nay + $abs) >= $quorum ? ($yea > $nay ? "passed" : "failed") : "held";
#					printf("\n%s%d/%d %s (%d-%d-%d-%d)", $command eq 'proposal' ? 'P' : 'M', $num[$i], $rev[$i], $result, $yea, $nay, $abs, $not);
#			
#					# poke voting result into db
#					unless ($dry) {
#						$db->do("update $command set end = '$edate' where number = $num[$i] and revision = $rev[$i]") unless $result eq 'held';
#						$db->do("insert into event (date, event) values ('$edate', '\u$command $num[$i]/$rev[$i] $result ($yea-$nay-$abs-$not)')") or die $dave;
#						$db->do("insert into ${command}0history (number, revision, id) values ($num[$i], $rev[$i], last_insert_id())");
#					}
#
#					if ($command eq 'proposal' and $result ne 'held') {
#						# calculate scoring
#						my ($owner_id) = query("select owner from proposal where number = $num[$i] and revision = $rev[$i]");
#						
#						if ($result eq 'passed') {
#							# adopted proposal award
#							push @score, [ $owner_id, $adopted ];
#	
#							# opposed minority award
#							for $j (0 .. $#name) {
#								if ($vote[$j][$i] eq 'n') {
#									push @score, [ &getid(quotemeta($name[$j]), $edate), $opposed ];
#								}
#							}
#						}
#						elsif ($result eq 'failed') {
#							# failed proposal fee
#							push @score, [ $owner_id, -1 * $failed ];
#						}
#						else { die "Doh!"; }
#					}
#				}
#
#				# print scoring
#				my @scored = ();
#				for $i (0 .. $#score) {
#					push @scored, $score[$i][0] if !(grep $_ == $score[$i][0], @scored);
#				}
#
#				print "\n\nScoring\n";
#
#				for $i (0 .. $#scored) {
#
#					my ($total, @breakdown) = ();
#					for $j (0 .. $#score) {
#						if ($score[$j][0] == $scored[$i]) { 
#							push @breakdown, $score[$j][1];
#							$total += $score[$j][1];
#						}
#					}
#					print &getname($scored[$i], $edate), " $total (", (join ', ', @breakdown), ")\n";
#				}
#			}
#			elsif ($command eq 'election') {
#				# calculate results
#				for $i (0 .. $#office) {
#					my $sth = $db->prepare("select name.name from name, election where nweek = $nweek and name.id = election.id and election.office = '$office[$i]' and election.decline = 'n' order by name.name");
#					$sth->execute;
#
#					my (@candidate, $tmp) = ();
#					while (($tmp) = $sth->fetchrow_array) { push @candidate, [ $tmp, 0]; }
#					$sth->finish;				
#
#					for $j (0 .. $#name) { 
#						for $k (0 .. $#candidate) { $candidate[$k][1]++ if $vote[$j][$i] eq $candidate[$k][0]; }
#			
#						# poke individual voting into db
#						unless ($dry) {
#							my $voter_id = &getid(quotemeta($name[$j]), $edate);
#							my $vote_id = $vote[$j][$i] eq '-' ? '-' : &getid(quotemeta($vote[$j][$i]), $edate);
#							$db->do("insert into ${command}0voting (nweek, id, vote, office, date) values ($nweek, $voter_id, '$vote_id', '$office[$i]', '$edate')");
#						}
#					}
#	
#					for $k (0 .. $#candidate) { print "\n $candidate[$k][0]: $candidate[$k][1]"; }	
#
#					my @max;
#					$max[0] = 0;
#					for $j (1 .. $#candidate) {
#						if ($candidate[$j][1] > $candidate[$max[0]][1] ) { $#max = 0; $max[0] = $j; }
#						elsif ($candidate[$j][1] == $candidate[$max[0]][1]) { push @max, $j; }
#					}
#				
#					$result = '';	
#					if ($#max == 0) { $result = "$candidate[$max[0]][0] elected"; }
#					else {
#						foreach (@max) { $result .= "$candidate[$_][0], "; }
#						$result =~ s/, $/ /;
#						$result .= "tied for";
#					}
#
#					print "\n$result $office[$i]";
#				
#					# poke results into db
#					unless ($dry) {
#						$result = quotemeta($result);
#						$db->do("update election set vitality = 'd' where nweek = $nweek and office = '$office[$i]'");
#						$db->do("insert into event (date, event) values ('$edate', '$result $office[$i]')");
#						$db->do("update officer set end = '$edate' where office = '$office[$i]' and isnull(end)");
#						if ($#max == 0) {
#							my $elected_id = &getid($candidate[$max[0]][0], $edate);
#							$db->do("insert into officer (id, office, start, admin) values ($elected_id, '$office[$i]', '$edate', 0)");
#						}
#						else { $db->do("insert into officer (id, office, start, admin) values (0, '$office[$i]', '$edate', 1)"); }
#					}
#				}
#			}
#			
#			print "\n";
#		}
#		else { die "bad command"; }
#	}
#	else { die "bad type"; }
#
#}

