#! /usr/bin/perl

use ccbs;
use strict;
use warnings;

ccbs::admin_only();

my $dbh = ccbs::db_connect();
my $cgi = new CGI;

$dbh->{AutoCommit} = 0;

my $tournament = $cgi->param('tournament');
my %already_ordered = ();
my $ranking = 1;
my $points = 100;

# Find all last rounds with only one group per round
my $srounds = ccbs::db_fetch_all($dbh, 'SELECT round FROM groups WHERE tournament=? GROUP BY round HAVING COUNT(*) = 1 ORDER BY round DESC', $tournament);

my $last_sround;
for my $sr (@$srounds) {
	# only accept strict ordering
	last if (defined($last_sround) && $sr->{'round'} != $last_sround - 1);
	$last_sround = $sr->{'round'};

	# Grab the highscore list from this round
	my $scores = ccbs::db_fetch_all($dbh, 'SELECT player,SUM(score) AS score FROM scores WHERE tournament=? AND round=? GROUP BY parallel,player ORDER BY SUM(score) DESC',
		$tournament, $sr->{'round'});
	for my $s (@$scores) {
		next if ($already_ordered{$s->{'player'}});
		$dbh->do('INSERT INTO tournamentrankings (tournament, ranking, player, points) VALUES (?,?,?,?)',
			undef, $tournament, $ranking, $s->{'player'}, points_for_place($ranking));
		$ranking++;
		$already_ordered{$s->{'player'}} = 1;
	}
}

# This should never happen
if (!defined($last_sround)) {
	ccbs::user_error("Forsøk på å avslutte en turnering med flere grupper aktive.");
}

# Grab all the remaining groups; we order by the simple criteria:
# 1. If player A has gone to group X and player B hasn't, player A is higher.
# 2. If player A has a higher ranking in his/her group than player B, player A is higher.
# 3. If player A has higher max score than player B, player A is higher.

# Basically, #2 makes this impossible to achieve in pure SQL. We just have
# to fetch one and one group and make the best out of it. Fetch out all the
# parallels (in sorted order) and grab all players in turn.

my $qscores = $dbh->prepare('SELECT parallel,player,SUM(score) AS sum_score,MAX(score) AS max_score FROM scores WHERE tournament=? AND round=? GROUP BY parallel,player ORDER BY SUM(score) DESC');
for my $r (reverse (1..($last_sround-1))) {
	my @parallels = ();
	my $num_players = 0;
	
	$qscores->execute($tournament, $r);

	while (my $ref = $qscores->fetchrow_hashref()) {
		my $p = $ref->{'parallel'};
		if (!defined($parallels[$p])) {
			$parallels[$p] = [];
		}

		push @{$parallels[$p]}, {%$ref};
		$num_players++;
	}

	my $place = 0;

	# Grab players from the top until nobody's left
	while ($num_players > 0) {
		my @players_this_place = ();
		for my $p (@parallels) {
			next if (!defined($p->[$place]));
			$num_players--;
			next if ($already_ordered{$p->[$place]->{'player'}});

			push @players_this_place, $p->[$place];
		}

		@players_this_place = sort { $b->{'max_score'} <=> $a->{'max_score'} } @players_this_place;

		for my $s (@players_this_place) {
			$dbh->do('INSERT INTO tournamentrankings (tournament, ranking, player, points) VALUES (?,?,?,?)',
				undef, $tournament, $ranking, $s->{'player'}, points_for_place($ranking));
			$ranking++;
			$already_ordered{$s->{'player'}} = 1;
		}

		$place++;
	}
}

$dbh->commit;
$dbh->disconnect;

ccbs::print_see_other('show-tournament.pl?id=' . $tournament);

# gives the usual 100, 91, 83, 76. 65, 61, ... series
sub points_for_place {
	my $n = shift;
	if ($n <= 10) {
		return 110 - (21/2) * $n + (1/2) * $n * $n;
	} elsif ($n <= 65) {
		return 65 - $n;
	} else {
		return 0;
	}
}
