//-----------------------------------------------------------------------------
void BoundaryMap::AddCanvas(const TriangleMesh& mesh)
{
    if (!(mState == ALLOCATED || mState == GENERATED))
    {
        return;
    }

    //
    // compute bounding box from canvas bb
    //
    Vector3f v1 = mesh.getBoundingBox().getV1();
    Vector3f v2 = mesh.getBoundingBox().getV2();

    Vector3f diff;
    Vector3f::minus(v2, v1, diff);
    diff.scale(1.0f/mDx);
    diff.ceil();

    // Save number of grid samples in each direction
    mIMax = static_cast<unsigned int>(diff.getX()) + 1;
    mJMax = static_cast<unsigned int>(diff.getY()) + 1;
    mKMax = static_cast<unsigned int>(diff.getZ()) + 1;
    mTotalSamples = mIMax*mJMax*mKMax;

    // adjust v2 to makes sure the grid fully contains the canvas
    diff.scale(mDx);

    v2 = v1;
    v2.add(diff);

    // set bounding box
    mDomain = Rectangle3f(v1, v2);

    //
    // (re)Init signed distance field
    //
    mNodeContents.clear();
    mNodeContents.Init(mIMax, mJMax, mKMax);
    this->Dump();

    //
    //  compute signed distance field
    //
    this->computeSignedDistanceField(mNodeContents, mesh);
    mState = INITIALIZING;
}
Rectangle3f RayIntersectorKDTreeNode::ComputeBBox(const Vector<UINT> &TriangleIndices, const RayIntersectorKDTree &Root) const
{
    Rectangle3f BBox;
    for(UINT TriangleIndex = 0; TriangleIndex < TriangleIndices.Length(); TriangleIndex++)
    {
        const UINT BaseIndexIndex = TriangleIndices[TriangleIndex] * 3;
        for(UINT VertexIndex = 0; VertexIndex < 3; VertexIndex++)
        {
            const Vec3f &CurVertex = Root._Vertices[Root._Indices[BaseIndexIndex + VertexIndex]];
            if(TriangleIndex == 0 && VertexIndex == 0)
            {
                BBox = Rectangle3f(CurVertex, CurVertex);
            }
            else
            {
                BBox.Min = Vec3f::Minimize(BBox.Min, CurVertex);
                BBox.Max = Vec3f::Maximize(BBox.Max, CurVertex);
            }
        }
    }
    return BBox;
}
Camera::Camera(const glm::vec3& defaultPos) : Transformable(Rectangle3f(defaultPos.x, defaultPos.y, defaultPos.z, 0, 0, 0))
{}
OBJWrapper::OBJWrapper(Updatable* parent, File& file) : Drawable(parent, NULL)
{
	//Information for the Transformation::defaultConf
	glm::vec3 defaultPositionMax;
	glm::vec3 defaultPositionMin;
	bool defaultPositionInit=false;

	//The vertex values for a specific OBJ
	std::vector<float> vertexPosition;
	std::vector<float> vertexNormal;
	std::vector<int>   vertexDrawOrder;
	std::vector<int>   vertexNormalOrder;

	//Associated an material (by its key str) to its number of vertices when it is being used
	std::map<std::string, int> materialSerie;
	int faceSerie = 0; //The serie of the material

	std::string currentMaterial; //the current material key
	bool currentMaterialInit = false; 

	OBJDatas* currentDatas = NULL;

	while(true)
	{
		char* buffer = file.readLine();
		std::string line;

		if(buffer != NULL)
		{
			line = std::string(buffer);
			unsigned int loc;
			
			//Replace two spaces by one
			while((loc = line.find("  ")) != std::string::npos) //Two spaces here
				line.replace(loc,2," "); //Single space in quotes
			if(std::regex_match(line, std::regex("^ *#$")))
				free(buffer);
			continue;
		}

		if(buffer == NULL || std::regex_match(line, std::regex("^o ")))
		{
			if(currentDatas)
			{
  				currentDatas->vertexPositionLength = COORDS_PER_VERTEX * vertexDrawOrder.size();
			    currentDatas->vertexNormalLength   = COORDS_PER_VERTEX * vertexNormalOrder.size();

				//fill datas
				float* vertexPositionArray = (float*) malloc(sizeof(float) * currentDatas->vertexPositionLength);
				float* vertexNormalArray   = (float*) malloc(sizeof(float) * currentDatas->vertexNormalLength);

				//Get the value of the position switch the order we get
				for(unsigned int i=0; i < vertexDrawOrder.size(); i++)
				{
					int offset = vertexDrawOrder[i] * COORDS_PER_VERTEX;
					glm::vec3 vPos = glm::vec3(vertexPosition[offset], vertexPosition[offset+1], vertexPosition[offset+2]);
					//get the default position min and max
					//First init the position
					if(!defaultPositionInit)
					{
						defaultPositionInit = true;
						defaultPositionMin = defaultPositionMax = vPos;
					}

					//then get the x value
					else if(defaultPositionMin.x > vPos.x)
						defaultPositionMin.x = vPos.x;
					else if(defaultPositionMax.x < vPos.x)
						defaultPositionMax.x = vPos.x;
					//the y value
					else if(defaultPositionMin.y > vPos.y)
						defaultPositionMin.y = vPos.y;
					else if(defaultPositionMax.y < vPos.y)
						defaultPositionMax.y = vPos.y;
					//and the z value
					else if(defaultPositionMin.z > vPos.z)
						defaultPositionMin.z = vPos.z;
					else if(defaultPositionMax.z < vPos.z)
						defaultPositionMax.z = vPos.z;

					//Store the vertex position get by the order in the vertexPositionArray
					for(uint32_t j=0; j < COORDS_PER_VERTEX; j++)
						vertexPositionArray[COORDS_PER_VERTEX*i + j] = vertexPosition[offset + j];
				}

				for(unsigned int i=0; i < vertexNormalOrder.size(); i++)
				{
					int offset = vertexNormalOrder[i] * COORDS_PER_VERTEX;
					for(int j=0; j < COORDS_PER_VERTEX; j++)
						vertexNormalArray[COORDS_PER_VERTEX*i + j] = vertexNormal[offset + j];
				}

				//create and fill VBOs
				glGenBuffers(1, &(currentDatas->vboID));
				glBindBuffer(GL_ARRAY_BUFFER, currentDatas->vboID);
				{
					glBufferData(GL_ARRAY_BUFFER, sizeof(float) * (currentDatas->vertexPositionLength + currentDatas->vertexNormalLength), NULL, GL_DYNAMIC_DRAW);
					glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float) * currentDatas->vertexPositionLength, vertexPositionArray);
					glBufferSubData(GL_ARRAY_BUFFER, sizeof(float) * currentDatas->vertexPositionLength, sizeof(float) * currentDatas->vertexNormalLength, vertexNormalArray);
				}
				glBindBuffer(GL_ARRAY_BUFFER, 0);

				//say how many faces per materials
				if(currentMaterialInit)
				{
					materialSerie.insert(std::make_pair(currentMaterial, faceSerie*COORDS_PER_VERTEX)); //because 3 vertex per faces
					currentDatas->materialSerie = materialSerie;
				}
			}

			if(buffer == NULL)
				break;

			//reinit the vertex
			{
				vertexDrawOrder          = std::vector<int>();
				vertexNormalOrder        = std::vector<int>();
				materialSerie            = std::map<std::string, int>();
				faceSerie                = 0;
				currentMaterialInit      = false;

				std::string name         = split(line, ' ')[1];
				OBJDatas* currentDatas   = new OBJDatas();
				currentDatas->mtlWrapper = NULL;
				m_objDatas.add(name, currentDatas);
			}
		}

		//Init the material file
		else if(std::regex_match(line, std::regex("^mtllib ")))
		{
			std::vector<std::string> pathSplited = split(file.getPath(), '/');
			std::string path="";
			for(unsigned int i=0; i < pathSplited.size()-1; i++)
				path                += pathSplited[i];
			std::string mtlName      = split(line, ' ')[1];
			path                    += mtlName;

			File f(JniMadeOf::jenv, JniMadeOf::context, path.c_str(), "r");
			currentDatas->mtlWrapper = new MaterialWrapper(f);
			m_mtlWrapper.add(mtlName, currentDatas->mtlWrapper);
		}

		else if(std::regex_match(line, std::regex("^usemtl ")))
		{
			if(currentMaterialInit)
				materialSerie.insert(std::make_pair(currentMaterial, faceSerie*COORDS_PER_VERTEX));
			currentMaterialInit = true;
			currentMaterial     = split(line, ' ')[1];
			faceSerie          = 0;
		}

		else if(std::regex_match(line, std::regex("^v ")))
		{
			std::vector<std::string> pointValues = split(line, ' ');
			for(unsigned int i=1; i < pointValues.size(); i++)
				vertexPosition.push_back(atoi(pointValues[i].c_str()));
		}

		else if(std::regex_match(line, std::regex("^vn ")))
		{
			std::vector<std::string> pointValues = split(line, ' ');
			for(unsigned int i=1; i < pointValues.size(); i++)
				vertexNormal.push_back(atoi(pointValues[i].c_str()));
		}	

		else if(std::regex_match(line, std::regex("^f ")))
		{
			std::vector<std::string> faceValue = split(line, ' ');
			for(unsigned int i=0; i < faceValue.size(); i++)
			{
				std::vector<std::string> orderValue = split(faceValue[i], '/');
				for(unsigned int j=0; j < orderValue.size(); j++)
				{
					if(orderValue[j] == "")
						continue;
					if(j==0)
						vertexDrawOrder.push_back(atoi(orderValue[j].c_str()));
					else if(j==2)
						vertexNormalOrder.push_back(atoi(orderValue[j].c_str()));
				}
			}
		}

		if(buffer != NULL)
			free(buffer);
	}
	setDefaultConf(Rectangle3f(defaultPositionMin, defaultPositionMax-defaultPositionMin));
}
//-----------------------------------------------------------------------------
void BoundaryMap::Load (const std::string& filename)
{
    this->Reset();
    std::ifstream file;
    file.open(filename);
    file >> mRestDistance;
    std::cout << mRestDistance << std::endl;
    file >> mCompactSupport;
    std::cout << mCompactSupport << std::endl;
    file >> mMaxDist;
    std::cout << mMaxDist << std::endl;
    file >> mDx;
    float v1[3];
    float v2[3];
    file >> v1[0];
    file >> v1[1];
    file >> v1[2];
    file >> v2[0];
    file >> v2[1];
    file >> v2[2];
    mDomain = Rectangle3f(Vector3f(v1[0], v1[1], v1[2]), 
        Vector3f(v2[0], v2[1], v2[2]));
    file >> mIMax;
    file >> mJMax;
    file >> mKMax;
    file >> mTotalSamples;
    file >> mNumCoordinates;
    mIndexMap = new unsigned int[mTotalSamples];
    mNodeContentsTable = new float[(mNumCoordinates + 1)*NC_NUM_ELEMENTS];
    mNodeContentsTable[NC_DISTANCE] = mRestDistance;
    mNodeContentsTable[NC_NORMAL_X] = 0.0f;
    mNodeContentsTable[NC_NORMAL_Y] = 0.0f;
    mNodeContentsTable[NC_NORMAL_Z] = 0.0f;


    for (unsigned int i = 0; i < mTotalSamples; i++)
    {
        mIndexMap[i] = 0;
    }

    unsigned int coord[3];
    unsigned int idx;
    float content;
    
    for (unsigned int i = 0; i < mNumCoordinates; i++)
    {
        file >> coord[0];
        file >> coord[1];
        file >> coord[2];
        idx = coord[0] + mIMax*(coord[1] + mJMax*coord[2]);
        mIndexMap[idx] = i + 1;

        for (unsigned int j = 0; j < NC_NUM_ELEMENTS; j++)
        {
            file >> content;
            mNodeContentsTable[(i + 1)*NC_NUM_ELEMENTS + j] = content;
        }
    }
    
    file.close();

    mState = GENERATED;

}