
#include "SDL.h"
#include "SDL_opengl.h"

#include "block.h"
#include "cube.h"
#include "coordinate.h"
#include "material.h"

namespace block {
	Block::Block() {
		material=M_DEFAULT;
		displaylist=0;
	}

	bool Block::is_splitted() const {
		return sub.size()>0;
	}
	bool Block::is_active() const {
		return material!=M_NONE;
	}

	void Block::activate() {
		if (is_active()) return;
		material=M_DEFAULT;
	}
	void Block::deactivate() {
		material=M_NONE;
	}
	void Block::toggle() {
		if (material==M_NONE) { material=M_DEFAULT; } else { material=M_NONE; }
	}
	void Block::set_material(E_Material m) {
		material=m;
	}
	E_Material Block::get_material() const {
		return material;
	}

	void Block::dirty(){
		if (displaylist==0) { return; }
		glDeleteLists(displaylist,1);
		displaylist=0;
	}


	void Block::split() {
		if (is_splitted()) return;
		sub.resize(8);
		for (unsigned int i=0;i<8;i++) { sub[i].set_material(get_material()); }
	}
	void Block::merge() { 
		if (!is_splitted()) return;
		set_material(sub[0].get_material());
		sub.resize(0); 
	}

	void Block::check_merge() {
		Block *b;
		E_Material mat=M_SELECTED;
		E_Material nm;
		for (unsigned int i=0;i<8;i++) {
			b=get_child(i);
			if (b->is_splitted()) return;
			
			nm=b->get_material();
			if (mat==M_SELECTED) { mat=nm; continue; }
			if (nm!=mat) return;
		}
		merge();
		return;
	}


	Block *Block::get_child(unsigned int b){
		if (!is_splitted()) return NULL;
		return &sub[b];
	}

	bool Block::top_save(std::string filename) const{
		std::cout << "topsave " << filename << std::endl;
		std::ofstream of;
		of.open(filename.c_str());
		if (!of) return false;
		save(of);
		of.close();
		return true;
	}
	bool Block::top_load(std::string filename) {
		merge();
		std::ifstream ifstr;
		ifstr.open(filename.c_str());
		if (!ifstr) return false;
		load(ifstr);
		ifstr.close();
		return true;
	}

	void Block::save(std::ostream& st) const {
		E_Material savemat;
		savemat=get_material();
		if (is_splitted()) { savemat=M_SAVE_SPLITTED; }
		unsigned char status=0;
		status=static_cast<unsigned char>(savemat)+33;
		st << status;
		if (!is_splitted()) { return; }
		for (unsigned int i=0;i<8;i++) {
			sub[i].save(st);
		}
	}
	void Block::load(std::istream& st) {
		if (st.eof()) return;
		unsigned char status;
		st >> status;
		E_Material loadmat;
		loadmat=static_cast<E_Material>(status-33);
		if (loadmat!=M_SAVE_SPLITTED) {
			set_material(loadmat);
			return;
		}
		split();
		for (unsigned int i=0;i<8;i++) {
			sub[i].load(st);
		}
	}

	C3f Block::sub_positionf(unsigned int i) {
		switch (i) {
			case 0: return C3f(0,0,0);
			case 1: return C3f(1,0,0);
			case 2: return C3f(0,1,0);
			case 3: return C3f(1,1,0);

			case 4: return C3f(0,0,1);
			case 5: return C3f(1,0,1);
			case 6: return C3f(0,1,1);
			case 7: return C3f(1,1,1);
			default: return C3f();
		}
	}
	C3 Block::sub_position(unsigned int i) {
		switch (i) {
			case 0: return C3(0,0,0);
			case 1: return C3(1,0,0);
			case 2: return C3(0,1,0);
			case 3: return C3(1,1,0);

			case 4: return C3(0,0,1);
			case 5: return C3(1,0,1);
			case 6: return C3(0,1,1);
			case 7: return C3(1,1,1);
			default: return C3();
		}
	}


} //namespace
