#include "StdAfx.h"
#include "Part.h"
#include "Constants.h"
#include "Puzzle.h"
#include "BitVector.h"

Part::Part(string path)
{
	this->path = path;
}

Part::~Part(void)
{
}

bool Part::foundTotallyAsymetric = false;

void Part::addToPuzzle(Puzzle* puzzle)
{
	this->puzzle = puzzle;

	int x, y, z;
	for(x = 0; x < maxExpansion; x++)
		for(y = 0; y < maxExpansion; y++)
			for(z = 0; z < maxExpansion; z++)
				space[x][y][z] = false;

	for(unsigned int p = 0; p < path.length(); p++)
	{
		switch(path[p])
		{
		case 's': x = y = z = maxLength - 1; break;		//center of space
		case 'l': x--; break;
		case 'r': x++; break;
		case 'u': y--; break;
		case 'd': y++; break;
		case 'f': z--; break;
		case 'b': z++; break;
		}
		space[x][y][z] = true;
	}
	turnAxisPositive(4, 'x');
	turnAxisPositive('y');
	turnAxisPositive(4, 'z');
	turnAxisPositive('y');
	turnAxisPositive(4, 'x');
	turnAxisPositive('y');
	turnAxisPositive(4, 'z');
	turnAxisPositive('y');
	turnAxisPositive('z');
	turnAxisPositive(4, 'y');
	turnAxisPositive('x');
	turnAxisPositive('x');
	turnAxisPositive(4, 'y');

	if(!foundTotallyAsymetric && turns.size() == 24)
	{
		foundTotallyAsymetric = true;
		turns.clear();
		turnAxisPositive(2, 'x');
		turnAxisPositive(2, 'x', false);
		turnAxisPositive('y', false);
		turnAxisPositive(2, 'z');
		turnAxisPositive(2, 'z', false);
		turnAxisPositive('x', false);
		turnAxisPositive(2, 'y');
		turnAxisPositive(2, 'y', false);	//6 Positionen im Raum verbleiben
	}

	int dx, dy, dz;
	for(set<__int64>::const_iterator t = turns.begin(); t != turns.end(); t++)
	{
		getDimensions(*t, dx, dy, dz);
		for(x = 0; x < xD - dx; x++)
			for(y = 0; y < yD - dy; y++)
				for(z = 0; z < zD - dz; z++)
					puzzle->insertInstance(Instance(*t, puzzle, x, y, z, this));
	}
}

void Part::turnAxisPositive(char axis, bool insert)	//insert = true
{
	bool buffer[maxExpansion][maxExpansion][maxExpansion];

	int x, y, z, cx, cy, cz;
	for(x = 0; x < maxExpansion; x++)
		for(y = 0; y < maxExpansion; y++)
			for(z = 0; z < maxExpansion; z++)
			{
				switch(axis)
				{
				case 'x':
					cx = x;
					cy = maxExpansion - 1 - z;
					cz = y;
				break;
				case 'y':
					cx = z;
					cy = y;
					cz = maxExpansion - 1 - x;
				break;
				case 'z':
					cx = maxExpansion - 1 - y;
					cy = x;
					cz = z;
				break;
				}
				buffer[cx][cy][cz] = space[x][y][z];
			}
	for(x = 0; x < maxExpansion; x++)
		for(y = 0; y < maxExpansion; y++)
			for(z = 0; z < maxExpansion; z++)
				space[x][y][z] = buffer [x][y][z];
	BitVector rep = puzzle->projection.projectAligned(space);
#ifdef output
/*	debugOutput();
	rep.debugOutput(&(puzzle->projection));*/
#endif
	if(insert && rep != 0) turns.insert(rep);
}

void Part::turnAxisPositive(int times, char axis, bool insert)
{
	for(int t = 0; t < times; t++) turnAxisPositive(axis, insert);
}

void Part::getDimensions(const BitVector& turn, int& x, int& y, int& z)
{
	int ox, oy, oz;
	x = 0;
	y = 0;
	z = 0;
	for(int bit = 0; bit < xD * yD * zD; bit++)
		if(turn.getBit(bit))
		{
			puzzle->projection.getCoordinates(bit, ox, oy, oz);
			x = ::max(x, ox);
			y = ::max(y, oy);
			z = ::max(z, oz);
		}
}

void Part::debugOutput()
{
	int x, y, z;

	cout << "---------------------------------------------------" << endl;
	for(x = 0; x < maxExpansion; x++)
	{
		cout << "x = " << x << endl;
		for(y = 0; y < maxExpansion; y++)
		{
			for(z = 0; z < maxExpansion; z++)
			{
				cout << (space[x][y][z] ? '*' : ' ') << ' ';
			}
			cout << endl;
		}
	}
	waitkey();
}

