#!/usr/bin/perl -s

use common::sense;
use Math::MatrixReal 2.11;
use Sereal::Encoder qw.encode_sereal.;
use Math::GSL::Matrix ':all';
use Math::GSL ':all';

our (
	$f,    # force writing file
	$gsl,  # output as a gsl;
	);

my ($input, $output) = @ARGV;

# check options
die "input file not specified\n"  unless $input;
die "output file not specified\n" unless $output;
die "input file [$input] not found: $!\n" unless -f $input;
die "output file exists. Won't write without force (-f)\n" if -f $output && !$f;

if ($gsl) {
	gsl_serialize_thetas(load_thetas($input), $output);
} else {
	serialize_thetas(load_thetas($input), $output);
}

sub gsl_serialize_thetas {
	my ($Thetas, $output) = @_;

	print STDERR "Serializing into $output...\n";

	my $fh = gsl_fopen($output, "wb");

	my $v = gsl_matrix_alloc(1,1);
	gsl_matrix_set($v, 0, 0, scalar(@$Thetas)+1);
	my $l = gsl_matrix_alloc(@$Thetas+1, 1);

	for my $i (0 .. @$Thetas-1) {
		my ($rows, $cols) = $Thetas->[$i]->dim();
		gsl_matrix_set($l, $i, 0, $cols-1);
		gsl_matrix_set($l, $i+1, 0, $rows);
	}

	gsl_matrix_fwrite($fh, $v);
	gsl_matrix_fwrite($fh, $l);

	for my $m (@$Thetas) {
		my ($rows, $cols) = $m->dim();
		my $matrix = gsl_matrix_alloc($rows,$cols);
		for my $i (1..$rows) {
			for my $j (1..$cols) {
				gsl_matrix_set($matrix, $i-1, $j-1, $m->element($i, $j));
			}
		}
		gsl_matrix_fwrite($fh, $matrix);
		gsl_matrix_free($matrix);
	}

	gsl_fclose($fh);
}

sub serialize_thetas {
	my ($Thetas, $output) = @_;

	print STDERR "Serializing into $output...\n";

	open OUT, ">:raw", $output or die "Can't create file $output: $!\n";
	print OUT encode_sereal($Thetas, { snappy => 1 });
	close OUT;
}

sub load_thetas {
	my $filename = shift;

	print STDERR "Loading $filename...\n";

	my @thetas = ();
	my @values = ();
	open my $fh, "<", $filename or die "Can't open file $filename: $!";
	while (<$fh>) {
		next if /^#/;
		chomp;
		push @values, $_;
	}
	close $fh;

	my $L = shift @values;

	my @arch;
	for (1..$L) {
		push @arch, shift @values;
	}

	my $p = 0;
	for my $i (1..$L-1) {
		my $rows = $arch[$i];
		my $cols = $arch[$i-1] + 1;
		push @thetas, Math::MatrixReal->reshape($rows, $cols,
 									[@values[$p .. $p + $rows*$cols - 1]]);
		$p += $rows*$cols;
	}
	return \@thetas;
}
