#ifndef WALLS_H
#define WALLS_H

#include <Indoor/floorplan/v2/Floorplan.h>
#include "../gl/GLHelper.h"
#include "../gl/GLTriangles.h"
#include "../gl/GLLines.h"
#include "../Renderable.h"
#include "../gl/Shader.h"


class Walls : public Renderable {

private:

	Floorplan::Floor* floor;

	GLTriangles<VertNormTexTan> triangles;
	GLLines outlines;

	bool outlineOnly = false;
	bool transparent = false;

public:

	/** ctor */
	Walls(Floorplan::Floor* floor) : floor(floor) {
		setOutlineOnly(false);
	}


	void initGL() override {

		build();

		triangles.build();
		triangles.setDiffuse(":/res/gl/tex/wall3.jpg");
		triangles.setNormalMap(":/res/gl/tex/wall3_normal.jpg");

		outlines.build();

	}

	/** render the floor */
	void _render(const RenderParams& params) override {

		// skip me?
		if (params.clipAboveHeight_m < floor->atHeight) {return;}

		if (transparent) {
			program.setUniformValue("alpha", 0.5f);
			glEnable(GL_BLEND);
		} else {
			program.setUniformValue("alpha", 1.0f);
			glDisable(GL_BLEND);
		}

		if (outlineOnly) {
			glLineWidth(1);
			outlines.render(&program);
		} else {
			triangles.render(&program);
		}

		glDisable(GL_BLEND);

	}

	/** render only the outline? */
	void setOutlineOnly(const bool outline) override {
		this->outlineOnly = outline;
		if (outlineOnly) {
			loadShader(":/res/gl/vertex1.glsl", ":/res/gl/fragmentLine.glsl");
			program.setUniformValue("color", QVector4D(0.9, 0.9, 0.9, 1.0));
		} else {
			loadShader(":/res/gl/vertex1.glsl", ":/res/gl/fragmentTex.glsl");
			program.setUniformValue("texDiffuse", 0);
			program.setUniformValue("texNormalMap", 1);
		}
	}

	void setTransparent(const bool transparent) override {
		this->transparent = transparent;
	}


private:

	void build() {

		for (Floorplan::FloorObstacle* obstacle : floor->obstacles) {

			if (dynamic_cast<Floorplan::FloorObstacleLine*>(obstacle)) {
				Floorplan::FloorObstacleLine* line = dynamic_cast<Floorplan::FloorObstacleLine*>(obstacle);
				if (line->type != Floorplan::ObstacleType::WALL) {continue;}
				addFace(line->from, line->to, floor->getStartingZ(), floor->getEndingZ());
			} else if (dynamic_cast<Floorplan::FloorObstacleDoor*>(obstacle)) {
				Floorplan::FloorObstacleDoor* door = dynamic_cast<Floorplan::FloorObstacleDoor*>(obstacle);
				addFace(door->from, door->to, floor->getStartingZ() + door->height, floor->getEndingZ());
			}

		}

	}

	void addFace(const Point2 from, const Point2 to, const float h1, const float h2) {

		const QVector3D vert1(from.x, h1, from.y);
		const QVector3D vert2(to.x, h1, to.y);
		const QVector3D vert3(to.x, h2, to.y);
		const QVector3D vert4(from.x, h2, from.y);

		const QVector3D n1 = GLHelper::getNormal(vert1, vert2, vert3);
		const QVector3D n2 = -n1;



		QVector3D tan = (vert1-vert2).normalized();
		tan = GLHelper::isCCW(vert1, vert2, vert3) ? (tan) : (-tan);

		const float l = from.getDistance(to);
		const float h = h2-h1;
		const float o = std::min(from.length(), to.length());

		const QVector2D tex1(o+0, h);		// start texturing at the ceiling so above-door-sections and walls have the same textre
		const QVector2D tex2(o+l, h);
		const QVector2D tex3(o+l, 0);
		const QVector2D tex4(o+0, 0);

		const float s = 0.65;



		{
			const VertNormTexTan vnt1(vert1, n1, tex1*s, tan);
			const VertNormTexTan vnt2(vert2, n1, tex2*s, tan);
			const VertNormTexTan vnt3(vert3, n1, tex3*s, tan);
			const VertNormTexTan vnt4(vert4, n1, tex4*s, tan);
			triangles.addQuadCCW(vnt1, vnt2, vnt3, vnt4);
		} {
			const VertNormTexTan vnt1(vert1, n2, tex1*s, -tan);
			const VertNormTexTan vnt2(vert2, n2, tex2*s, -tan);
			const VertNormTexTan vnt3(vert3, n2, tex3*s, -tan);
			const VertNormTexTan vnt4(vert4, n2, tex4*s, -tan);
			triangles.addQuadCW(vnt1, vnt2, vnt3, vnt4);
		}

		outlines.addLine(vert1, vert2);
		outlines.addLine(vert2, vert3);
		outlines.addLine(vert3, vert4);
		outlines.addLine(vert4, vert1);

	}

//private:
//
//	QVector2D tex(const QVector3D vert) {
//		return QVector2D(vert.x(), vert.y());
//	}

};

#endif // WALLS_H
