The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#! /usr/bin/env perl
use warnings;
use strict;
use File::Spec;
use Cwd;
use Getopt::Long;
use Pod::Usage;

our $VERSION = '2.19';

=pod

=head1 NAME

pack_ostn_data - [not for users] re-create the OSTN02 data for OSGB.pm

Run this from the root of the distribution.  Default behaviour is to create a new copy
of the module in the current directory.

=head1 SYNOPSIS

  build/pack_ostn_data

The source OSTN02 data set should be in OSTN02/OSTN02_OSGM02_GB.txt

=head1 OPTIONS

=over 4 

=item --outfile ostn.data

File to write to.  Defaults to "ostn.data" in current directory.  
Any existing file will be overwritten.

=back

=head1 AUTHOR 

Toby Thurston -- 30 Jul 2017

=cut

my $outfile = 'ostn.data';
my $source = File::Spec->catfile('OSTN02', 'OSTN02_OSGM02_GB.txt');

my $options_ok = GetOptions(
    'outfile=s' => \$outfile,

    'version'     => sub { warn "$0, version: $VERSION\n"; exit 0; }, 
    'usage'       => sub { pod2usage(-verbose => 0, -exitstatus => 0) },                         
    'help'        => sub { pod2usage(-verbose => 1, -exitstatus => 0) },                         
    'man'         => sub { pod2usage(-verbose => 2, -exitstatus => 0) },

);
die pod2usage() if @ARGV || ! $options_ok;


# ideally designed for 0 <= $d < 2**15 = 32768, but will work ok with higher
sub b32 {
    my $d = shift;
    my $h = $d >> 10; $d -= $h << 10;
    my $t = $d >> 5;  $d -= $t << 5;
    return join '', map { chr 48+$_ } $h, $t, $d;
}

open my $ostn_fh, '<', $source or die "Can't open $source: $!\n";
my ($x, $y, $datum);
warn "Reading $source....\n" ;
my @OSTN02 = ();
my $row = '';
while (<$ostn_fh>) {
    chomp;
    (undef, undef, undef, $x, $y, undef, $datum) = split ',';
   
    $row .= int $datum ? b32(int ($x*1000) - 86000) .  b32(int ($y*1000) + 82000) : '000000';
    # The constants subtracted and added bring the values into the range 0 < xxx < 2**15
    # Note that they are never zeros like this..  Zeros are reserved for "datum 0" - the undefined
    # area

    if ( length $row == 4206 ) {
        push @OSTN02, $row;
        $row = '';
    }
}
close $ostn_fh;

open my $data_fh, '>', $outfile or die "Can't open $outfile for writing: $!\n";
warn "Packing to $outfile...\n" ;
my $i = 0;
# remove the blank rows from the end
my $blank_line = '0' x 4206;
while (1) {
    last if $blank_line ne $OSTN02[-1];
    pop @OSTN02;
}

for my $row (@OSTN02) {
    $i++;
    die "Bad row $i" unless 4206 == length $row;
    my ($zeros, $data) = $row =~ m{\A ((?:0{6})+)(.*?)(?:0{6})*\Z}iosxm;
    die "Zeros not in sixes $i" if length($zeros) % 6;
    die "Data not in sixes $i" if length($data) % 6;
    printf $data_fh "%03d%s\n", length($zeros)/6, $data;
}
close $data_fh;
warn "Wrote $i rows to $outfile\n";