/* rmap - vector based global map generating program
 * Copyright (C) 2000 Reza Naima <reza@reza.net>
 *
 * http://www.reza.net/rmap/
 *
 *
 * 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 <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <math.h>
#include <strings.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>


#define SHORTFLAG 0x4000
#define CBD_MAGIC 0x20770002
#define HEADER_MAGIC 0x86460346	//random number
#define BIT32 int
#define BIT16 short

// THE INPUT PARAMS MUST BE IN THE FORM OF
//   generate Map/*.Map/*.cbd
//  for the proper continent and type mappings
//	(i need to pull it fromt he filenames, and
//	 rather than parsing it, i just pull it from
//        various spots)
//


struct cbdhead
{
    BIT32           magic;	/* Magic number */
    BIT32           dictaddr;	/* Offset of segment dictionary in file */
    BIT32           segcount;	/* Number of segments in file */
    BIT32           segsize;	/* Size of segment dictionary */
    BIT32           segmax;	/* Size of largest segment's strokes, /2 */
    BIT32           fill[(40 / sizeof (BIT32)) - 5];	/* Filler */
};

struct myheader
{
    BIT32           magic;
    BIT32           segment_index_address;
    BIT32           segment_index_count;
};

int main (int argc, char **argv) {
		int cat, continent;
		char string[4];
    int             Ofile;
    int             my_seg_idx = 0;
    int             my_segment_total = 0;
    int             my_stroke_count = 0;
    int             ret;
    int             Ifile, segcount, idx, idy, segbufsize, olt, oln, j, k,
      jstroke, iseg;
    char            filename[20][80];
    char	    file[30];
    int             filenum;
    BIT32           i32;
    BIT16          *segbuf;


    struct my_segment_index
    {
	BIT32           maxlat;
	BIT32           minlat;
	BIT32           maxlong;
	BIT32           minlong;
	BIT32           segment_address;
	BIT32           continent;
	BIT32           catagory;
	BIT32           type;
    }
    seg_idx;

    struct my_segment_header
    {
	BIT32           orgx;
	BIT32           orgy;
	BIT32           nstrokes;
    }
    seg_head;

    struct my_stroke
    {
	BIT32           dx;
	BIT32           dy;
    }
    stroke;


    struct segdict
    {
	BIT32           segid;
	BIT32           maxlat, minlat, maxlong, minlong;
	BIT32           absaddr;
	BIT16           nbytes;
	BIT16           rank;
    }
                   *sd, *sdbuf;

    struct segment
    {
	BIT32           orgx, orgy;
	BIT32           id;
	BIT16           nstrokes;
	BIT16           dummy;
    } sb;
    struct cbdhead  header;
    struct myheader my_top;


// create a file to output my data to 
    Ofile = creat ("output.rez", S_IRWXU);
    if (Ofile == -1 ) {
	printf ("couln't open output file\n");
	exit (2);
    }
    if (Ofile <3 ) {
	printf("opened fh= %d\n", Ofile);
	exit(-1);
    }

// initialize some shitz
//itterate through this twice.. once to create list of indexes, 
//and a second time to generate the data

    //determine the number of segments
    for (filenum = 1; filenum < argc; filenum++) {
	strcpy (filename[filenum], argv[filenum]);

	Ifile = open (filename[filenum], O_RDONLY, 0);
	if (Ifile == -1) {
		printf("unable to open file %s", filename[filenum]);
		continue;
	}

	printf ("Reading %s\n", filename[filenum]);
	read (Ifile, &header, sizeof header);
	if (header.magic != CBD_MAGIC) {
	    printf ("File has bad magic number %d != %d\n", header.magic, CBD_MAGIC);
	    exit (2);
	}
	my_seg_idx += header.segcount;
	close (Ifile);
    }
    printf ("determined that there are %d segments\n", my_seg_idx);

    my_segment_total = my_seg_idx;
    my_seg_idx = 0;

    my_top.magic = HEADER_MAGIC;
    my_top.segment_index_address = sizeof my_top;
    my_top.segment_index_count = my_segment_total;
    ret = write (Ofile, &my_top, sizeof (my_top));
    if (ret != sizeof (my_top)) {
	printf ("error 1\n");
	exit (2);
    }
    //now generate a list of the segment_indexs     
printf("Writing Segment Indexes ");
    for (filenum = 1; filenum < argc; filenum++) {
	continent=0; cat=0; //init
	strcpy (filename[filenum], argv[filenum]);
	strcpy (file, argv[filenum]);
        Ifile = open (filename[filenum], O_RDONLY, 0);

	if (Ifile == -1) continue; // problem?

	// determine the continent and catagory id
	bzero(string,3);
	strncpy(string, file+4, 3);
	string[3]='\0';
	if (!strcmp(string, "afr")) continent=1;
	if (!strcmp(string, "asi")) continent=2;
	if (!strcmp(string, "eur")) continent=3;
	if (!strcmp(string, "nam")) continent=4;
	if (!strcmp(string, "sam")) continent=5;
	printf("Country -> %s -> %d\n", string, continent);
	bzero(string,3);
	strncpy(string, file+(strlen(file)-7), 3);
	string[3]='\0';
	if (!strcmp(string, "pby")) cat=1;
	if (!strcmp(string, "riv")) cat=2;
	if (!strcmp(string, "bdy")) cat=3;
	if (!strcmp(string, "cil")) cat=4;
	printf("Type -> %s -> %d\n", string, cat);

	printf ("Reading %s\n", filename[filenum]);
	read (Ifile, &header, sizeof header);

/* allocate space for the segment buffer */
	segbufsize = 2 * header.segmax;
	segbuf = (BIT16 *) malloc (50 + segbufsize);
	sd = sdbuf = (struct segdict *) malloc (100 + header.segsize);

/* Go read in the segment dictionary (it's at the end of the file) */
	lseek (Ifile, header.dictaddr, L_SET);
	j = read (Ifile, sd + 1, header.segsize);

	if (j < header.segsize) {
	    fprintf (stderr, "File segment dictionary expecting %d got %d\n",
		     header.segsize, j);
	    exit (2);
	}

	segcount = header.segcount;

	for (iseg = 1; iseg <= segcount; iseg++) {

	    sd++;		/* next one */
		//determine the country and 
		// the catagory using a crude method


	    my_seg_idx++;
	    seg_idx.maxlat = sd->maxlat;
	    seg_idx.minlat = sd->minlat;
	    seg_idx.maxlong = sd->maxlong;
	    seg_idx.minlong = sd->minlong;
	    seg_idx.segment_address = sizeof (my_top)	//hader
	      + sizeof (seg_idx) * my_segment_total	//the segment index block
	      + sizeof (seg_head) * (my_seg_idx - 1)	//the number of past segment headers
	      + sizeof (stroke) * my_stroke_count;
	    seg_idx.continent = 0x00000001 << continent-1;	// aka the file num
	    seg_idx.catagory = 0x00000001 << cat-1;	// should break this up really..
	    seg_idx.type = sd->rank;
if (my_seg_idx <  10) 
printf("my_seg_idx = %d, addr = %d\n", my_seg_idx, seg_idx.segment_address);

	    lseek (Ifile, sd->absaddr, L_SET);
	    read (Ifile, &sb, sizeof sb);
	    my_stroke_count += sb.nstrokes;
	    ret = write (Ofile, &seg_idx, sizeof (seg_idx));
	    if (ret != sizeof (seg_idx)) {
		printf ("error 1\n");
		exit (2);
	    }
	    //printf ("wrote segment_index %d (strokes = %d)\n", my_seg_idx, my_stroke_count);
		//if (!iseg%(my_segment_total/20)) 
		//	printf("."); 

	}
	printf("\n");
	close (Ifile);
	free (sdbuf);
	free (segbuf);
    }
//another loop!

    for (filenum = 1; filenum < argc; filenum++) {
	strcpy (filename[filenum], argv[filenum]);
	if ((Ifile = open (filename[filenum], O_RDONLY, 0)) == -1)
	    continue;
	printf ("Reading %s\n", filename[filenum]);
	read (Ifile, &header, sizeof header);

/* allocate space for the segment buffer */
	segbufsize = 2 * header.segmax;
	segbuf = (BIT16 *) malloc (50 + segbufsize);
	sd = sdbuf = (struct segdict *) malloc (100 + header.segsize);

/* Go read in the segment dictionary (it's at the end of the file) */
	lseek (Ifile, header.dictaddr, L_SET);
	j = read (Ifile, sd + 1, header.segsize);

	if (j < header.segsize) {
	    fprintf (stderr, "File segment dictionary expecting %d got %d\n",
		     header.segsize, j);
	    exit (2);
	}

	segcount = header.segcount;
	for (iseg = 1; iseg <= segcount; iseg++) {
	    sd++;		/* next one */

	    lseek (Ifile, sd->absaddr, L_SET);
	    read (Ifile, &sb, sizeof sb);

	    if (sd->nbytes > segbufsize) {
		fprintf (stderr,
			 "Segment %d needs %d bytes; buffer limit is %d.\n",
			 iseg, sd->nbytes, segbufsize);
		exit (2);
	    }
	    read (Ifile, segbuf, sd->nbytes);

	    k = 0;
	    oln = sb.orgx;
	    olt = sb.orgy;

	    seg_head.orgx = sb.orgx;
	    seg_head.orgy = sb.orgy;
	    seg_head.nstrokes = sb.nstrokes;

//ret = lseek(Ofile, 0, SEEK_CUR);
//printf("the offset is at %d\n", ret);
	    ret = write (Ofile, &seg_head, sizeof (seg_head));
	    if (ret != sizeof (seg_head)) {
		printf ("error 1\n");
		exit (2);
	    }
	    //printf ("writing stroke header - total strokes = %d\n", sb.nstrokes);
		printf(".");
		fflush(stdout);

	    for (jstroke = 1; jstroke <= sb.nstrokes; jstroke++) {
		if (segbuf[k] & SHORTFLAG) {
/* Flag bit on: unpack a 16-bit field into dx and dy */
		    i32 = segbuf[k++];

		    if (i32 > 0)
			i32 &= ~SHORTFLAG;	/* turn off short flag bits */

		    idy = i32 & 0x000000FF;
		    if (idy & 0x00000080)
			idy |= ~0x000000FF;	/* extend sign */

		    idx = i32 >> 8;
		    if (idx & 0x00000080)
			idx |= ~0x000000BF;	/* extend sign */

		} else {
/* Flag bit off: take dx and dy from 32-bit fields. */
		    idx = segbuf[k++];

		    if (idx < 0)
			idx |= SHORTFLAG;
		    idx = (idx << 16) | (unsigned short) segbuf[k];
		    k++;

		    idy = segbuf[k];
		    k++;
		    if (idy < 0)
			idy |= SHORTFLAG;
		    idy = (idy << 16) | segbuf[k];
		    k++;
		}
		stroke.dx = idx;
		stroke.dy = idy;

		ret = write (Ofile, &stroke, sizeof (stroke));
		if (ret != sizeof (stroke)) {
		    printf ("error 1\n");
		    exit (2);
		}

	    }
	}
	printf("\n");
	close (Ifile);
	free (sdbuf);
	free (segbuf);
    }
    close (Ofile);
    return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1