//------------------------------------------------------------
// $Id: GridColor.h,v 1.2.2.1 2000/06/14 15:00:10 yamauchi Exp $
//------------------------------------------------------------
//	(M\pi)^2 define grid color
//	Copyright (C) By Hitoshi YAMAUCHI  山内 斉
//------------------------------------------------------------
#ifndef _GridColor_h
#define _GridColor_h 1

#include <assert.h>
#include <iostream.h>
#include <stdio.h>
#include "Vector3.h"
#ifdef RED
# error "RED is already defined before. (like mp_marker.h) That's bad."
#endif

//------------------------------------------------------------
// grid (格子点)の内部表現
//    array3D に入れるため serialize 可能にするが，SerializeableIF
//    を継承すると size が増大するので interface の method 群を埋め込
//    んでいる．
//------------------------------------------------------------
// constants
// ppm file から読み込むものとしているので，内部の表現は 
// R, G, B, A の 4 種類とする
//------------------------------------------------------------
const int GridColorUNINITIALIZED = -1; // 色が初期化されていない場合の値
const int GridColorMAX_DEPTH	 = 255;	// depth の最大値

// class GridColor
class GridColorClass {
public:
    enum GRIDCOLOR {		
	RED,			
	GREEN,			
	BLUE, 
	ALPHA,
	NUM_OF_GRIDCOLOR
    };

public:	// static functions
    // interface for getting zero color
    static GridColorClass getZeroColor(void)
    {
	unsigned char col[3];
	col[0] = col[1] = col[2] = 0;
	return(GridColorClass(col, 0));
    }

protected:
    // 型は unsigned char でも良いかと思ったが，不正な値があると便
    // 利なので short とした．
    short int mRGBA[NUM_OF_GRIDCOLOR]; 
    
public:
    GridColorClass(void) 	
    {
	for(int i = 0; i < NUM_OF_GRIDCOLOR; i++)
	{
	    this->mRGBA[i]	= GridColorUNINITIALIZED;
	}
    }
    GridColorClass(unsigned char rgbcol[], unsigned char alpha) 	
    { 
	for(int i = 0; i < (NUM_OF_GRIDCOLOR - 1); i++)
	{
	    this->mRGBA[i]	= (short int)rgbcol[i];
	}
	this->mRGBA[ALPHA]	= alpha;
    }
    GridColorClass(const Vector3 rgbcol, unsigned char alpha) 	
    { 
	for(int i = 0; i < (NUM_OF_GRIDCOLOR - 1); i++)
	{
	    this->mRGBA[i]	= (short int)rgbcol.get(i);
	}
	this->mRGBA[ALPHA]	= alpha;
    }
    GridColorClass(const GridColorClass& rhs)
    { 
	for(int i = 0; i < NUM_OF_GRIDCOLOR; i++)
	{
	    this->mRGBA[i]	= rhs.mRGBA[i];
	}
    }
    const GridColorClass& operator=(const GridColorClass& rhs)
    {
	if(this != &rhs)
	{
	    for(int i = 0; i < NUM_OF_GRIDCOLOR; i++)
	    {
		this->mRGBA[i]	= rhs.mRGBA[i];
	    }
	}
	return(*this);
    }
    friend int operator==(const GridColorClass& a, const GridColorClass& b)
    {
	return((a.mRGBA[RED]   == b.mRGBA[RED]) &&
	       (a.mRGBA[GREEN] == b.mRGBA[GREEN]) &&
	       (a.mRGBA[BLUE]  == b.mRGBA[BLUE]) &&
	       (a.mRGBA[ALPHA] == b.mRGBA[ALPHA]));
    }
    friend int operator!=(const GridColorClass& a, const GridColorClass& b)
    {
	return(!((a.mRGBA[RED]   == b.mRGBA[RED])   &&
		 (a.mRGBA[GREEN] == b.mRGBA[GREEN]) &&
		 (a.mRGBA[BLUE]  == b.mRGBA[BLUE])  &&
		 (a.mRGBA[ALPHA] == b.mRGBA[ALPHA])));
    }
    friend ostream& operator<<(ostream& s, const GridColorClass& g)
    {
	s << g.mRGBA[RED] << " " << g.mRGBA[GREEN] << " " <<
		g.mRGBA[BLUE] << g.mRGBA[ALPHA];
	return(s);
    }

    // 以下の関数は再考を要する FIXHERE
    // というのも内部と外部の扱いをきりわけていないからだ ppm の値をそ
    // のまま使うのであれば型変換は下手にしない方が良い
    void setRGBColor(const Vector3 &v)
    {
	this->mRGBA[RED]   = (short int)(v.get(Vector3::X));
	this->mRGBA[BLUE]  = (short int)(v.get(Vector3::Y));	
	this->mRGBA[GREEN] = (short int)(v.get(Vector3::Z));
    }
    void setRGBColors(const int col[])
    {
	this->mRGBA[RED]   = (short int)(col[RED]);
	this->mRGBA[BLUE]  = (short int)(col[BLUE]);	
	this->mRGBA[GREEN] = (short int)(col[GREEN]);
    }
    void setAlpha(double alpha_val) 
    {
	this->mRGBA[ALPHA] = (short int)alpha_val;
    }
    Vector3 getRGBColor(void) const
    {
	return(Vector3((double)(this->mRGBA[RED]), 
		       (double)(this->mRGBA[BLUE]),
		       (double)(this->mRGBA[GREEN])));
    }
    double getAlpha(void) const
    {
	return((double)(this->mRGBA[ALPHA]));
    }
    
    void getRGBColorAsInt3Array(int color[]) const
    {
	for(int i = 0; i <= GridColorClass::BLUE; i++)
	{
	    color[i] = (int)(this->mRGBA[i]);
	}
    }
    int getAlphaAsInt(void) const 
    {
	return((int)(this->mRGBA[ALPHA]));
    }

    // この GridColor は初期化されたか
    int isInitialized(void) const 
    {
	return(this->mRGBA[RED] != GridColorUNINITIALIZED);
    }
    
    //----------------------------------------
    // SerializableIF : interfaces/serializable.h
    // double の表現が同じ計算機でないと上手くいかない    
    //----------------------------------------
    int getSerializedSize(void) const
    {
	// 要素数は R, G, B, A の 4 つ
	return(4);
    }
    double *newSerializedArray(void)
    {
	double *r = new double[4];
	r[RED]   = (double)(this->mRGBA[RED]);
	r[BLUE]  = (double)(this->mRGBA[BLUE]);
	r[GREEN] = (double)(this->mRGBA[GREEN]);
	r[ALPHA] = (double)(this->mRGBA[ALPHA]);
	return(r);
    }
    void deserialize(double *pBuf)
    {
	this->mRGBA[RED]	= (short int)(pBuf[0]);
	this->mRGBA[BLUE]	= (short int)(pBuf[1]);
	this->mRGBA[GREEN]	= (short int)(pBuf[2]);
	this->mRGBA[ALPHA]	= (short int)(pBuf[3]);
    }
};

#endif				// #ifndef _GridColor_h
