/*
 * Filename: container.cpp
 * Revision: 19981004
 */

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

#include "./include/container.h"
#include "./include/shape.h"

#include "./include/config.h"

#define min(a,b)  ( (a) < (b) ? (a) : (b))

// Constructor
container::container (void)
{
	memset (cube_data, 0, FRAME_SIZE);
}

// Destructor
container::~container (void)
{
}

// Copy from a source container into this container
void container::copy (container *source)
{
	if (source) {
		level = source->level;
		memcpy (cube_data, source->cube_data, FRAME_SIZE);
	} else {
		level = 0;
		memset (cube_data, 0, FRAME_SIZE);
	}
}

// Perform the action of dropping the shape into the container
int container::drop_shape (shape *src_shape)
{
	int alt;

	// Shouldn't really be needed
	if (src_shape->shape_x + src_shape->width > CONT_WIDTH) return 0;
	if (src_shape->shape_z + src_shape->depth > CONT_DEPTH) return 0;
  
	// Find where the shape will settle
	alt = touch_down (src_shape);
	if (alt + src_shape->height > CONT_HEIGHT) return 0;
  
	// Move the shape to the altitude at which it would settle
	src_shape->shift_up (alt);

	// Merge the shape with this container
	// Will be saved in the temporary frame
	merge_shape (src_shape);

	// Validate the temporary frame
	if (!validate ()) return 0;

	// Temporary frame is valid so update this container
	update ();
  
	return -1;
}

// Find at what altitude the bottom of the shape
// will settle in this container
int container::touch_down (shape *block)
{
	int cy, by, z;
  
	// Scan container from top downwards
	for (cy=CONT_HEIGHT - 1; cy>=0; cy--) {
    
		// Only scan the necessary rows
		for (z=block->shape_z; z< (block->shape_z + block->depth); z++) {
      
			// Only scan the overlapping layers
			for (by=0; by<min (block->height, CONT_HEIGHT - cy); by++) {
				if (cube_data[ (by + cy)*CONT_DEPTH + z]
					& block->cube_data[by*CONT_DEPTH + z]) return cy + 1;
			}
		}
	}

	// Made it to the bottom with no collisions
	return 0;
}   

// Ensure the contents of the temporary frame are valid.
// This means that there are no overhanging edges
int container::validate (void)
{
	int x, y, z;
	ROW upper, lower;

	for (y=0; y<CONT_HEIGHT - 1; y++) {
		for (z=0; z<CONT_DEPTH; z++) {
			upper = temp_cube[(y+1)*CONT_DEPTH + z];
			lower = temp_cube[y*CONT_DEPTH + z];

			for (x=0; x<CONT_WIDTH; x++) {
				// If there is an overhang return FALSE
				if ( (int) (upper & 1) > (int) (lower & 1)) return 0;
				upper = upper >> 1;
				lower = lower >> 1;
			}
		}
	}

	// Temporary frame is valid.
	return -1;
}

// Duplicate the current container into the temporary
// frame and merge with the shape
void container::merge_shape (shape *source)
{
	int y, z;

	// Copy the current container into the temporary frame
	memcpy (temp_cube, cube_data, FRAME_SIZE);

	// Merge the shape with the temporary frame
	for (y=0; y<CONT_HEIGHT; y++) {
		for (z=0; z<CONT_DEPTH; z++) {
			temp_cube[y*CONT_DEPTH + z] |= source->cube_data[y*CONT_DEPTH + z];
		}
	}
}

// Load the container
void container::load (fstream &fs)
{
	fs >> level;

	frame::load (fs);
}

// Save the container
void container::save (fstream &fs)
{
	fs << level;
	
	frame::save (fs);
}

// Print the status of this container
void container::status (void)
{
	int y, z;

	printf ("Container Level: %d\n\n    ", level);

	for (y=CONT_HEIGHT; y!=0; y--) {
		for (z=0; z<CONT_DEPTH; z++) {
			printf ("%02d  ", cube_data[(y-1)*CONT_DEPTH + z]);
		}
		printf ("\n    ");
	}
	printf ("\n");
}
