/* ImLib3D
 * Copyright (c) 2001, ULP-IPB Strasbourg.
 *
 * This program 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 program 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 program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
/*! \file  SparseImage3D.hxx  */

#ifndef _SparseImage3D_hxx
#define _SparseImage3D_hxx

#include<ImLib3D/SparseImage3D.hpp>
#include<ImLib3D/XMLTools.hpp>

template<class Im3DValue>
void 
SparseImage3D<Im3DValue>::Write(ImLib3DFile *file,XMLNode *parentNode,XMLNode *node) const
{
	node=CreateWriteNode(file,parentNode,node);
	// **** Optionally add unset image properties ***
	// set image type (Image3Df, Field3D etc....) 
	if(!file->HasProperty(node,"Type")){node->add_property("Type",GetTypeName());}

	// store sparseStructure
	XMLNode *sNode=node->add_child("sparseStructure");
	if(!shareSparseStructureFile){sparseStructure->Write(file,sNode);}
	else
	{
		if(sparseStructure->Name()=="")
		{
			ThrowError("SparseImage3D<Im3DValue>::Write sparseStructure file is shared, but has sparseStructure has no name");
		}
		sNode->add_property("sparseStructureFile",sparseStructure->Name());
	}
	// store Data (underlying image) information
	XMLNode *dataN=node->add_child("ImageData");
	file->AddBinaryNode(dataN,sparseStructure->ValSize()*sizeof(value_type));
	file->template BinaryWrite<Im3DValue,Im3DValue *>(imageData,imageDataEnd);
	// write parents data (image size and properties)
	Image3D::Write(file,NULL,node);
}
template<class Im3DValue>
void 
SparseImage3D<Im3DValue>::Read(ImLib3DFile *file,XMLNode *parentNode,XMLNode *node)
{
	node=CreateReadNode(file,parentNode,node);
	Image3D::Read(file,NULL,node);
	//type checking
	string type=file->GetProperty(node,"Type");
	if(type!=GetTypeName()){ThrowError("ReadFromXMLTree: Expected type:\"%s\" found type:\"%s\"",GetTypeName(),type);}
	// store sparseStructure
	XMLNode *sNode=file->GetChild(node,"sparseStructure");
	string sparseStructureFile=::Property(sNode,"sparseStructureFile");
	// if sparseStructureFile file is not shared just get it from this node
	if(sparseStructureFile==""){shareSparseStructureFile=false;sparseStructure=SparseStructure3D::Create(file,sNode);}
	else
	{
		shareSparseStructureFile=true;
		// check if already in mem
		sparseStructure=SparseStructure3D::Find(sparseStructureFile);
		if(!sparseStructure)
		{// not yet loaded, must create
			sparseStructure=SparseStructure3D::Create(sparseStructureFile);
		}
		// in both cases tell sparseStructure that somedy else is using it
		sparseStructure->Reference(this);
	}
	//image data
	XMLNode *dataN=file->GetChild(node,"ImageData");
	file->ReadBinaryNode(dataN);
	Allocate();
	file->template BinaryRead<Im3DValue,Im3DValue *>(imageData,imageDataEnd);
	if(!file->CheckBinaryReadComplete())
	{ThrowError("XMLBinaryFile::BinaryRead bad read size (maybe wrong image type?) ");}
}

template<class Im3DValue>
void 
SparseImage3D<Im3DValue>::Allocate()
{
	if(imageData){delete [] imageData;}
	imageData=new Im3DValue[sparseStructure->ValSize()];
	imageDataEnd=imageData+sparseStructure->ValSize();
}

// *******************************************************
template<class Im3DValue>
void 
SparseImage3D<Im3DValue>::Resize(const Size3D &newSize)
{
	if(Size()!=newSize && Size()!=Size3D(0,0,0)){ThrowError("SparseImage3D<Im3DValue>::Resize not allowed");}
	Image3D::Resize(newSize);
}


// *******************************************************
template<class Im3DValue>
SparseImage3D<Im3DValue>& 
SparseImage3D<Im3DValue>::operator=(const SparseImage3D & other)
{
	if (this == &other){return *this;}
	sparseStructure->Dereference(this);
	SetSparseStructure(other.sparseStructure);
	Image3D::operator=(other);
	Allocate();
	memcpy((void *)imageData,(void *)other.imageData,sizeof(Im3DValue)*sparseStructure->ValSize());
	return *this;
}


// *******************************************************
template<class Im3DValue>
bool 
SparseImage3D<Im3DValue>::operator==(const SparseImage3D & other) const
{
	if(other.Size()!=Size()){return false;}
	if(!equal(begin(),end(),other.begin())){return false;}	
	if(!(properties==other.properties)){return false;}
	
	return true;
}



// *******************************************************
template<class Im3DValue>
SparseImage3D<Im3DValue>::~SparseImage3D()
{
	if(sparseStructure){sparseStructure->Dereference(this);}
	else
	{printf("deleting invalidated SparseImage3D\n");}
	delete [] imageData;
}

// *******************************************************
//  SparseImage3D<Im3DValue>::SparseImage3D(int _width, int _height, int _depth) : 
//  	Image3D(_width,_height,_depth)
//  {
//  	Resize(Size3D(_width,_height,_depth));
//  }
// *******************************************************
template<class Im3DValue>
SparseImage3D<Im3DValue>::SparseImage3D():
	SparseImage3DBase(),
	imageData(NULL),imageDataEnd(NULL)
{
	InitZero();
}

// *******************************************************
template<class Im3DValue>
SparseImage3D<Im3DValue>::SparseImage3D(const SparseStructure3D *_sparseStructure):
	SparseImage3DBase(_sparseStructure),
	imageData(NULL),imageDataEnd(NULL)
{
	InitZero();
	Allocate();
}

// *******************************************************
template<class Im3DValue>
SparseImage3D<Im3DValue>::SparseImage3D(const SparseImage3D & other) :
	SparseImage3DBase(other),
	imageData(NULL),imageDataEnd(NULL)
{
	InitZero();
	Allocate();
	memcpy((void *)imageData,(void *)other.imageData,sizeof(Im3DValue)*sparseStructure->ValSize());
}


#endif // _SparseImage3D_hxx
