use strict; use warnings;

our ($lock_file, $booked_file, $static_file, $cancelled_file, $holidays_file, $info_file, $static_info_file);
our ($laptops_file, $laptops_log_file);
our ($booked, $static, $cancelled, $booked_x, $static_x, $cancelled_x, $holidays, $info, $info_x, $static_info, $static_info_x);
our ($changed_cancelled, $changed_booked, $changed_static, $changed_info, $changed_static_info, $changed_bookings_conf, $changed_holidays);
our ($short_uid_type);  # descriptive, for messages

our ($conf);

$lock_file = "bookings.lock";
$booked_file = "bookings.data";
$static_file = "bookings.static.data";
$cancelled_file = "bookings.cancelled.data";
$holidays_file = "holidays.conf";
$info_file = "bookings.info.data";
$static_info_file = "bookings.static.info.data";
$laptops_file = "laptops.data";
$laptops_log_file = "laptops.log.data";

use IO::File;

sub test_perms {
	my @files = ($booked_file, $static_file, $cancelled_file, $holidays_file, $info_file, $static_info_file);
	push @files, "bookings.conf";
	if ($conf->{laptops}) {
		push @files, $laptops_file, $laptops_log_file;
	}
	my @backups;
	for (@files) { push @backups, "$_~"; }
	push @files, @backups;
#	push @files, $lock_file;

	my @dirs = ("backups", "paranoia_backups", "recovery_backups");

	my @problems;

	for (@files) {
		if (!test_can_write_file($_)) {
			push @problems, "cannot write to the file $_\n";
		};
	}
	for (@dirs) {
		if (!test_can_write_dir($_)) {
			push @problems, "cannot write to the directory $_\n";
		};
	}

	if (@problems) {
		my $problems = join "", @problems;

		die <<End;
Uhoh, file permissions in the bookings program's database are incorrect,
please contact your computer technicians; they can fix this problem.

Here are some details... you don't need to write down these details,
because how to fix it is written in this file:
  cgi-bin\\0README.1st.txt

$problems
End
	}
}

sub test_can_write_file {
	my ($file) = @_;
	if (my $fh = IO::File->new($file, "a")) {
		close $fh;
		return 1;
	} else {
		return 0;
	}
}

sub test_can_write_dir {
	my ($dir) = @_;
	my $testfile = "$dir\\.testfile";
	if (my $fh = IO::File->new($testfile, "w")) {
		close $fh;
		unlink $testfile;
		return 1;
	} else {
		return 0;
	}
}

sub load_calendar_data {
	# load and index data files
	# the data is stored in tsv, 4 columns, which are:
	#  YMD  PERIOD  RESOURCE  WHO
	# the holidays table is different:
	#  YMD-START  YMD-END  DESCRIPTION
	# FIXME the static table should be:
	#  WDAY  PERIOD  RESOURCE  WHO
	load_booked();
	load_static();
	load_cancelled();
	load_holidays();
	load_info();
	load_static_info();
}
sub load_booked {
	$booked = read_tsv($booked_file, 1);
	fix_caps_ids_last_field($booked);
	$booked_x = table_to_index($booked);
	$changed_booked = 0;
}
sub load_static {
	$static = read_tsv($static_file, 1);
	fix_caps_ids_last_field($static);
	$static_x = table_to_index($static);
	$changed_static = 0;
}
sub load_cancelled {
	$cancelled = read_tsv($cancelled_file, 1);
	fix_caps_ids_last_field($cancelled);
	$cancelled_x = table_to_index($cancelled);
	$changed_cancelled = 0;
}
sub load_holidays {
	$holidays = read_tsv($holidays_file, 1);
	sort_holidays();
	$changed_holidays = 0;
}

sub sort_holidays {
	@$holidays = sort {$a->[0] cmp $b->[0] || $b->[1] cmp $a->[1] || $a->[2] cmp $b->[2] } @$holidays;

	# this is a bit weird, the intention is to allow smaller holidays
	# within a big holiday to show up!  such as Christmas within summer, etc :)
	# of dubious utility :)
}

sub load_info {
	$info = read_tsv($info_file, 1);
	$info_x = table_to_index($info);
	$changed_info = 0;
}
sub load_static_info {
	$static_info = read_tsv($static_info_file, 1);
	$static_info_x = table_to_index($static_info);
	$changed_static_info = 0;
}
sub fix_caps_ids_last_field {
	my ($table) = @_;
	fix_caps_ids($table, [-1]);
}
sub fix_caps_ids {
	my ($table, $fields) = @_;
	for my $row (@$table) {
		for my $field (@$fields) {
			$row->[$field] = uc_or_lc_id($row->[$field]);
		}
	}
}
sub lc_ids_last_field {
	my ($table) = @_;
	for (@$table) { $_->[-1] = lc($_->[-1]); }
}

sub lookup_staff_etc {
	my %long_uid_of;
	my %names;
	my @short_uids;
	my $dup_uids;
#	die Dumper($ou_allowed);

	my @domains = @{ou_allowed_tree_to_ldap_domains($conf->{"ou.allowed"})};

	for my $domain (@domains) {
		my $users = ldap_lookup_users_uid_name($domain);
		if (ref $users) {
			USER: for my $user (@$users) {
				my $long_uid = $user->{uid};
				my $short_uid = uc_or_lc_id($user->{short_uid});

				if (!defined $short_uid or $short_uid eq "") {
#					msg("no short_uid ($short_uid_type) for $long_uid");
					next USER;
				}

				if (exists $long_uid_of{$short_uid}) {
					msg("duplicate short_uid `$short_uid' ($short_uid_type): for $long_uid_of{$short_uid}, $long_uid");
					$dup_uids = 1;
				} else {
					$long_uid_of{$short_uid} = $long_uid;
				}

				push @short_uids, $short_uid;  # for dropdown

				my $fullname = ldap_get_fullname($user);
				$names{$short_uid} = $fullname;
			}
		} else {
			die "bad: ldap_lookup in domain $domain returned $users";
		}
	}
	if ($dup_uids) {
		die "duplicate short_uids - please contact $conf->{administrator}";
	}
	@short_uids = sort @short_uids;
	return (\%names, \@short_uids);
}

1
