/*                    R E A D - R T L O G . C
 * BRL-CAD
 *
 * Copyright (c) 1991-2013 United States Government as represented by
 * the U.S. Army Research Laboratory.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this file; see the file named COPYING for more
 * information.
 */
/** @file rt/read-rtlog.c
 *
 * This is a program will read an RT log file.  It is meant to be used
 * by any other program that needs to read an RT log file to extract
 * the model size, orientation, eye position, azimuth, and elevation
 * from the log file.
 *
 */

#include "common.h"

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

#include "vmath.h"
#include "bu.h"
#include "raytrace.h"

#define BUFF_LEN 256

extern int verbose;


/**
 * R E A D _ R T _ F I L E
 *
 * Read an RT program's log file line by line until it either finds
 * view, orientation, eye_position, and size of the model, or it hits
 * the end of file.  When a colon is found, sscanf() retrieves the
 * necessary information.  It takes a file pointer, file name, and a
 * matrix pointer as parameters.  It returns 0 okay or < 0 failure.
 */
int
read_rt_file(FILE *infp, char *name, fastf_t *model2view)
{
    FILE *fp;
    fastf_t azimuth = 0.0;	/* part of the view */
    fastf_t elevation = 0.0;	/* part of the view */
    quat_t orientation;		/* orientation */
    point_t eye_pos = VINIT_ZERO;
    fastf_t m_size = 0.0;	/* size of model in mm */
    char *ret;			/* return code for fgets */
    char string[BUFF_LEN];	/* temporary buffer */
    char *arg_ptr;		/* place holder */
    char forget_it[9];		/* "azimuth" catcher, then forget */
    int i;			/* reusable counter */
    int num;			/* return code for sscanf */
    int seen_view;		/* these are flags.  */
    int seen_orientation;
    int seen_eye_pos;
    int seen_size;
    double scan[4] = HINIT_ZERO;

    mat_t rotate, xlate;


    /* Open the incoming file for reading */

    fp = fopen(name, "r");
    if (fp == NULL) {
	perror(name);
	bu_exit(EXIT_FAILURE, "unable to open file for reading");
    }

    /* Set all flags to ready state.  */

    seen_view = 0;
    seen_orientation = 0;
    seen_eye_pos = 0;
    seen_size = 0;

    if (verbose) {
	fprintf(stderr, "set flags: view:%d, orient:%d, eye_pos:%d, size:%d\n",
		seen_view, seen_orientation, seen_eye_pos, seen_size);
    }

    /* feof returns 1 on failure */

    while (feof(infp) == 0) {

	/* clear the buffer */
	for (i = 0; i < BUFF_LEN; i++) {
	    string[i] = '\0';
	}
	ret = bu_fgets(string, BUFF_LEN, infp);

	if (ret == NULL) {
	    /* There are two times when NULL might be seen:
	     * at the end of the file (handled above) and
	     * when the process dies horribly and unexpectedly.
	     */

	    if (feof(infp))
		break;

	    /* This needs to be seen only if there is an
	     * unexpected end.
	     */
	    fprintf(stderr, "read_rt_file: read failure on file %s\n",
		    name);
	    fclose(fp);
	    return -1;
	}

	/* Check the first for a colon in the buffer.  If there is
	 * one, replace it with a NULL, and set a pointer to the next
	 * space.  Then feed the buffer to BU_STR_EQUAL to see whether
	 * it is the view, the orientation, the eye_position, or the
	 * size.  If it is, then sscanf() the needed information into
	 * the appropriate variables.  If the keyword is not found, go
	 * back for another line.
	 *
	 * Set arg_ptr to NULL so it can be used as a flag to verify
	 * finding a colon in the input buffer.
	 */

	arg_ptr = NULL;

	for (i = 0; i < BUFF_LEN; i++) {
	    /* Check to make sure the first char. is not a NULL;
	     * if it is, go back for a new line.
	     */
	    if (string[i] == '\0') {
		break;
	    }
	    if (string[i] == ':') {
		/* If a colon is found, set arg_ptr to the
		 * address of the colon, and break: no need to
		 * look for more colons on this line.
		 */

		if (verbose) {
		    fprintf(stderr, "found colon\n");
		}

		string[i] = '\0';
		arg_ptr = &string[++i];		/* increment before using */
		break;
	    }
	}

	/* Check to see if a colon has been found.  If not, get another
	 * input line.
	 */

	if (arg_ptr == NULL) {
	    continue;
	}

	/* Now compare the first word in the buffer with the
	 * key words wanted.  If there is a match, read the
	 * information that follows into the appropriate
	 * variable, and set a flag to indicate that the
	 * magic thing has been seen.
	 *
	 * Note two points of interest: scanf() does not like %g;
	 * use %lf.  Likewise, don't use %g for printing out info:
	 * it might get rounded to the nearest integer.  Use %.6f
	 * instead.
	 * Also, if loading a whole array of characters
	 * with %s, then the name of the array can be used for the
	 * destination.  However, if the characters are loaded
	 * individually into the subscripted spots with %c (or equiv),
	 * the address of the location must be provided: &eye_pos[0].
	 */

	if (BU_STR_EQUAL(string, "View")) {
	    num = sscanf(arg_ptr, "%lf %9s %lf", &scan[X], forget_it, &scan[Y]);
	    /* double to fastf_t */
	    azimuth = scan[X];
	    elevation = scan[Y];
	    if (num != 3) {
		fprintf(stderr, "View= %.6f %s %.6f elevation\n", azimuth, forget_it, elevation);
		fclose(fp);
		return -1;
	    }
	    seen_view = 1;
	} else if (BU_STR_EQUAL(string, "Orientation")) {
	    num = sscanf(arg_ptr, "%lf, %lf, %lf, %lf", &scan[X], &scan[Y], &scan[Z], &scan[W]);
	    HMOVE(orientation, scan); /* double to fastf_t */

	    if (num != 4) {
		fprintf(stderr, "Orientation= %.6f, %.6f, %.6f, %.6f\n",
			V4ARGS(orientation));
		fclose(fp);
		return -1;
	    }
	    seen_orientation = 1;
	} else if (BU_STR_EQUAL(string, "Eye_pos")) {
	    num = sscanf(arg_ptr, "%lf, %lf, %lf", &scan[X], &scan[Y], &scan[Z]);
	    VMOVE(eye_pos, scan); /* double to fastf_t */
	    if (num != 3) {
		fprintf(stderr, "Eye_pos= %.6f, %.6f, %.6f\n",
			V3ARGS(eye_pos));
		fclose(fp);
		return -1;
	    }
	    seen_eye_pos = 1;
	} else if (BU_STR_EQUAL(string, "Size")) {
	    num = sscanf(arg_ptr, "%lf", &scan[X]);
	    m_size = scan[X];
	    if (num != 1) {
		fprintf(stderr, "Size=%.6f\n", m_size);
		fclose(fp);
		return -1;
	    }
	    seen_size = 1;
	}
    }

    /* Check that all the information to proceed is available */

    if (seen_view != 1) {
	fprintf(stderr, "View not read for %s!\n", name);
	fclose(fp);
	return -1;
    }

    if (seen_orientation != 1) {
	fprintf(stderr, "Orientation not read for %s!\n", name);
	fclose(fp);
	return -1;
    }

    if (seen_eye_pos != 1) {
	fprintf(stderr, "Eye_pos not read for %s!\n", name);
	fclose(fp);
	return -1;
    }

    if (seen_size != 1) {
	fprintf(stderr, "Size not read for %s!\n", name);
	fclose(fp);
	return -1;
    }

    if (verbose) {
	/* Take your chances on the %g with the orientation: it is
	 * difficult to say how many figures it will take to print the
	 * orientation back, and it is disconcerting to have it come
	 * back as 0.
	 */

	fprintf(stderr, "logfile: %s\n", name);
	fprintf(stderr, "view: azimuth %.6f; elevation: %.6f\n", azimuth, elevation);
	fprintf(stderr, "orientation: %g, %g, %g, %g\n", V4ARGS(orientation) );
	fprintf(stderr, "eye_pos: %.6f, %.6f, %.6f\n", V3ARGS(eye_pos) );
	fprintf(stderr, "size: %.6fmm\n", m_size);
    }

    /* Build the view2model matrix. */

    quat_quat2mat(rotate, orientation);
    rotate[15] = 0.5 * m_size;
    MAT_IDN(xlate);
    MAT_DELTAS_VEC_NEG(xlate, eye_pos);
    bn_mat_mul(model2view, rotate, xlate);

    if (verbose) {
	bn_mat_print("model2view", model2view);
    }

    fclose(fp);		/* clean up */
    return 0;
}


/*
 * Local Variables:
 * mode: C
 * tab-width: 8
 * indent-tabs-mode: t
 * c-file-style: "stroustrup"
 * End:
 * ex: shiftwidth=4 tabstop=8
 */
