/*
 * $Id: $
 *
 * Description  : Data structure describing render tile data for distributed ray tracing
 * Author       : Jiri Bittner
 *
 * Purpose      :
 *     Long description of what the file is for.
 */



#ifndef __RENDER_TILE_DATA__H__
#define __RENDER_TILE_DATA__H__

#if LUKAS_RUZICKA_DEBUG
#define LUKAS_RUZICKA_DEBUG2 0
#define LUKAS_RUZICKA_DEBUG3 0
#endif


#include "3dmath.h"
#include <memory>
#if LUKAS_RUZICKA_DEBUG
#include "wx/longlong.h"
#endif
#if LUKAS_RUZICKA_DEBUG2
#include "flexilog.h"
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#endif


namespace VRUT
{
	class RenderTileData
	{
	public:
		#if LUKAS_RUZICKA_DEBUG
		wxULongLong time, totalTime;
		#endif
		int frameId;
		int tileIndex;
		short LOD;
		short skip;
		unsigned int cameraIndex;
		bool antialiasing;
		Vector2i minVal, maxVal;
		short imageWidth;
		short imageHeight;
		int workerId;
		// number of samples computed (return value)
		int samples;
		// number of pixels computed (return value)
		int numPixels;
		// the actual pixel data
		std::shared_ptr<Vector4> pixels;

		RenderTileData() : frameId(-1), tileIndex(-1), LOD(0), skip(0), cameraIndex(-1), antialiasing(false), imageWidth(0), imageHeight(0), workerId(-1), samples(0), numPixels(0), pixels(NULL)
		#if LUKAS_RUZICKA_DEBUG
		, time(INT_MAX), totalTime(0)
		#endif
		{}

		RenderTileData(const int frameId, const int tileIndex, const short LOD, const short skip, unsigned int cameraIndex, bool antialiasing, const Vector2i minVal, const Vector2i maxVal, const short imageWidth,
		const short imageHeight, const int workerId) : frameId(frameId), tileIndex(tileIndex), LOD(LOD), skip(skip), cameraIndex(cameraIndex), antialiasing(antialiasing), minVal(minVal), maxVal(maxVal),
		imageWidth(imageWidth), imageHeight(imageHeight), workerId(workerId), samples(0), numPixels(0), pixels(NULL) 
		#if LUKAS_RUZICKA_DEBUG
		, time(INT_MAX), totalTime(0)
		#endif
		{}

		~RenderTileData() {}
	};


	#if LUKAS_RUZICKA_DEBUG2
	class Node {
	private:
	public:
		//IPAddress ipAddress; //initialized after parsing (by outer code!)
		enum Role {
			NODE_DISPLAYING_CLIENT,
			NODE_COMPUTATIONAL_CLIENT,
			NODE_MASTER
		} role; //parsed
		wxString name; //parsed
		int port; //parsed
		unsigned long id; //parsed
		std::vector<unsigned long> neighbors; //parsed
		Node() {
		}
	};

	class Network {
	private:
	public:
		std::vector<Node> vertices;
		Network() {
		}
		Network(const std::vector<Node> & nodes) : vertices(nodes) {
			bool erase = false;
			for (size_t id = 0; id < vertices.size(); ++ id) {
				if (vertices[id].id != id) {// (n := vertices.size()) its not sorted or {0, 1, ..., n-1} -> serious error
					LOGERROR(wxString::Format(wxT("Network::Network(const std::vector<Node> &) : serious error : structure of passed argument isn't as required - id = %lu, vertices[id].id = %lu"), id, vertices[id].id));
					erase = true;
				}
			}
			if (erase) {
				vertices.clear();
				LOGERROR(wxT("Network::Network(const std::vector<Node> &) : since error in format occured, graph will be ignored and discarded."));
			}
		}
		std::vector<unsigned long> BreadthSearchID() const { //this generates topology good for parallel distribution (a -> b, c, d, ...)
			std::vector<unsigned long> result;
			result.resize(vertices.size(), UINT_MAX);

			for (size_t i = 0; i < vertices.size(); ++ i) {
				if (result[i] == UINT_MAX) { //it wasn't visited yet
					std::queue<unsigned long> nextNode;
					nextNode.push(i); //place it in queue...
					result[i] = i; //it points to self ~ it is root

					while (!nextNode.empty()) {
						auto node = nextNode.front();
						nextNode.pop();
						for (auto & child : vertices[node].neighbors) {
							if (result[child] == UINT_MAX) { //child wasn't visited yet
								nextNode.push(child); //place it in queue ...
								result[child] = node; //its parent is ...
							}
						}
					}
				}
			}

			return result;
		}
		std::vector<unsigned long> DepthSearchID() const { //this generates topology good for serial distribution (a -> b -> c -> d -> ...)
			std::vector<unsigned long> result;
			result.resize(vertices.size(), UINT_MAX);

			for (size_t i = 0; i < vertices.size(); ++ i) {
				if (result[i] == UINT_MAX) { //it wasn't visited yet
					std::stack<unsigned long> nextNode;
					nextNode.push(i); //place it in stack...
					result[i] = i; //it points to self ~ it is root

					while (!nextNode.empty()) {
						auto node = nextNode.top();
						bool markedChildren = false;
						for (auto & child : vertices[node].neighbors) {
							if (result[child] == UINT_MAX) { //child wasn't visited yet
								markedChildren = true;
								nextNode.push(child); //place it in stack ...
								result[child] = node; //its parent is ...
								break;
							}
						}
						if (!markedChildren) //nothing new?
							nextNode.pop(); //then there wouldn't be anything new in the future too => discard
					}
				}
			}

			return result;
		}
		size_t ComponentsOfConnectedness() const {
			auto vec = BreadthSearchID();
			size_t result = 0;
			for (size_t i = 0; i < vec.size(); ++ i) {
				if (vec[i] == i)
					++ result;
			}
			return result;
		}
		std::vector<unsigned long> GenerateListOfDirectSuccessorsID(const unsigned long myId, const std::vector<unsigned long> & tree) const {
			std::vector<unsigned long> result;
			for (size_t it = 0; it < vertices.size(); ++ it) {
				if ((it != myId) && (tree[it] == myId)) {
					result.push_back(it);
				}
			}
			return result;
		}
		/*std::vector<IPAddress> GenerateListOfDirectSuccessorsIPAddress(const unsigned long myId, const std::vector<unsigned long> & tree) const {
			std::vector<IPAddress> result;
			auto ids = GeneretaListOfDirectSuccessorsID(myId, tree);
			result.reserve(ids.size());
			for (auto & id : ids)
				result.push_back(vertices[id].ipAddress);
			return result;
		}*/
	};
	#endif //LUKAS_RUZICKA_DEBUG2
}

#endif
