//     Persistence manager for template numerical arrays
//               R. Ansari, C.Magneville   03/2000

#include "pexceptions.h"
#include "fiondblock.h"
#include "fiospsqmtx.h"
#include "datatype.h"
#include <typeinfo>


//----------------------------------------------------------------------
/*!
  \class SOPHYA::FIO_SpecialSquareMatrix
  \ingroup TArray

  \brief Manager class the PPF I/O (SOPHYA persistence) of SpecialSquareMatrix<T> objects.
 
 */
///////////////////////////////////////////////////////////

namespace SOPHYA {

//! Default constructor
template <class T>
FIO_SpecialSquareMatrix<T>::FIO_SpecialSquareMatrix()
{
  dobj=NULL;
  ownobj=false;
}


//! Constructor from the file \b filename - Reads the SpecialSquareMatrix object from the specified file.
template <class T>
FIO_SpecialSquareMatrix<T>::FIO_SpecialSquareMatrix(string const & filename) 
{
  dobj=NULL;
  ownobj=false;
  Read(filename);
}

//! Constructor from the SpecialSquareMatrix \b obj
template <class T>
FIO_SpecialSquareMatrix<T>::FIO_SpecialSquareMatrix(const SpecialSquareMatrix<T> & obj) 
{ 
  const SymmetricMatrix<T>* sym = dynamic_cast< const SymmetricMatrix<T> * >(&obj);
  if (sym != NULL) dobj = new SymmetricMatrix<T>(*sym, true); 
  else {
    const LowerTriangularMatrix<T>* trn = dynamic_cast< const LowerTriangularMatrix<T> * >(&obj);
    if (trn != NULL)  dobj = new LowerTriangularMatrix<T>(*trn, true);
    else {
      const DiagonalMatrix<T>* diag = dynamic_cast< const DiagonalMatrix<T> * >(&obj);
      if (diag != NULL)  dobj = new DiagonalMatrix<T>(*diag, true);
      else throw TypeMismatchExc("FIO_SpecialSquareMatrix<T>::FIO_SpecialSquareMatrix(obj) Not a TriangularMatrix<T> / DiagonalMatrix<T> / SymmetricMatrix<T> ");
    }
  }
  ownobj=true; 
}

//! Connect with a SpecialSquareMatrix \b obj
template <class T>
FIO_SpecialSquareMatrix<T>::FIO_SpecialSquareMatrix(SpecialSquareMatrix<T> * obj) 
{ 
  dobj = obj;
  ownobj=false; 
}

//! destructor
template <class T>
FIO_SpecialSquareMatrix<T>::~FIO_SpecialSquareMatrix()
{
  if (ownobj && dobj) delete dobj;
}

//! Return the pointer to the connected SpecialSquareMatrix<T> object
template <class T>
AnyDataObj* FIO_SpecialSquareMatrix<T>::DataObj()
{
  return(dobj);
}

//! Connect SpecialSquareMatrix \b o
template <class T>
void FIO_SpecialSquareMatrix<T>::SetDataObj(AnyDataObj & o)
{
  SpecialSquareMatrix<T> * po = dynamic_cast< SpecialSquareMatrix<T> * >(&o);
  if (po == NULL) {
    char buff[160];
    sprintf(buff,"FIO_SpecialSquareMatrix<%s>::SetDataObj(%s) - Object type  error ! ",
	    DataTypeInfo<T>::getTypeName().c_str(), typeid(o).name());
    throw TypeMismatchExc(PExcLongMessage(buff));    
  }
  if (ownobj && dobj) delete dobj;
  dobj = po; ownobj = false;
} 

//! Reads in the SpecialSquareMatrix<T> object from the PPF input stream \b is
template <class T>
void FIO_SpecialSquareMatrix<T>::ReadSelf(PInPersist& is)
{
// On lit les 4 premiers uint_4
//  0: Numero de version,  1 : MtxType,  2 != 0 , has Info, 3 : Reserved
  uint_4 itab[4];
  is.Get(itab,4);

  if (dobj == NULL)  { 
    if (itab[1] == (uint_4)C_DiagonalMatrix)  dobj = new DiagonalMatrix<T>;
    else if (itab[1] == (uint_4)C_LowerTriangularMatrix)  dobj = new LowerTriangularMatrix<T>;
    else if (itab[1] == (uint_4)C_SymmetricMatrix)  dobj = new SymmetricMatrix<T>;
    else throw TypeMismatchExc("FIO_SpecialSquareMatrix<T>::ReadSelf() bad matrix type in file");
  }
  else {
    if ((uint_4)dobj->MtxType() != itab[1]) {
      // cout << " BUG*** dobj->MtxType()=" << (uint_4)(dobj->MtxType()) << " itab[1]=" << itab[1] << endl;
      throw TypeMismatchExc("FIO_SpecialSquareMatrix<T>::ReadSelf() matrix type dobj <> in file ");
    }
  }

// On lit les tailles, etc ...

// Tous les sa_size_t sont ecrit/lu en int_8 afin de maintenir la compatibilite  
// -- 0: rowSize
  int_8 tmpi8s[3];

  is.Get(tmpi8s, 3);
  dobj->SetSize(tmpi8s[0]);

// On lit le datablock
  is >> dobj->DataBlock();
// On lit le DVList info si necessaire
  if (itab[2] != 0)  is >> dobj->Info();  
}

//! Writes the SpecialSquareMatrix<T> object to the output PPF  stream \b os
template <class T>
void FIO_SpecialSquareMatrix<T>::WriteSelf(POutPersist& os) const
{
  if (dobj == NULL)   return;
//  On ecrit 3 uint_4 .... 
//  0: Numero de version,  1 : reserved  2 != 0 , has Info
  uint_4 itab[4];
  itab[0] = 1;  // Numero de version a 1 - fev 2009
  itab[1] = (uint_4)dobj->MtxType();  // Type de matrice : Diagonal, Triangular, Symmetric ...
  // cout << " *** DBG** WriteSelf() dobj->MtxType()= " << itab[1] << endl;
  itab[2] = (dobj->mInfo != NULL) ? 1 : 0;
  itab[3] = 0;  // Reserved
  os.Put(itab,4);

// On ecrit les tailles, etc ...
// Tous les sa_size_t sont ecrit en int_8 afin de pouvoir etre ecrit/relu
// entre version du programme utilisant int_4 OU int_8 pour sa_size_t 
  int_8 tmpi8s[3];
  tmpi8s[0] = dobj->NRows();
  tmpi8s[1] = tmpi8s[2] = 0;
  os.Put(tmpi8s, 3);
  // On ecrit le datablock
  os << dobj->DataBlock();
// On ecrit le DVList info si necessaire
  if (itab[2] != 0)  os << dobj->Info();
}



///////////////////////////////////////////////////////////////
#ifdef __CXX_PRAGMA_TEMPLATES__
// Instances des delegues FileIO (PPersist)
#pragma define_template FIO_SpecialSquareMatrix<uint_1>
#pragma define_template FIO_SpecialSquareMatrix<uint_2>
#pragma define_template FIO_SpecialSquareMatrix<uint_4>
#pragma define_template FIO_SpecialSquareMatrix<uint_8>
#pragma define_template FIO_SpecialSquareMatrix<int_1>
#pragma define_template FIO_SpecialSquareMatrix<int_2>
#pragma define_template FIO_SpecialSquareMatrix<int_4>
#pragma define_template FIO_SpecialSquareMatrix<int_8>
#pragma define_template FIO_SpecialSquareMatrix<r_4>
#pragma define_template FIO_SpecialSquareMatrix<r_8>
#pragma define_template FIO_SpecialSquareMatrix< complex<r_4> >
#pragma define_template FIO_SpecialSquareMatrix< complex<r_8> >
#ifdef SO_LDBLE128
#pragma define_template FIO_SpecialSquareMatrix<r_16>
#pragma define_template FIO_SpecialSquareMatrix< complex<r_16> >
#endif
#endif

#if defined(ANSI_TEMPLATES) || defined(GNU_TEMPLATES)
template class FIO_SpecialSquareMatrix<uint_1>;
template class FIO_SpecialSquareMatrix<uint_2>;
template class FIO_SpecialSquareMatrix<uint_4>;
template class FIO_SpecialSquareMatrix<uint_8>;
template class FIO_SpecialSquareMatrix<int_1>;
template class FIO_SpecialSquareMatrix<int_2>;
template class FIO_SpecialSquareMatrix<int_4>;
template class FIO_SpecialSquareMatrix<int_8>;
template class FIO_SpecialSquareMatrix<r_4>;
template class FIO_SpecialSquareMatrix<r_8>;
template class FIO_SpecialSquareMatrix< complex<r_4> >;
template class FIO_SpecialSquareMatrix< complex<r_8> >;
#ifdef SO_LDBLE128
template class FIO_SpecialSquareMatrix<r_16>;
template class FIO_SpecialSquareMatrix< complex<r_16> >;
#endif
#endif

} // Fin de namespace SOPHYA 
