/*  Copyright 2004 David Turnbull
 *
 *  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
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define INPUT_STRING_SIZE 1024

static long int convert(FILE *infile, FILE *outfile, char *storyname);
static write16(FILE *outfile, unsigned int value);
static write32(FILE *outfile, unsigned long int value);


int main(int argc, char *argv[])
{
    char *inpstr, *storyname, *outname;
    FILE *infile, *outfile;
    size_t i;
    long int bytes;

    printf("z2pdb - Convert a Z-code story file into a Frobnitz Palm database.\n");

    inpstr = (char *)malloc(INPUT_STRING_SIZE);

    /* If no arguments passed, print the helpful information and exit */
    if (argc < 2)
    {
        printf("\nUsage: z2pdb filename.z filename.pdb \"Story Name\"\n");
#ifdef _WIN32
        printf("Windows users can drag a Z-code file on top of this executable.\n");
        goto winend;
#else
        exit(1);
#endif
    }

    /* Open the input file */
    if (NULL == (infile = fopen(argv[1], "rb")))
    {
        printf("\nError opening input file.\n");
        exit(1);
    }

    /* Get the output filename */
    if (argc > 2)
    {
        /* user supplied output filename */
        outname = argv[2];
    }
    else
    {
        /* build output filename from the input filename */
        i = strlen(argv[1]);
        outname = (char *)malloc(i + 5);
        strcpy(outname, argv[1]);

	/* back up to the . (if any) and append ".pdb" */
        while (i)
        {
            i--;
            if (outname[i] == '.')
                goto addPDB;
        }
        i = strlen(argv[1]) - 1;
        addPDB:
        strcpy(outname + i, ".pdb");

        /* Tell user the output filename we created for them */
        printf("\nOutput file: %s\n", outname);
    }

    /* Get the story name (database name) */
    if (argc > 3)
    {
        /* user supplied story name */
        storyname = argv[3];
    }
    else
    {
        /* prompt user to supply story name */
        *inpstr = 0;
        storyname = inpstr;
        while (!*inpstr || strlen(storyname) > 31)
        {
            printf("\nPlease name this story (max 31 chars): ");
            fgets(inpstr, INPUT_STRING_SIZE, stdin);
            storyname = inpstr;

            /* strip newline from end */
            i = strlen(inpstr);
            if (i && inpstr[i-1] == '\n')
                inpstr[--i] = 0;

            /* strip spaces fron end */
            while(i && inpstr[--i] == ' ') inpstr[i] = 0;

            /* strip spaces fron beginning */
            while (*storyname == ' ') storyname++;
        }
    }

    /* Open the output file */
    if (NULL == (outfile = fopen(outname, "wb")))
    {
        fclose(infile);
        printf("\nError opening output file.\n");
        exit(1);
    }

    /* Do the conversion */
    bytes = convert(infile, outfile, storyname);
    fclose(outfile);
    fclose(infile);

    printf("\nWrote %ld bytes to output file.\n", bytes);

#ifdef _WIN32
    winend:
    /* Add a pause at the end so Windows users can read messages */
    if (argc < 3)
    {
        printf("\nPress ENTER: ");
        fgets(inpstr, INPUT_STRING_SIZE, stdin);
    }
#endif
}


static long int convert(FILE *infile, FILE *outfile, char *storyname)
{
    unsigned int recs, l;
    int c;

    fseek(infile, 0, SEEK_END);
    recs = (ftell(infile) + 4095) / 4096;

    /* write out the database header structure */
    fwrite(storyname, 1, 32, outfile); /* database name */
    write16(outfile, 0);               /* attributes */
    write16(outfile, 1);               /* version */
    write32(outfile, 0x34ac829f);      /* creation date */
    write32(outfile, 0x34ac829f);      /* modification date */
    write32(outfile, 0);               /* last backup date */
    write32(outfile, 0);               /* modification number */
    write32(outfile, 0);               /* app info area */
    write32(outfile, 0);               /* sort info area */
    fwrite("ZCOD", 1, 4, outfile);     /* database type */
    fwrite("Frtz", 1, 4, outfile);     /* database creator */
    write32(outfile, 0);               /* Unique ID seed */
    write32(outfile, 0);               /* Next record list ID */
    write16(outfile, recs);            /* Number of records */

    /* write record headers */
    for(l = 0; l < recs; l++)
    {
        write32(outfile, 78 + (8 * recs) + (4096 * l)); /* record data offset */
        write32(outfile, 0x00000000); /* record attributes (0x00), unique ID (0x000000) */
    }

    /* write the Z-code records */
    fseek(infile, 0, SEEK_SET);
    c = fgetc(infile);
    while (!feof(infile))
    {
        fputc(c, outfile);
        c = fgetc(infile);
    }

    return ftell(outfile);
}


static write16(FILE *outfile, unsigned int value)
{
    fputc((value >> 8) & 0xFF, outfile);
    fputc(value & 0xFF, outfile);
}


static write32(FILE *outfile, unsigned long int value)
{
    fputc((value >> 24) & 0xFF, outfile);
    fputc((value >> 16) & 0xFF, outfile);
    fputc((value >> 8) & 0xFF, outfile);
    fputc(value & 0xFF, outfile);
}
