//------------------------------------------------------------
// $Id: object.h,v 1.4.2.1 2000/06/14 15:00:11 yamauchi Exp $
//------------------------------------------------------------
//	object.h
//	1996/3/18 
//	(C) Copyright Hitoshi YAMAUCHI
//	object base class 全ての物体はここから始まる
//	IntVerClass を分離し，VertexIntensity.h に移動
//------------------------------------------------------------
#ifndef _object_h
#define _object_h

#include <stdlib.h>
#include <string.h>
#include "constants.h"
#include "IntVec3.h"
#include "material.h"
#include "ray.h"
#include "mpi2exit.h"
#include "VertexIntensity.h"

//------------------------------------------------------------
// object base class (all object(primitive) is derived from this.
//------------------------------------------------------------
// #define FOR_2DIM_OUT 1
enum object_type_e {
    TRIANGLE_OBJ_E,
    SPHERE_OBJ_E,
    NULL_OBJ_E			// xlC のおかげで ,を外さなくてはならん
};

class objBaseClass {
private:
    const objBaseClass& operator=(const objBaseClass& rhs);
    objBaseClass(const objBaseClass& rhs)
#if (__GNUC_MINOR__ == 5)
    {
 	cerr << "Why? gcc 2.5.8 need this" << endl; 
 	abort();
    }
#endif
    ;    

protected:
    int 	mObjectID;
    IntVec3 	mSpcPos;
    int		mMaterialID;	// material を指し示す ID

public:
    objBaseClass(void) : mObjectID(-1), mMaterialID(-1){};
    virtual ~objBaseClass(void){};

    // get object num(同一のobjectNumは同一のobjectで分割されるなりされている)
    int getObjectID(void) const   	{ return(this->mObjectID);	}
    // material ID (set は object が new される時)
    int getMaterialID(void) const 	{ return(this->mMaterialID); 	}

    // 分割空間位置
    const IntVec3 getSpcPos(void) const{ return(this->mSpcPos);	}

    // pure virtual functios
    // 物体までの距離(if ret PlusInfty =  not hit)
    virtual double getDistance(const Ray *const apRay, 
			       Vector3 *pHitPos) 		       = 0; 
    // shading のための輝度を返す(flat and shaded color)
    virtual Vector3 getFlatRadiosityColor(const Vector3& hitPos)       = 0;
    virtual Vector3 getShadedRadiosityColor(const Vector3& hitPos)     = 0;
    // 物体の法線ベクトルを返す arg = void の方は利用できない object あり
    virtual Vector3 getNormal(void) const	       		       = 0;
    virtual Vector3 getNormal(const Vector3& hitpos) const	       = 0;

    virtual void print(const char *pHead)			       = 0; 
    virtual void getMpi2Form(int type, char *pRes)	       	       = 0;
    virtual int  who(void) const				       = 0;
    virtual YorN checkSpcPos(const Vector3 &partmin, 
			     const Vector3 &subSpcSize, 
			     int subduvnum) const 	       	       = 0;

    //----- virtual functios but there is default. for radiation objects
    virtual void addUnshotRadiosity(const Vector3& rad)
    {				// use in triangle
	cerr << "Warning : only use in triangle. addUnshotRadiosity" << 
	    rad << endl;
	commMpi2_exit(1);
    } 
    virtual double flushUnshotRadiosityNInitVerInt(void)
    {				// use in triangle
	cerr << "Warning : only use in triangle. flushUnshotRadiosity" <<endl;
	commMpi2_exit(1);
	return(-1.0);
    }		  
    virtual double getNonRadEnergy(void) const
    {				// use in triangle
	cerr << "Warning : only use in triangle. getNonRadEnergy" << endl;
	commMpi2_exit(1);
	return(-1.0);
    }		  
    virtual void setInRadiationQueue(void)
    {
	cerr << "Warning : only use in triangle .setInRadiationQueue." << endl;
	commMpi2_exit(1);
    }
    virtual void unsetInRadiationQueue(void)
    {
	cerr << "Warning : only use in triangle. setInRadiationQueue." << endl;
	commMpi2_exit(1);
    }
    virtual YorN isInRadiationQueue(void) const
    {
	cerr << "Warning : only use in triangle. isInRadiationQueue." << endl;
	commMpi2_exit(1);
	return(NO);		// for -Wall
    }
    virtual double getArea(void) const
    {				// 物体の面積を返す
	cerr << "Warning : only use in triangle. getArea." << endl;
	commMpi2_exit(1);
	return(0.0);		// for -Wall
    }
    virtual const Vector3 getGCenter(void) const
    {				// 物体の重心を返す
	cerr << "Warning : only use in triangle. getGCenter." << endl;
	commMpi2_exit(1);
	static Vector3 ret(-1.0, -1.0, -1.0);
	return(ret); // for -Wall
    }
    virtual const Vector3 getNClearNonRadAndUpdateRadiosity(void)
    {
	cerr << "Warning : only use in triangle.getNClearNonRad." << endl;
	commMpi2_exit(1);
	static Vector3 ret(0.0, 0.0, 0.0);
	return(ret);
    }
    virtual void addIntensityToVertex(const VertexIntensity& vint)
    {
	cerr << "Warning : only use in triangle. addIntensityToVertex."<< endl;
	commMpi2_exit(1);
	VertexIntensity a = vint; a = a; // for -Wall;
    }
    virtual void getRadVer(VertexIntensity *pRadiosityVertexInfo3)
    {				 // polygon 全体の明るさを返す:各頂点輝度でない
	cerr << "Warning : only use in triangle. pIntensityVertexInfo."<< endl;
	commMpi2_exit(1);
	pRadiosityVertexInfo3 = pRadiosityVertexInfo3;
    }
    virtual void getVerIntensity(VertexIntensity *pIntensityVertexInfo3)
    {				 // 各頂点の輝度を返す
	cerr << "Warning : only use in triangle. pIntensityVertexInfo."<< endl;
	commMpi2_exit(1);
	pIntensityVertexInfo3 = pIntensityVertexInfo3;
    }
    //     virtual const Vector3 getNonRad(void)     
    //     { 
    // 	cerr << "Warning : only use in triangle. Vector3."<< endl;
    // 	commMpi2_exit(1);
    // 	return(Vector3(0.0, 0.0, 0.0));
    //     }
    virtual void calcVerIntAveVal(void)
    {
	cerr << "Warning : only use in triangle. calcVerIntAveVal."<< endl;
	commMpi2_exit(1);
    }
    
//------------------------------
// for 2 dimension output 
#ifdef FOR_2DIM_OUT
    virtual int  get2dimPoiNumbers(void) const = 0;
    virtual void get2dimPoint(int idx, double *x, double *y, double *z) = 0;
#endif
//------------------------------
};

//------------------------------
// NULL object (どの object でもない)
//------------------------------
class nullObjectClass : public objBaseClass {
private:
    const nullObjectClass& operator=(const nullObjectClass& rhs);

protected:
    virtual Vector3 getNormal(void) const
    {
	static Vector3 illegal(-1.0, -1.0, -1.0);
	return(illegal);
    }

public:
    nullObjectClass(void)
    {
	this->mObjectID 	= -1;
	this->mMaterialID	= -1;
    }
    nullObjectClass(const nullObjectClass& rhs)
    {
	this->mObjectID		= rhs.mObjectID;
	this->mSpcPos		= rhs.mSpcPos;
	this->mMaterialID	= rhs.mMaterialID;
    }
    virtual double getDistance(const Ray *const apRay, Vector3 *pHitPos)
    { 
	return(PlusInfty); 
	apRay->print("Error!");	// for Wall 
	pHitPos = pHitPos;	// for Wall 
    }
    virtual Vector3 getFlatRadiosityColor(const Vector3& hitPos)
    {
	static Vector3 illegal(-1.0, -1.0, -1.0);
	return(illegal);
	cerr << hitPos << endl;	// for Wall
    }
    virtual Vector3 getShadedRadiosityColor(const Vector3& hitPos)
    {
	static Vector3 illegal(-1.0, -1.0, -1.0);
	return(illegal);
	cerr << hitPos << endl;	// for Wall
    }
    virtual Vector3 getNormal(const Vector3& hitpos) const
    {
	static Vector3 illegal(-1.0, -1.0, -1.0);
	return(illegal);
	cerr << hitpos << endl;	// for Wall
    }
    virtual void print(const char *pHead){
	cerr << pHead << " This is NULL object." << endl;
    }
    virtual void getMpi2Form(int outtype, char *pRes)
    {
	strcpy(pRes, "# Null Object");
	return;
	outtype = outtype;	// for Wall
    }
    virtual int  who(void) const {
	return(NULL_OBJ_E);
    }
    virtual YorN checkSpcPos(const Vector3 &partmin, 
			     const Vector3 &subSpcSize,
			     int subdivnum) const
    {
	return(NO);
	cout << partmin << subSpcSize << subdivnum << endl; // for Wall
    }

//------------------------------
// for 2 dimension output 
#ifdef FOR_2DIM_OUT
    virtual int  get2dimPoiNumbers(void) const { return(-1);	}
    virtual void get2dimPoint(int idx, double *x, double *y, double *z){
	(*x) = (*y) = (*z) = -1.0; idx = 1;
    }
#endif
};    


#endif				// #ifndef _object_h
