#!/usr/bin/perl

# Copyright 2002 by Eric House (xwords@eehouse.org)   All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

# Only enough of par's features to support building a crosswords dict
# pdb

use strict;

my $debug = 0;


# stolen from par source
my $PRC_FLAGS_RESOURCE =    (0x1<<0);
my $PRC_FLAGS_READONLY =   (0x1<<1);
my $PRC_FLAGS_DIRTY    =   (0x1<<2);
my $PRC_FLAGS_BACKUP   =   (0x1<<3);
my $PRC_FLAGS_NEWER    =   (0x1<<4);
my $PRC_FLAGS_RESET    =   (0x1<<5);
my $PRC_FLAGS_COPYPREVENT = (0x1<<6);
my $PRC_FLAGS_STREAM   =   (0x1<<7);
my $PRC_FLAGS_HIDDEN   =   (0x1<<8);
my $PRC_FLAGS_LAUNCHABLE = (0x1<<9);
my $PRC_FLAGS_RECYCLABLE = (0x1<<10);
my $PRC_FLAGS_BUNDLE   =   (0x1<<11);
my $PRC_FLAGS_OPEN     =   (0x1<<15);


my $gAttrs = 0;
my $gVersion = 1;               # par defaults this to 1

my $cmd = shift( @ARGV );
die "only 'c' supported now" if $cmd ne "c" && $cmd ne "-c";

readHOptions( \@ARGV );

my $dbfile = shift( @ARGV );
my $name = shift( @ARGV );
die "name $name too long" if length($name) > 31;
my $type = shift( @ARGV );
die "type $type must be of length 4" if length($type) != 4;
my $cid = shift( @ARGV );
die "cid $cid must be of length 4" if length($cid) != 4;

my @fileNames;
my @fileLengths;

my $nFiles = 0;

while ( @ARGV > 0 ) {
    my $filename = shift( @ARGV );
    push @fileNames, $filename;
    push @fileLengths, -s $filename;
    ++$nFiles;
}

# from par's prcp.h; thanks djw!
# typedef struct prc_file_t {
#     prc_byte_t name[32];
#     prc_byte_t flags[2];
#     prc_byte_t version[2];
#     prc_byte_t ctime[4];
#     prc_byte_t mtime[4];
#     prc_byte_t btime[4];
#     prc_byte_t modnum[4];
#     prc_byte_t appinfo[4];
#     prc_byte_t sortinfo[4];
#     prc_byte_t type[4];
#     prc_byte_t cid[4];
#     prc_byte_t unique_id_seed[4];
#     prc_byte_t next_record_list[4];
#     prc_byte_t nrecords[2];
# } prc_file_t;

my $str;
my $offset = 0;

open OUTFILE, "> $dbfile" or die "couldn't open outfile $dbfile for writing";

# print the string, then pad with 0s
$offset = length($name);
print OUTFILE $name;
while ( $offset < 32 ) {
    print OUTFILE pack("c", 0);
    ++$offset;
}

$str = pack("n", $gAttrs);     # flags
print OUTFILE $str;
$offset += length($str);

$str = pack("n", $gVersion);     # version
print OUTFILE $str;
$offset += length($str);

my $time = time() + 2082844800;
$str = pack("NNN", $time, $time, 0);     # ctime, mtime, btime
print OUTFILE $str;
$offset += length($str);

$str = pack("N", 0 );    # mod num
print OUTFILE $str;
$offset += length($str);

$str = pack("N", 0 );    # appinfo
print OUTFILE $str;
$offset += length($str);

$str = pack("N", 0 );    # sortinfo
print OUTFILE $str;
$offset += length($str);


print OUTFILE $type;            # type
print OUTFILE $cid;             # cid
$offset += 8;

$str = pack("NN", 0, 0 ); # unique_id_seed, next_record_list
print OUTFILE $str;
$offset += length($str);

$str = pack("n", $nFiles );     # nrecords
print OUTFILE $str;
$offset += length($str);

$offset += $nFiles * 8;
$offset += 2;                   # djw adds 2 bytes after size list; see below
foreach my $len ( @fileLengths ) {
    print OUTFILE pack( "N", $offset );
    print OUTFILE pack( "N", 0 );
    $offset += $len;
}

print OUTFILE pack( "n", 0 );   # djw does this sans comment: flush.c, line 87

foreach my $file ( @fileNames ) {
    open INFILE, "<$file" or die "couldn't open infile $file\n";
    my $buffer;
    while ( read INFILE, $buffer, 1024 ) {
        print OUTFILE $buffer;
    }
    close INFILE;
}


close OUTFILE;

exit 0;

##############################################################################
# Subroutines
##############################################################################

sub readHOptions {

    my ( $argvR ) = @_;
    
    for ( ; ; ) {
        my $opt = ${$argvR}[0];
    
        if ( $opt !~ /^-/ ) {
            last;
        }

        # it starts with a '-': use it; else don't consume anything
        shift @{$argvR};

        if ( $opt eq "-a" ) {
            my $attrs = shift @{$argvR};
            processAttrString( $attrs );
        } elsif ( $opt eq "-v" ) {
            $gVersion = shift @{$argvR};
        } else {
            die "what's with \"$opt\": -a and -v are the only hattrs supported";
        }
    }

} # readHOptions

sub processAttrString {

    my ( $attrs ) = @_;

    foreach my $flag ( split /\|/, $attrs ) {

        print STDERR "looking at flag $flag\n" if $debug;

        if ( $flag =~ /resource/ ) {
            $gAttrs |= $PRC_FLAGS_RESOURCE;
            die "resource attr not supported";
        } elsif ( $flag =~ /readonly/ ) {
            $gAttrs |= $PRC_FLAGS_READONLY;
        } elsif ( $flag =~ /dirty/ ) {
            $gAttrs |= $PRC_FLAGS_DIRTY;
        } elsif ( $flag =~ /backup/ ) {
            $gAttrs |= $PRC_FLAGS_BACKUP;
        } elsif ( $flag =~ /newer/ ) {
            $gAttrs |= $PRC_FLAGS_NEWER;
        } elsif ( $flag =~ /reset/ ) {
            $gAttrs |= $PRC_FLAGS_RESET;
        } elsif ( $flag =~ /copyprevent/ ) {
            $gAttrs |= $PRC_FLAGS_COPYPREVENT;
        } elsif ( $flag =~ /stream/ ) {
            $gAttrs |= $PRC_FLAGS_STREAM;
            die "stream attr not supported";
        } elsif ( $flag =~ /hidden/ ) {
            $gAttrs |= $PRC_FLAGS_HIDDEN;
        } elsif ( $flag =~ /launchable/ ) {
            $gAttrs |= $PRC_FLAGS_LAUNCHABLE;
        } elsif ( $flag =~ /recyclable/ ) {
            $gAttrs |= $PRC_FLAGS_RECYCLABLE;
        } elsif ( $flag =~ /bundle/ ) {
            $gAttrs |= $PRC_FLAGS_BUNDLE;
        } elsif ( $flag =~ /open/ ) {
            $gAttrs |= $PRC_FLAGS_OPEN;
        } else {
            die "flag $flag not supportd";
        }
    }
} # processAttrString