// Aqsis
// Copyright (c) 1997 - 2001, Paul C. Gregory
//
// Contact: pgregory@aqsis.com
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

/**
 * Copyright (C) 2006-2007  NTT DATA CORPORATION
 * 
 * Version: 1.0.0 2007/04/01
 *  
 */
package net.cellcomputing.himawari.library;

import static net.cellcomputing.himawari.library.RiGlobal.QGetRenderContext;
import static net.cellcomputing.himawari.library.RiGlobal.QGetRenderContextI;
import net.cellcomputing.himawari.util.HimawariLogger;
/**
 *
 * @author NTT DATA Corporation
 */
public strictfp class CqTextureMapBuffer {


//	protected  TqPuchar	m_pBufferData;	///< Pointer to the image data.

	//高速化のチューニングを行うためコメントアウト
//	protected  ArrayList<Byte>	m_pBufferData;	///< Pointer to the image data.
//	protected  STLArrayList	m_pBufferData;	///< Pointer to the image data.
	protected  Object[]	m_pBufferData;	///< Pointer to the image data.

	protected  long	m_sOrigin;		///< Horizontal segment origin.
	protected  long	m_tOrigin;		///< Vertical segment origin.
	protected	long	m_Width;		///< Width of segment.
	protected	long	m_Height;		///< Height of segment.
	protected	int	m_Samples;		///< Number of samples per pixel.
	protected	int	m_Directory;	///< TIFF directory index. Used for multi image textures, i.e. cubeface environment.
	protected	boolean	m_fProtected;	///< Flag indicating if this buffer is protected from being automatically delted by the cache.

	/**
	 * データを格納するクラス
	 */
	protected Class dataClass;
	public CqTextureMapBuffer(){
		//高速化
//        m_pBufferData = new ArrayList<Byte>();
		dataClass = Byte.class;
        m_sOrigin =  0 ;
        m_tOrigin =  0 ;
        m_Width =  0 ;
        m_Height =  0 ;
        m_Samples =  0 ;
        m_Directory =  0 ;
        m_fProtected =  false ;

	}
	
	public void destruct(){
	        Release();
	}

	    /** Initialise the buffer reference to the specified format.
	     * \param xorigin Integer origin within the texture map.
	     * \param yorigin Integer origin within the texture map.
	     * \param width Width of the buffer segment.
	     * \param height Height of the buffer segment.
	     * \param samples Number of samples per pixel.
	     * \param directory The directory within the TIFF image map, used for multi image formats, i.e. cubeface environment map.
	     * \param fProt A flag indicating the buffer should be protected from removal by the cache management system.
	     */
	 public void	Init( long xorigin, long yorigin, long width, long height, int samples, int directory, boolean fProt)
	    {
	        Release();
	        m_sOrigin = xorigin;
	        m_tOrigin = yorigin;
	        m_Width = width;
	        m_Height = height;
	        m_Samples = samples;
	        m_Directory = directory;
	        m_fProtected = fProt;
	        m_pBufferData = AllocSegment( width, height, samples, m_fProtected );
	    }

	 public void	Init( long xorigin, long yorigin, long width, long height, int samples, int directory){
		 Init(xorigin,yorigin,width,height,samples,directory,false);
	 }

	 public void	Init( long xorigin, long yorigin, long width, long height, int samples){
		 Init(xorigin,yorigin,width,height,samples,0,false);
	 }

	 /** Release this reference to the cache.
	     */
	    public void	Release()
	    {
	        if ( m_pBufferData != null ) {
	        	FreeSegment( m_pBufferData, m_Width, m_Height, m_Samples );
//高速化
	        	//		        m_pBufferData.clear();
	        }
	        //高速化
	        //	        m_pBufferData.clear();
	        m_pBufferData = null;
	    }

	    /** Determine if the specified sample point and directory index is within this buffer segment.
	     * \param s Horizontal sample position.
	     * \param t Vertical sample position.
	     * \param directory TIFF directory index.
	     * \return Boolean indicating sample is within this buffer.
	     */
	    public boolean	IsValid( long s, long t, int directory)
	    {

	        return (
	                   (s >= m_sOrigin) &&
	                   (t >= m_tOrigin) &&
	                   (s < m_sOrigin + m_Width) &&
	                   (t < m_tOrigin + m_Height) &&
	                   directory == m_Directory );
	    }

	    public boolean	IsValid( long s, long t){
	    	return IsValid(s,t,0);
	    }

	    
	    /** Get a pointer to the data for this buffer segment.
	     */
	    //高速化
//	    public STLArrayList 	pBufferData()
//	    {
//	        return ( m_pBufferData );
//	    }
	    public Object[] 	pBufferData()
	    {
	        return ( m_pBufferData );
	    }
	    /** Get a pointer to the data for this buffer segment.
	     * 
	     */
//高速化
	    //	   public STLArrayList	pVoidBufferData()
//	    {
//	        return ( m_pBufferData );
//	    }
	   public Object[]	pVoidBufferData()
	    {
	        return ( m_pBufferData );
	    }
	    /** Get the size of a single element
	     */
	    public int	ElemSize()
	    {
//	        return( m_Samples * sizeof(TqUchar) );
	        return( m_Samples);
	    }
	    /** Get the type of the data in the buffer
	     */
	    public  EqBufferType	BufferType()
	    {
	        return( new EqBufferType(EqBufferType.BufferType_RGBA) );
	    }

	    /**
	     * メモリからテクスチャの色情報を取得する。 
	     * Get the float value at the specified pixel/element (0.0 --> 1.0)
	     */
	    public float GetValue(int x, int y, int sample)
	    {
	        int iv =(int)( y * ( m_Width * ElemSize() ));

	        int iu = x * ElemSize();
//	        return ( m_pBufferData.elementAt( iv + iu + sample ) / 255.0f ); 2006/01/18 128+処理を付加した
//高速化    return ( (m_pBufferData.get( iv + iu + sample )+128) / 255.0f );
//	        return (((Byte)m_pBufferData.get(iv+iu+sample)+128) / 255.0f);
	        return ((Byte)m_pBufferData[iv+iu+sample]+128)/255f;
	    }
	    /** Set the float value at the specified pixel/element (0.0 --> 1.0)
	     */
	   public  void	SetValue(int x, int y, int sample, float value)
	    {
	        int iv =(int)( y * ( m_Width * ElemSize() ));
	        int iu = x * ElemSize();
//	        m_pBufferData[ iv + iu + sample ] = static_cast<TqUchar>( value * 255.0f );
//高速化    m_pBufferData.add(iv + iu + sample,((byte)(value * 255.0f - 128/*byteのため2006/01/19*/)) );
//	        m_pBufferData.set(iv + iu + sample, ((byte)(value * 255.0f - 128/*byteのため2006/01/19*/)));
	        m_pBufferData[iv+iu+sample] = ((byte)(value * 255.0f - 128/*byteのため2006/01/19*/));
	    }
	    /** Get the origin of this buffer segment.
	     */
	    public long sOrigin()
	    {
	        return ( m_sOrigin );
	    }
	    /** Get the origin of this buffer segment.
	     */
	    public  long tOrigin()
	    {
	        return ( m_tOrigin );
	    }
	    /** Get the width of this buffer segment.
	     */
	    public long Width() 
	    {
	        return ( m_Width );
	    }
	    /** Get the height of this buffer segment.
	     */
	    public long Height() 
	    {
	        return ( m_Height );
	    }
	    /** Get the directory index of this buffer segment.
	     */
	    public int	Directory() 
	    {
	        return ( m_Directory );
	    }
	    /** Get the number of samples per element.
	     */
	    public int	Samples() 
	    {
	        return ( m_Samples );
	    }
	    /** Get the status of the protected flag
	     */
	    public boolean	 fProtected() 
	    {
	        return( m_fProtected );
	    }
	    /** Set this buffer as protected or not.
	     */
	    public void	SetfProtected( boolean fProt)
	    {
	        m_fProtected = fProt;
	    }
	    
	    public void SetfProtected(){
	    	SetfProtected(true);
	    }



		
		//下で利用する変数
		static int limit = -1;
		static int report = -1;
		static int megs = 10;
		/**
		 * テクスチャに利用するメモリ量を計算し、確保する。
		 * javaの場合は確保する必要がないため、STLVector<Byte>を返す。
		 * 
		 * @param width
		 * @param height
		 * @param samples
		 * @param fProt
		 * @return
		 *///高速化
//		public STLArrayList AllocSegment( long width, long height, int samples, boolean fProt ){
//			int demand =(int)( width * height * ElemSize());
//			
//			//limitを計算する
//			if(limit == -1){
//				final int[] poptMem = QGetRenderContextI().GetIntegerOption("limits","texturememory");
//				limit = RiGlobal.MEG1;
//				if(poptMem != null)
//					limit = poptMem[ 0 ] * 1024;
//			}
//			
//			//Textureの予想メモリ量を計算する
//			int more = QGetRenderContext().Stats().GetTextureMemory() + demand;
//			
//			//limitを超えた場合の処理を行う
//			if((more > limit) && !fProt){
//				//メモリが許容量を超えようとしている
//				//メモリキャッシュをクリアしたほうがよい
//				//必要とされるメモリを確保するためにはキャッシュをZAPする必要がある
//				//今からユーザに、リクエストする分のメモリを拡大しないければ
//				//ならないと警告をしよう。
//				
//				if(report != 0){
//					HimawariLogger.getLogger().warning("Exceeding allocated texture memory by "+
//							(more - limit) + "\n");
//				}
//				report = 0;
//				RiGlobal.m_critical = true;	
//				//デバッグコード　必ず消すこと
////				RiGlobal.m_critical = false;//デバグ
//
//			}
////デバッグコード			
////			#ifdef _DEBUG
////		    if ( ( more > MEG1 ) && ( ( more / ( 1024 * 1024 ) ) > megs ) )
////		    {
////		        std::cerr << debug << "Texturememory is more than " << megs << " megs" << std::endl;
////		        megs += 10;
////		    }
////		#endif
//			 
//		    QGetRenderContext().Stats().IncTextureMemory( demand );
////高速化	return new ArrayList<Byte>(demand);
//		    return new STLArrayList(dataClass,demand);
//		}
		public Object[] AllocSegment( long width, long height, int samples, boolean fProt ){
			int demand =(int)( width * height * ElemSize());
			
			//limitを計算する
			if(limit == -1){
				final int[] poptMem = QGetRenderContextI().GetIntegerOption("limits","texturememory");
				limit = RiGlobal.MEG1;
				if(poptMem != null)
					limit = poptMem[ 0 ] * 1024;
			}
			
			//Textureの予想メモリ量を計算する
			int more = QGetRenderContext().Stats().GetTextureMemory() + demand;
			
			//limitを超えた場合の処理を行う
			if((more > limit) && !fProt){
				//メモリが許容量を超えようとしている
				//メモリキャッシュをクリアしたほうがよい
				//必要とされるメモリを確保するためにはキャッシュをZAPする必要がある
				//今からユーザに、リクエストする分のメモリを拡大しないければ
				//ならないと警告をしよう。
				
				if(report != 0){
					HimawariLogger.getLogger().warning("Exceeding allocated texture memory by "+
							(more - limit) + "\n");
				}
				report = 0;
				RiGlobal.m_critical = true;	


			}
//デバッグコード			
//			#ifdef _DEBUG
//		    if ( ( more > MEG1 ) && ( ( more / ( 1024 * 1024 ) ) > megs ) )
//		    {
//		        std::cerr << debug << "Texturememory is more than " << megs << " megs" << std::endl;
//		        megs += 10;
//		    }
//		#endif
			 
		    QGetRenderContext().Stats().IncTextureMemory( demand );
//高速化	return new ArrayList<Byte>(demand);
		    return new Byte[demand];
		}
		
		//高速化
//		public STLArrayList AllocSegment( long width, long height, int samples){
//	    	return AllocSegment(width,height,samples,false);
//	    }
		
		public Object[] AllocSegment( long width, long height, int samples){
    	return AllocSegment(width,height,samples,false);
    }

//		public void	FreeSegment( STLArrayList pBufferData, long width, long height, int samples ){
//	    	long demand = width *height *samples;
//	    	QGetRenderContext().Stats().IncTextureMemory((int)-demand);
//	    }


		public void	FreeSegment( Object[] pBufferData, long width, long height, int samples ){
	    	long demand = width *height *samples;
	    	QGetRenderContext().Stats().IncTextureMemory((int)-demand);
	    }

}
