#!/usr/bin/perl

##############################################################
# Paolo Ferragina @ August 2008
#
# Loads the array of permuted positions: _PermutedPos_.txt
# Loads the array of page sizes: _PageSizes_.txt
# 
# Computes the final offsets for each page and scan the STDIN
# writing out the pages in their correct positions as they are
# found in this scanning. I/Os are amortized since pages are
# few Kbs on avg.
# The output is written in _FinalPermuted_.txt
##############################################################

use bytes;
use Fcntl 'SEEK_CUR';
sub systell { sysseek($_[0], 0, SEEK_CUR) }

$psize = 0;
$page_num = 0;
$row="";           ## currently parsed row

if(scalar(@ARGV) < 2){
    print "Error: you need to specify FilePermPos + FilePageSizes!\n\n";
    print "Recall that the STDIN provides the file of pages to be permuted.\n\n";
    exit;
}

$file_permPos = shift @ARGV;
$file_pageSize = shift @ARGV;


# Load the array of permuted docIDs
print "\nLoad the positions...\n";
open(INPERM,"<$file_permPos") || die "Not Perm file!\n";
while ($row = <INPERM>) {
    chomp($row);
    $row += 0;
    $permutation[$page_num] = $row;
    $page_num++;
}
close(INPERM);
print "Done!\n";

print "\nLoad the size...\n";
# Load the array of page sizes
$pp = 0;
open(INSIZES,"<$file_pageSize") || die "Not Size file!\n";
while ($row = <INSIZES>) {
    chomp($row);
    $row += 0;
    $psize_array[$pp] = $row;
    $pp++;
}
close(INSIZES);
print "Done!\n";

if($pp != $page_num){
    print "Difference in num pages between PERM and SIZE files!\n";
    exit;
}

print "\nCompute offsets...\n";
# Permute the sizes to determine the right offset
@permuted_sizes = ();
for($i=0; $i < $page_num; $i++){
    $permuted_sizes[$permutation[$i]] = $psize_array[$i];
}


# Prefix sum of the sizes
for($i=1; $i < $page_num; $i++){
    $permuted_sizes[$i] += $permuted_sizes[$i-1];
}


# Final position of a page
@final_pos = ();
for($i=0; $i < $page_num; $i++){
    $final_pos[$i] = $permuted_sizes[$permutation[$i]] - $psize_array[$i];
}
print "Done!\n";


open(OUTFILE, ">_FinalPermuted_.txt");

# Just sets the last bytes for sanity check....
sysseek OUTFILE, $permuted_sizes[$page_num-1]-1, SEEK_SET;
syswrite OUTFILE, " ";

$pCurr = 0;
$PageCurr ="";

while ($row = <STDIN>) {

    chomp($row);
    $row .= "\n";

    if ($row =~ m/^warc\/0\.9/) { 

	if ($pCurr % 100000 == 0){
	    print "$pCurr\n";
	}

	if ($pCurr > 0) {    

	    if ($psize_array[$pCurr-1] != length($PageCurr)){
		print "Error $pCurr\n";
		print $PageCurr;
		print "\n\n";
		exit;
	    }
	    $xx = sysseek OUTFILE, $final_pos[$pCurr-1], SEEK_SET;
	    $xx +=0;
	    if ($xx != $final_pos[$pCurr-1]){
		print $xx . "\n\n";
		print $final_pos[$pCurr-1] . "\n\n";
		print "\nError in seeking $pCurr\n\n";
		exit;
	    }
	    syswrite OUTFILE, $PageCurr;
	    if (systell(OUTFILE) != ($final_pos[$pCurr-1]+$psize_array[$pCurr-1] )){
		print systell(OUTFILE) . "\n\n";
		print $final_pos[$pCurr-1]+$psize_array[$pCurr-1] . "\n\n";
		print "\nError in writing $pCurr\n\n";
		exit;
	    }

	}

	$pCurr++;
	$PageCurr = "";
    }

    # In all cases (also if we flushed a block)
    $PageCurr .= $row;
}


# Something is still buffered
sysseek OUTFILE, $final_pos[$pCurr-1], SEEK_SET;
syswrite OUTFILE, $PageCurr;

close(OUTFILE);

