#!/usr/bin/env perl

# -------------------------------------------------------------------------
# file:		dhw2ps.pl
# task:		convert the internal dwh file format of DigiMemo A501 to
#		ps or pdf files
# authors:	Jan Theofel (theofel@etes.de)
#		Harald Koenig
# version:	0.1
# license:	free to use, an official license will follow
# -------------------------------------------------------------------------
# TODO:
# - code cleanup
# - code optimisation (the array of chars is very slow)
# - adding a real license
# - add documentation
# -------------------------------------------------------------------------

use strict;
use Getopt::Long qw(:config gnu_getopt);

my $pdfout = ($0 =~ /dhw2pdf/);;
my $debug = 0;
my $verbose = 0;
my $usage = 0;
my $quiet = 0;
my $colorlayers = 0;

sub usage
{
  print "usage: $0 [params] [dwh file(s)]\n\n";
  print "Where params can be:\n";
  print "-c|--colorlayers     color layers\n";
  print "-d|--debug           run in debug mode\n";
  print "-h|--help            display this usage message\n";
  print "-q|--quiet           run in quite mode\n";
  print "-v|--verbose         run in verbose mode\n";
  print "--pdf                create pdf files (nneds ps2pdf)\n";
  print "--ps                 create ps files\n"; 
  exit $_[0];
}

GetOptions (
	    'c' => \$colorlayers, 'colorlayers!' => \$colorlayers,
	    'd' => \$debug,       'debug!'       => \$debug,
	    'h' => \$usage,       'help'         => \$usage,
	    'q' => \$quiet,       'quiet!'       => \$quiet,
	    'v' => \$verbose,     'verbose!'     => \$verbose,
	    'pdf!' => \$pdfout,
	    'ps!'  => sub { $pdfout = 0 },
	    ) or usage(1);

my $inname = shift();

usage(0) if ($usage || !$inname);

if ($pdfout) 
{
  my $check_ps2pdf = `which ps2pdf`;
  if($check_ps2pdf eq "")
  {
    die "ERROR: ps2pdf is needed in pdf mode.\n";
  }
}


while ($inname) { # loop for all input files

    my ($buffer, $skip, $data);
    my ($fileversion, $paperwidth, $paperheight, $paperformat);
    my $file_content;



    print "INFO: input file: $inname\n" if (!$quiet);
    open(IN, "$inname");

    my $count = 32;
    read(IN, $data, $count);

    if($data ne "ACECAD_DIGIMEMO_HANDWRITING_____") {
	die "Invalid INK file $inname\n";
    }

# read rest of input file in 64K junks
    while(read(IN, $buffer, 64*1024)) {
	$data .= $buffer;
    }
    close(IN);

    my @data = split(//, $data);


# decode header data

    $fileversion = ord($data[$count++]);
    
    $paperwidth = ord($data[$count+0]) + (ord($data[$count+1]) << 8);
    $count += 2;

    $paperheight = ord($data[$count+0]) + (ord($data[$count+1]) << 8);
    $count += 2;

    my $pagetype = ord($data[$count++]);

    ord($data[$count++]);  # skip header byte
    ord($data[$count++]);  # skip header byte

    my $paper = ("a5", "a4", "??2", "??3", "??4", "??5", "??6", "??7", "b5", "b4")[$pagetype];
    my $orientation = ("Portrait", "Landscape")[ $paperheight < $paperwidth ];

    my $llx = 0;  #  87  for A4 centering on A4
    my $lly = 0;  # 123  for A4 centering on A4
    my $urx = $llx + int($paperwidth  / 1000. * 72. + 0.999999);
    my $ury = $lly + int($paperheight / 1000. * 72. + 0.999999);

    my $now = gmtime;

    print "DEBUG: ink file version: $fileversion\n" if ($debug);
    print "DEBUG: width / height: $paperwidth / $paperheight\n" if ($debug);
    print "DEBUG: pagetype: $pagetype ($paper)\n" if ($debug);


    my $outfile;

    if ($pdfout) {
	$outfile = "|ps2pdf -sPAPERSIZE=$paper - $inname";
	$outfile =~ s/\.dhw$//;
	$outfile .= ".pdf";
    } else {
	$outfile = ">$inname";
	$outfile =~ s/\.dhw$//;
	$outfile .= ".ps";
    }

    print "DEBUG: output file: $outfile\n" if ($debug);
    open(OUT, "$outfile");


    print OUT <<PSHEAD;
    %!PS-Adobe-2.0
	%%Title: $inname
	%%Creator: ink2ps $inname
	%%CreationDate: $now
	%%Orientation: $orientation
	%%BoundingBox: $llx $lly $urx $ury
	%%DocumentPaperSizes: $paper
	%%Pages: 1
	%%EndComments
	/StartPage {
	    gsave
		$llx $lly translate
		72 1000 div dup scale
		1 setlinecap
		1 setlinejoin
		1 LW
	    } bind def
	    /EndPage {
		grestore
		    showpage
		} bind def
		/RGB { setrgbcolor } bind def
		/LW { setlinewidth } bind def
		/S { newpath moveto } bind def
		/L { lineto } bind def
		/E { stroke } bind def
		%%EndProlog
		%%Page: 1 1
		StartPage

		% set line width
		16 LW

		% set color
		0 0 0 RGB

		% strokes
PSHEAD


    my $color     = 0;
    my $lastcolor = 0;
    my $layer     = 0;
    my $strokes   = 0;
    my $points    = 0;
    my $pointcmd  = "S";
    
    while($count < $#data) {
	my $next = ord($data[$count++]);

	if (($next & ~0x07) == 0x80) {  # pen up/down
	    if ($next & 0x01) {
		$pointcmd = "S";
		print "DEBUG pen down POSITION $count\n" if ($debug);
	    }
	    else {
		$pointcmd = "L\nE\n";
		$strokes++;
		print "DEBUG pen up POSITION $count\n" if ($debug);
	    }

	    $color = (($next >> 1) + ($layer * $colorlayers))  & 0x03;
	    print "DEBUG pen color $color\n" if ($debug);
	    if ($color != $lastcolor) {
		$lastcolor = $color;
		print OUT "%%Color: $color\n";
		print OUT ("0 0 0", "1 0 0", "0 1 0", "0 0 1")[$color] . " RGB\n";
	    }
	}
	elsif ($next == 0x88) {  # time stamp
	    my $timestamp = ord($data[$count++]);
	    print "DEBUG TimeStamp $timestamp\n" if ($debug);
	    print OUT "%%TimeStamp: $timestamp\n" if ($timestamp < 0x7f);
	}
	elsif ($next == 0x90) {  ## end of layer
	    $layer = ord($data[$count++]);
	    print "DEBUG End of LAYER $layer\n" if ($debug);
	    die("Layer # $layer > 127") if ($layer & 0x80);
		print OUT "%%EndOfLayer: $layer\n\n";
	}
	elsif (!($next & ~0x7f)) {  ## coordinates
	    my ($b1, $b2, $b3, $b4) = ($next, ord($data[$count+0]), ord($data[$count+1]), ord($data[$count+2]));
	    $count += 3;
	    printf "DEBUG CHECK position $count A %02x %02x %02x %02x\n", $b1, $b2, $b3, $b4 if ($debug);
	    # die("MSB set in coordinate bytes") if (($b1 | $$b2 | $b3 | $b4) & ~0x7f);

	    my $x = $b1 + ($b2 << 7);
	    my $y = $b3 + ($b4 << 7);
	    print "DEBUG $count: x = $x / y = $y\n" if ($debug);
	    print OUT "$x $y " . $pointcmd . "\n";
	    $points++;

	    $pointcmd = "L";
	} else {
	    die("unknown byte " . sprintf("0x%02x", $next) . " at position $count");
	}
    }

    print OUT <<PSFOOT;

    EndPage
	%%Trailer
	%%EOF
PSFOOT

    close(OUT);

    print "INFO: $points points, $strokes strokes, $layer layers\n\n" if (! $quiet);

    $inname = shift();
}