/*
QtWagon: a project about 3D objects.
Science and technology promotion license applied. Third party license automatically cascaded.
Zhikai Wang/ www.heteroclinic.net 2013
You can do anything with this file or any file(s) published as part QtWagon project, given this header is kept.
*/
#ifndef __ORIENTATION
#define __ORIENTATION
#include "mathVector.h"
#include "mathMatrix.h"
#include <iostream>

//Virtual class virtual func() = 0;
//Rather a test.
template <class T>
class orientation {
protected:
	//T data[16];
	mathVector<T> up;
	mathVector<T> left;
	mathVector<T> front;
public:
	virtual void roll(T degree = 1.0) = 0;
	virtual void yaw(T degree = 1.0) = 0;
	virtual void pitch(T degree = 1.0) = 0;
	virtual void drawAxis(T scale = 1.0f) = 0;
	virtual void draw(T scale = 1.0f) = 0;
	virtual void apply() = 0;
	//orientation
	orientation(const T nup[],const T nleft[],const T nfront[]):
	up(nup),left(nleft),front(nfront)
	{
		normalize();
	}
	virtual ~orientation() {
		//std::cout<<" ~orientation() "<<std::endl;

	}
	void normalize () {
		up.normalize();
		left.normalize();
		front.normalize();
	}

	orientation() {
#ifdef __USE_DOUBLE
				const double t1[] = {0.0,1.0,0.0};
		const double t2[] = {1.0,0.0,0.0};
		const double t3[] = {0.0,0.0,1.0};

#else
				const float t1[] = {0.0,1.0,0.0};
		const float t2[] = {1.0,0.0,0.0};
		const float t3[] = {0.0,0.0,1.0};

#endif
		up =  mathVector<T>(t1);
		left =  mathVector<T>(t2);
		front =  mathVector<T>(t3);

	}
	orientation(const orientation & no) {
		up = no.up;
		left = no.left;
		front = no.front;

	}
	// assignment operator
	orientation & operator=(const orientation & no) {
		if (this == &no) return *this;  // time-saving self-test
		up = no.up;
		left = no.left;
		front = no.front;

		return *this;                    // for daisy-chaining
	}

	template <class U> 
	friend std::ostream & operator << (std::ostream & os,const orientation<U> & mm);
	template <class U> 
	friend std::istream & operator >> (std::istream & is, orientation<U> & mm);

	const mathVector<T> & getUpVectorRef() const {
		return up;
	}
	const mathVector<T> & getLeftVectorRef() const {
		return left;
	}
	const mathVector<T> & getFrontVectorRef() const {
		return front;
	}

	const mathVector<T>  getUpVectorValue() const {
		return mathVector<T>(up);
	}
	const mathVector<T>  getLeftVectorValue() const {
		return mathVector<T>(left);
	}
	const mathVector<T>  getFrontVectorValue() const {
		return mathVector<T>(front);
	}

	// 5. get pointers
	T * getUpPointer() const{
		return up.getDataPointer();
	}
	T * getLeftPointer() const{
		return left.getDataPointer();
	}
	T * getFrontPointer() const{
		return front.getDataPointer();
	}
};
template <class U> 
std::ostream & operator << (std::ostream & os,const orientation<U> & or) {
	os<<or.up;
	os<<or.left;
	os<<or.front;
	return os;

};
template <class U> 
std::istream & operator >> (std::istream & is, orientation<U> & or ) {
	is>>or.up;
	is>>or.left;
	is>>or.front;
	return is;
};
#endif