#ifndef ATS_DXF_H
#define ATS_DXF_H

#include <GL/glut.h>
#include <fstream.h>
#include <vector>
#include <io.h>
#include "ats_point.h"
#include "ats_component.h"
#include "ats_composite.h"
#include "ats_leaf.h"
#include "ats_exception.h"

namespace ats
{
	template<class T>
	class Dxf : public Leaf3D<T>
	{
	protected:
		std::vector<T> m_pnt_array;
		std::vector<int> m_idx_array;
		std::vector<T> m_nrm_array;
		T m_scale;
		// 0 xmax 1 xmin 2 ymax 3 ymin 4 zmax 5 zmin
		Point<T> m_box[6];

		virtual void cul_normal();
		virtual void read_pnt(::ifstream& dxf);
		virtual void set_scale();

	public:
		Dxf(const char* filename);
		virtual void Draw();
		virtual void UpdateTime(double) {};
	};

	// コンストラクタ -----------------------------------------------------
	template<class T>
	Dxf<T>::Dxf(const char* filename)
	{
		::ifstream dxf(filename, ios::nocreate);
		if(!dxf.is_open()){
			throw cant_open_file("DXF::DXF ファイルが開けません");
		}
		read_pnt(dxf);
		cul_normal();
		dxf.close();

		set_scale();
	}

	// 描画関数 -----------------------------------------------------------
	template<class T>
	void Dxf<T>::Draw()
	{
		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
		glDisable(GL_LIGHTING);
		glPushMatrix();
		glScaled(m_scale, m_scale, m_scale);
		glColor3f(1.0, 1.0, 1.0);
		glVertexPointer(3, GL_DOUBLE, 0, reinterpret_cast<void*>(m_pnt_array.begin()) );
		glNormalPointer(GL_DOUBLE, 0, reinterpret_cast<void*>(m_nrm_array.begin()) );
		glDrawElements(GL_QUADS, m_idx_array.size(), GL_UNSIGNED_INT, reinterpret_cast<void*>(m_idx_array.begin()));
		glPopMatrix();
	}

	// 法線計算 ------------------------------------------------------------
	template<class T>
	void Dxf<T>::cul_normal()
	{
		m_nrm_array.resize(m_pnt_array.size());
		for(int i=0; i < m_pnt_array.size(); i+=3){
//				normal(&m_pnt_array[i], &m_pnt_array[i+1], &m_nrm_array[i]);
		}
	}

	// ポイント読み込み ----------------------------------------------------

	template<class T>
	void Dxf<T>::read_pnt(::ifstream& dxf)
	{
		std::vector<T> pnt_array(::filelength( dxf.fd() ) / 5);
		/****************************************************
		* char command[1024]バッファはSTLのfstreamの速度が
		* 改善した時点でstringに変更すること。
		****************************************************/
		char command[1024] = {0};
		static int i=0;
		do
		{
			dxf >> command;

			if(!strcmp(command, "3DFACE"))
			{
				char tmp[256];
				while(strcmp("10", tmp)){ dxf >> tmp; }

				for(int j=i; i < j+12; i+=3)
				{
					dxf >> pnt_array[i] >> tmp
						>> pnt_array[i+1] >> tmp
						>> pnt_array[i+2] >> tmp; // 10 もしくは最後の0
				}
			}
		} while(strcmp(command, "EOF"));

		int pnt_size = i - 3;
		m_pnt_array.resize(pnt_size);
		for(i=0; i <= pnt_size; i++){
			m_pnt_array[i] = pnt_array[i];
		}
		m_idx_array.resize(pnt_size/3);
		int j;
		for(j=0; j < pnt_size/3; j++)
		{
			m_idx_array[j] = j;

		}
		cout << "first : " << m_pnt_array[0] << ' ' << m_pnt_array[1] << ' ' << m_pnt_array[2] << endl;
		cout << "point : " << m_pnt_array.size() << endl
			   << "polygon : " << m_idx_array.size() << endl;
	}

	
	// オブジェクトの最大値がsizeで表示されるように -------------------------
	// スケールを設定
	template<class T>
	void Dxf<T>::set_scale()
	{
		for(int i=0; i < m_pnt_array.size() /3; i++){
			if(m_box[0].X() < m_pnt_array[i*3]){
				m_box[0].X(m_pnt_array[i*3]);
				m_box[0].Y(m_pnt_array[i*3+1]);
				m_box[0].Z(m_pnt_array[i*3+2]);
			}
			if(m_box[1].X() > m_pnt_array[i*3]){
				m_box[1].X(m_pnt_array[i*3]);
				m_box[1].Y(m_pnt_array[i*3+1]);
				m_box[1].Z(m_pnt_array[i*3+2]);
			}
			if(m_box[2].Y() < m_pnt_array[i*3+1]){
				m_box[2].X(m_pnt_array[i*3]);
				m_box[2].Y(m_pnt_array[i*3+1]);
				m_box[2].Z(m_pnt_array[i*3+2]);
			}
			if(m_box[3].Y() > m_pnt_array[i*3+1]){
				m_box[3].X(m_pnt_array[i*3]);
				m_box[3].Y(m_pnt_array[i*3+1]);
				m_box[3].Z(m_pnt_array[i*3+2]);
			}
			if(m_box[4].Z() < m_pnt_array[i*3+2]){
				m_box[4].X(m_pnt_array[i*3]);
				m_box[4].Y(m_pnt_array[i*3+1]);
				m_box[4].Z(m_pnt_array[i*3+2]);
			}
			if(m_box[5].Z() > m_pnt_array[i*3+2]){
				m_box[5].X(m_pnt_array[i*3]);
				m_box[5].Y(m_pnt_array[i*3+1]);
				m_box[5].Z(m_pnt_array[i*3+2]);
			}
		}
		T obj_size, scale_size = 1.5;
		obj_size = fabs(m_box[0].X() - m_box[1].X());
		obj_size = (obj_size == 0) ? 0.000000000001 : obj_size;
		T sx = scale_size / obj_size;

		obj_size = fabs(m_box[2].Y() - m_box[3].Y());
		obj_size = (obj_size == 0) ? 0.000000000001 : obj_size;
		T sy = scale_size / obj_size;

		obj_size = fabs(m_box[4].Z() - m_box[5].Z());
		obj_size = (obj_size == 0) ? 0.000000000001 : obj_size;
		T sz = scale_size / obj_size;

		m_scale = (sx < sy) ? sx : sy;
		m_scale = (m_scale < sz) ? m_scale : sz;
		cout << "scale : " << m_scale << endl;
	}


}

#endif // ATS_DXF_H
