#! /usr/bin/perl -w
use strict;
use List::Util;
use Digest::MD5 qw(md5);
use POSIX qw(strftime);

my $num_submit_hosts = 3;
my $num_users = 5;

srand(0);

my @cheese = qw( brick brie camembert cheddar cheshire colby coldpack cottage cream edam feta farmers gjetost gorgonzola gouda gruyere limburger mozzarella muenster mysost neufchatel parmesan provolone ricotta romano roquefort stilton swiss tilsit);

my @surnames = qw( smith johnson williams jones brown davis miller wilson moore taylor anderson thomas jackson white harris martin thompson garcia martinez robinson clark rodriguez lewis lee walker );

my $domain = 'example.com';

my @submit_hosts = map { "$_.$domain" } draw_n_random($num_submit_hosts, @cheese);

my @users = map { "$_\@$domain" } draw_n_random($num_users, @surnames);

my @statuses = qw(Idle Running Held);

my $MINUTE = 60;
my $HOUR = 60 * $MINUTE;
my $day = 24 * $HOUR;
my $week = 7 * $day;
my $monthish = 30.5 * $day;

#my $LAST_DATE = 1449003077; # Roughly Dec 1 2015
#my $LAST_DATE = 1467349200; # Roughly July 1, 2016
my $LAST_DATE = time() + 60*60*24; # Tomorrow.

exit main();

sub main {
	create_submitter_files();
}

sub epoch_to_iso {
	my($ctime) = @_;
	my($sec,$min,$hour,$mday,$mon,$year) = localtime($ctime);
	return sprintf("%04d-%02d-%02dT%02d:%02d:%02d", $year+1900, $mon+1, $mday, $hour, $min, $sec);
}

sub epoch_to_monthly {
	return strftime("%Y-%m",localtime($_[0]));
}

sub epoch_to_weekly {
	return strftime("%G-W%V",localtime($_[0]));
}

sub epoch_to_daily {
	return strftime("%Y-%m-%d",localtime($_[0]));
}

sub submitter_count {
	my($ctime, $name, $machine, $status) = @_;
	$ctime = $ctime / (60*60*24);
	my $hash = unpack("I",md5("$name|$machine|$status"));
	my $fraction = perlin_noise($ctime + $hash);
	$fraction -= 0.5; # want about 10% empty
	my $machines = int($fraction * 200);
	if($status eq 'Held') { $machines -= 50; }
	if($status eq 'Running') { $machines -= 25; }
	if($machines < 0) { $machines = 0; }
	return $machines;
}

sub submitter_record {
	my($ctime, $name, $machine, $status) = @_;
	my $count = submitter_count($ctime, $name, $machine, $status);
	my $date = epoch_to_iso($ctime);
	return <<END;
{
"Date":"$date",
"Name":"$name",
"Machine":"$machine",
"JobStatus":"$status",
"Count":"$count"
},
END
}

sub create_submitter_file {
	my($now, $step, $end, $basename, $datefunc) = @_;

	my $filename ='';
	my $fh;
	for(; $now < $end; $now += $step) {
		my $newfile = $basename."".$datefunc->($now).".json";
		if($newfile ne $filename) {
			$filename = $newfile;
			open $fh, '>', $filename or die "unable to open(>$filename): $!";
		}
		foreach my $name (@users) {
			foreach my $machine (@submit_hosts) {
				foreach my $status (@statuses) {
					print $fh submitter_record($now, $name, $machine, $status);
				}
			}
		}
	}
}


sub create_submitter_files {

	my $end = $LAST_DATE;
	my $start_daily = $end - 3*$day;
	my $start_weekly = $end - 3*$week;
	my $start_monthly = $end - 24*$monthish;

	create_submitter_file($start_monthly, $day/4, $end, "data/submitter.monthly.", \&epoch_to_monthly);
	create_submitter_file($start_weekly, $HOUR*2, $end, "data/submitter.weekly.", \&epoch_to_weekly);
	create_submitter_file($start_daily, $MINUTE*15, $end, "data/submitter.daily.", \&epoch_to_daily);
	open my $fh, '>', "data/submitter.oldest.json" or die "Unable to open >submitter.oldest: $!";

	my $oldest_daily = epoch_to_daily($start_daily);
	my $oldest_weekly = epoch_to_weekly($start_weekly);
	my $oldest_monthly = epoch_to_monthly($start_monthly);
	print $fh <<END;
{
"monthly": "$oldest_monthly",
"weekly": "$oldest_weekly",
"daily": "$oldest_daily"
}
END
	close $fh;


}

sub draw_n_random {
	my $count = shift;
	my @list = List::Util::shuffle(@_);
	return @list[0..($count-1)];
}



# Algorithm based on http://freespace.virgin.net/hugo.elias/models/m_perlin.htm
# except noise1, which is based on https://stackoverflow.com/questions/3062746/special-simple-random-number-generator 
sub perlin_noise {
	sub noise1 {
		my($x) = int($_[0]);
		my $int = (1103515245*$x+12345)%(2**32);
		return $int / (2**32);
	}

	sub smoothed_noise_1 {
		my($x) = @_;
		return noise1($x)/2 + noise1($x-1)/4 + noise1($x+1)/4
	}

	sub interpolate {
		my($a, $b, $x) = @_;
		my $ft = $x* 3.1415927;
		my $f = (1-cos($ft))*0.5;
		return  $a*(1-$f) + $b*$f
	}

	sub interpolated_noise_1 {
		my($x) = @_;
		my($int_x) = int($x);
		my($fract_x) = $x - $int_x;
		my $v1 = smoothed_noise_1($int_x);
		my $v2 = smoothed_noise_1($int_x+1);
		return interpolate($v1, $v2, $fract_x);
	}
	my($x) = @_;
	my $total = 0;
	my $persistence = 0.3;
	my $octaves = 10;
	for(my $i = 0; $i < $octaves; $i++) {
		my $frequency = 2**$i;
		my $amplitude = $persistence**$i;
		$total += interpolated_noise_1($x*$frequency)*$amplitude
	}
	return $total;
}
