#! /usr/bin/perl -w
use strict;
use POSIX qw(strftime mktime);
use Date::Manip;

my $start_year = 1990;
my $end_year = 2100;

my @test_groups;


sub create_tests_parseMore {
	my $test_group = {};
	$test_group->{name} = 'datext.js Date.parseMore: YYYY-Www dates';
	$test_group->{tests} = '';

	for(my $year = $start_year; $year < $end_year; $year++) {
		for(my $week = 1; $week <= 53; $week++) {
			my $date = sprintf("%04d-W%02d", $year, $week);
			my $dm = ParseDate($date);
			my $fulldate = UnixDate($dm, "%O.000Z");
			if(length($test_group->{tests})) { $test_group->{tests} .= ",\n"; }
			$test_group->{tests} .= "      [try_parseMore, '$date', '$fulldate']";
		}
	}
	return $test_group;
}
push @test_groups, create_tests_parseMore();

sub create_tests_getISOWeekDate {
	my $test_group = {};
	$test_group->{name} = 'datext.js Date.getISOWeekDate';
	$test_group->{tests} = '';


	my $now = mktime(0, 0, 0, 1, 0, $start_year-1900);
	my $end = mktime(0,0, 12, 1,0, $end_year-1900);
	my $last_year = 0;
	while($now < $end) {
		my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($now);
		my $input = strftime("%Y-%m-%dT%H:%M:%S",localtime($now));
		my $expected = strftime("%G-W%V",localtime($now));
		if(length($test_group->{tests})) { $test_group->{tests} .= ",\n"; }
		$test_group->{tests} .= "      [try_getISOWeekDate, '$input', '$expected']";
		$now += 60*60*24;
	}
	return $test_group;
}
push @test_groups, create_tests_getISOWeekDate();

sub create_tests_getISOWeekDateUTC {
	my $test_group = {};
	$test_group->{name} = 'datext.js Date.getISOWeekDate with UTC dates';
	$test_group->{tests} = '';


	my $now = mktime(0, 0, 0, 1, 0, $start_year-1900);
	my $end = mktime(0,0, 12, 1,0, $end_year-1900);
	my $last_year = 0;
	while($now < $end) {
		my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($now);
		my $input = strftime("%Y-%m-%dT%H:%M:%S.000Z",localtime($now));
		my $expected = strftime("%G-W%V",localtime($now));
		if(length($test_group->{tests})) { $test_group->{tests} .= ",\n"; }
		$test_group->{tests} .= "      [try_getISOWeekDate, '$input', '$expected']";
		$now += 60*60*24;
	}
	return $test_group;
}
push @test_groups, create_tests_getISOWeekDateUTC();

sub create_tests_roundtripweek {
	my $test_group = {};
	$test_group->{name} = 'datext.js ISOWeekDate round trip';
	$test_group->{tests} = '';

	my $now = mktime(0, 0, 0, 1, 0, $start_year-1900);
	my $end = mktime(0,0, 12, 1,0, $end_year-1900);
	my $last_year = 0;
	while($now < $end) {
		my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($now);
		my $input = strftime("%Y-%m-%dT%H:%M:%S",localtime($now));
		if(length($test_group->{tests})) { $test_group->{tests} .= ",\n"; }
		$test_group->{tests} .= "      [try_round_trip_week, '$input', true]";
		$now += 60*60*24;
	}

	return $test_group;
}
push @test_groups, create_tests_roundtripweek();




print <<END;
<!doctype html>
<htmlUTC>
<head>
  <meta charset="utf-8">
  <title>Date testing</title>
<script src="dateext.js"></script>
</head>
<body>
<div>
<progress id="pbar" value="0" max="100"></progress>
<span id="progress"></span>
</div>
<div id="output"></div>
<script>

var outdiv;
var progressdiv;
var progressbardiv;

function add_h1() {
	var args_arr = Array.prototype.slice.call(arguments);
	var s = args_arr.join(" ");
	var p = document.createElement("h1");
	var txt = document.createTextNode(s);
	p.appendChild(txt);
	outdiv.appendChild(p);
}

function add_paragraph() {
	var args_arr = Array.prototype.slice.call(arguments);
	var s = args_arr.join(" ");
	var p = document.createElement("p");
	var txt = document.createTextNode(s);
	p.appendChild(txt);
	outdiv.appendChild(p);
}

function progress() {
	var args_arr = Array.prototype.slice.call(arguments);

	var final = args_arr.shift();
	if(this.last_update === undefined) { this.last_update = 0; }
	if(!final && (this.last_update+100)>Date.now()) {
		return;
	}

	this.last_update = Date.now();

	while (progressdiv.firstChild) {
		progressdiv.removeChild(progressdiv.firstChild);
	}

	var s = args_arr.join(" ");
	var txt = document.createTextNode(s);
	progressdiv.appendChild(txt);
}

function try_parseMore(i) { return Date.parseMore(i).toISOString(); }

function try_getISOWeekDate(i) { return Date.parseMore(i).getUTCISOWeekDate(); }

function try_round_trip_week(i) {
	var initial = new Date(i);
	var week_start = initial.getUTCISOWeekDate();
	var back_to_obj = Date.parseMore(week_start);
	var week_end = back_to_obj.getUTCISOWeekDate();
	if(week_start === week_end) { return true; }
	return week_start + " became " + back_to_obj.toISOString() + " became " + week_end;
}


END
print "test_groups = [\n";

for(my $group = 0; $group < @test_groups; $group++) {
	print qq(  { name: "$test_groups[$group]{name}",\n);
	print qq(    tests: [\n);
	print $test_groups[$group]{tests},"\n";
	print qq(    ] });
	if(($group+1) != @test_groups) {
		print ",";
	}
	print "\n";
}

print "];\n";
print <<END;

var group_num = 0;
var test_num = 0;

var group_success = 0;
var group_fail = 0;

var total_possible = 0;
var total_success = 0;
var total_fail = 0;

var current_test_start;
var max_run_time = 10;

function run_next_tests_impl() {
	while(true) {

		if(group_num >= test_groups.length) {
			progress(true, "done");
			return;
		}
		var num_tests_in_group = test_groups[group_num].tests.length;
		progress(false, total_success+total_fail,"/",total_possible);
		progressbardiv.setAttribute("value", total_success+total_fail);
		if(test_num >= num_tests_in_group) {
			test_num = 0;
			add_paragraph(group_success, "/", num_tests_in_group, "succeeded.", group_fail, "/", num_tests_in_group, "failed.", "Found", group_success+group_fail, "out of", num_tests_in_group, "tests.");
			group_num++;
			group_success = 0;
			group_fail = 0;
			if(run_next_tests()) { return; }
			continue;
		}
		if(test_num === 0) {
			add_h1(group_num, test_groups[group_num].name);
		}
		var func = test_groups[group_num].tests[test_num][0];
		var input = test_groups[group_num].tests[test_num][1];
		var expected = test_groups[group_num].tests[test_num][2];
		var actual;
		var funcname;
		if(func.name) { funcname = func.name; }
		else { funcname = func; }
		try {
			actual = func(input);
		} catch (e) {
			add_paragraph("Failed:", test_num, funcname+"("+input+") EXCEPTED with", e, "!=", expected);
			group_fail++;
			total_fail++;
			test_num++;
			if(run_next_tests()) { return; }
			continue;
		}
		if(actual === expected) {
			group_success++;
			total_success++;
		} else {
			add_paragraph("Failed:", test_num, funcname+"("+input+") ->", actual, "!=", expected);
			group_fail++;
			total_fail++;
		}
		test_num++;
		if(run_next_tests()) { return; }
	}
}

function run_next_tests() {
	var now = Date.now();
	if(current_test_start === undefined) { current_test_start = 0; }
	if((current_test_start+10) > now) {
		return false;
	}
	//console.log(group_num, test_num);
	current_test_start = Date.now();
	setTimeout(run_next_tests_impl, 0);
	return true;
}

function count_all_tests() {
	var g;
	var count = 0;;
	for(g = 0; g < test_groups.length; g++) {
		count += test_groups[g].tests.length;
	}
	return count;
}

window.onload = function() {
	outdiv = document.getElementById('output');
	progressdiv = document.getElementById('progress');
	progressbardiv = document.getElementById('pbar');
	total_possible = count_all_tests();
	progressbardiv.setAttribute("max", total_possible);
	run_next_tests();
}


</script>
</body>
</html>
END


