/* -*- linux-c -*-
 * Filename: frame.cc
 * Revision: 19981003
 */

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

#include "./include/frame.h"
#include "./include/errmsg.h"

#include "./include/config.h"

// Constructor
frame::frame ()
{
#ifdef _DEBUG
	fprintf (stderr, "frame::frame()\n");
#endif

	frame_name = NULL;
	cube_data = (ROW *)calloc (2, FRAME_SIZE);
	if (!cube_data) {
		fprintf (stderr, FAIL_MEM_ALLOC);
		return;
	}
	temp_cube = (ROW *)cube_data + FRAME_SIZE;
}

// Destructor
frame::~frame ()
{
	if (frame_name) free (frame_name);
	if (cube_data) free (cube_data);
}

// Set the frame identifier
void frame::set_name (char *new_name)
{
	int len;

#ifdef _DEBUG
	fprintf (stderr, "frame::set_name()\n");
#endif

	if (frame_name) free (frame_name);
	len = strlen (new_name);

	// Allocate memory, throw a barny if need be
	// *** replace with a try/throw/catch mechanism ***
	if (! (frame_name = (char *)malloc (len))) {
		fprintf (stderr, FAIL_MEM_ALLOC);
		return;
	};

	strcpy (frame_name, new_name);
}

// Clear contents of the temporary cube
void frame::clear (void)
{
	memset (temp_cube, 0, FRAME_SIZE);
}

// Sets the actual cube data to the temporary cube
void frame::update (void)
{
	memcpy (cube_data, temp_cube, FRAME_SIZE);
}

// Calculates the used volume of the frame
int frame::volume (void)
{
	int x, y, z;
	int sum = 0;
	int mask;

	for (y=0; y<CONT_HEIGHT; y++) {
		for (z=0; z<CONT_DEPTH; z++) {
			mask = 1;

			for (x=0; x<CONT_WIDTH; x++) {
				if (cube_data[y*CONT_DEPTH + z] & mask) sum++;
				mask <<= 1;
			}
		}
	}
  
	return sum;
}

// Save the frame object
void frame::save (fstream &fs)
{
	int y, z;
	int len;

	// Write the frame identifier
	if (frame_name) {
		len = strlen (frame_name);
		fs << len;
		if (len > 0) {
			fs << frame_name;
		}
	} else {
		fs << 0;
	}

	// Write the frame size
	fs << CONT_WIDTH << CONT_HEIGHT << CONT_DEPTH;
	fs << ROW_SIZE;

	// Write the frame data
	for (y=0; y<CONT_HEIGHT; y++) {
		for (z=0; z<CONT_DEPTH; z++) {
			fs << cube_data[y*CONT_DEPTH + z];
		}
	}
}

// Load the frame object
void frame::load (fstream &fs)
{
	int y, z;
	int cw, ch, cd;
	int name_len;
	int tmp;

	// Load the frame identifier
	fs >> name_len;
	if (frame_name) free (frame_name);
	if (! (frame_name = (char *)malloc (name_len + 1))) {
		fprintf (stderr, FAIL_MEM_ALLOC);
		return;
	}
	fs >> frame_name;
	

	// Check the saved frame's dimensions
	fs >> cw;
	fs >> ch;
	fs >> cd;

	if ( (cw != CONT_WIDTH)
		|| (ch != CONT_HEIGHT)
		|| (cd != CONT_DEPTH)) {
		
		fprintf (stderr, "Frame \"%s\" has bad size", frame_name);
		return;
	}


	// Load the frame data
	for (y=0; y<CONT_HEIGHT; y++) {
		for (z=0; z<CONT_DEPTH; z++) {
			fs >> tmp;
			cube_data[y*CONT_DEPTH + z] = (ROW)tmp;
		}
	}

	// Clear the temp cube
	clear ();
}
