/*
$Id: ElementContainerMatrix.cc 2295 2011-08-10 02:57:13Z jisuzuki $
*/


#include "ElementContainerMatrix.hh"
////////////////////////////////////
ElementContainerMatrix::
ElementContainerMatrix()
{
}
////////////////////////////////////
ElementContainerMatrix::
ElementContainerMatrix( HeaderBase pheader )
  :  NeutronVector<ElementContainerArray,HeaderBase>( pheader )
     //  :: NeutronVector<ElementContainerArray,HeaderBase>( pheader )
{
}
////////////////////////////////////
ElementContainerMatrix::
ElementContainerMatrix( const ElementContainerMatrix &ob )
  :  NeutronVector<ElementContainerArray,HeaderBase>( ob )
     //  :: NeutronVector<ElementContainerArray,HeaderBase>( ob )
{
}
////////////////////////////////////
ElementContainerMatrix::
ElementContainerMatrix( const NeutronVector<ElementContainerArray, HeaderBase> &ob )
  :  NeutronVector<ElementContainerArray, HeaderBase>( ob )
     //  :: NeutronVector<ElementContainerArray, HeaderBase>( ob )
{
}
////////////////////////////////////
ElementContainer*
ElementContainerMatrix::
operator()( UInt4 Mindex, UInt4 Aindex )
{
  return PutPointer( Mindex ) -> PutPointer( Aindex );
}
////////////////////////////////////
std::vector<Double>*
ElementContainerMatrix::
operator()( UInt4 Mindex, UInt4 Aindex, UInt4 Cindex )
{
  return ( *( PutPointer( Mindex ) -> PutPointer( Aindex ) ) )( Cindex );
}
////////////////////////////////////
std::vector<Double>*
ElementContainerMatrix::
operator()( UInt4 Mindex, UInt4 Aindex, std::string Key )
{
  return ( *( PutPointer( Mindex ) -> PutPointer( Aindex ) ) )( Key );
}
////////////////////////////////////
std::vector<UInt4>
ElementContainerMatrix::
SaveToBinFile( std::string key, std::string FileName ){
  std::vector<UInt4> dimensions;
  dimensions.clear();
  std::vector<Double> dat;

  for( UInt4 i=0; i<PutSize(); i++ ){
    ElementContainerArray *TargetArray = PutPointer( i );

    dimensions.push_back( TargetArray->PutSize() );

    for( UInt4 j=0; j<TargetArray->PutSize(); j++ ){
      ElementContainer *Target = TargetArray->PutPointer( j );
      std::vector<Double> temp = Target -> Put( key );
      dimensions.push_back( (UInt4)(temp.size()) );

      for( UInt4 k=0; k<temp.size(); k++ ){
        dat.push_back( temp[ k ] );
      }
    }

  }

  NeutronWriteBinaryData<Double> *nw =
    new NeutronWriteBinaryData<Double>();
  nw -> Write( dat, FileName );
  delete nw;

  return dimensions;
}
////////////////////////////////////
PyObject *
ElementContainerMatrix::
SaveToBinFilePy( std::string key, std::string FileName ){
  std::vector<UInt4> r = SaveToBinFile( key, FileName );
  CppToPython *p = new CppToPython();
  PyObject *po = p->VectorUInt4ToList( r );
  delete p;
  return po;
}
////////////////////////////////////
void
ElementContainerMatrix::
ReadBinFile( std::string FileName,
             std::vector<UInt4> dimensions,
             std::string key ){

  NeutronReadBinaryData<Double> *nr =
    new NeutronReadBinaryData<Double>();
  std::vector<Double> dat = nr->ReadData( FileName );
  delete nr;



  UInt4 dim_counter = 0;
  std::vector< std::vector<UInt4> > dim;
  while( dim_counter < dimensions.size() ){

    std::vector<UInt4> Temp;
    UInt4 TempSize = dimensions[ dim_counter++ ];
    for( UInt4 i=0; i<TempSize; i++ ){
      Temp.push_back( dimensions[ dim_counter++ ] );
    }
    dim.push_back( Temp );
  }

  UInt4 counter = 0;

  for( UInt4 i=0; i<dim.size(); i++ ){
    std::vector<UInt4> ArraySize = dim[ i ];
    ElementContainerArray *eca =
      new ElementContainerArray();

    for( UInt4 j=0; j<ArraySize.size(); j++ ){
      ElementContainer *ec = new ElementContainer();

      UInt4 VecSize = (ArraySize)[j];
      std::vector<Double> temp;

      for( UInt4 k=0; k<VecSize; k++ ){
        temp.push_back( dat[ counter++ ] );
      }
      ec -> Add( key, temp );
      eca -> AddPointer( ec );
    }
    AddPointer( eca );
  }
}
////////////////////////////////////
void
ElementContainerMatrix::
ReadBinFile( std::string FileName, PyObject *dimensions,
             std::string key ){
  CppToPython *p = new CppToPython();
  std::vector<UInt4> di = p->ListToUInt4Vector( dimensions );
  delete p;
  ReadBinFile( FileName, di, key );
  return;
}
////////////////////////////////////
void
ElementContainerMatrix::
AppendErr( std::string Counts, std::string Error, Double ErrorValue ){
  for( UInt4 i=0; i<PutSize(); i++ ){
    PutPointer( i ) -> AppendErr( Counts, Error, ErrorValue );
  }
  return;
}
////////////////////////////////////
ElementContainerMatrix
ElementContainerMatrix::
Transpose(){
    ElementContainerArray ecaFirst;
    UInt4 numEca = PutSize();
    if (numEca == 0){
        return *this;
    }else{
        ecaFirst = Put(0);
    }
    UInt4 numEcInFirstEca = ecaFirst.PutSize();
    for (UInt4 i = 1; i < numEca; ++i){
        if ( numEcInFirstEca != Put(i).PutSize() ){
            return *this;
        }
    }
    ElementContainerMatrix result(PutHeader());
    ElementContainerArray* newEca = new ElementContainerArray[numEcInFirstEca];
    ElementContainerArray* eca;
    for (UInt4 i = 0; i < numEca; ++i){
        eca = PutPointer(i);
        for (UInt4 j = 0; j < numEcInFirstEca; ++j){
            newEca[j].Add(eca->Put(j));
        }
    }
    for (UInt4 i = 0; i < numEcInFirstEca; ++i){
        result.Add(newEca[i]);
    }
    delete[] newEca;
    return result;
}

////////////////////////////////////
////////////////////////////////////
ElementContainerMatrix
ElementContainerMatrix::
Mul( Double d ){
  ElementContainerMatrix result = (*this);
  UInt4 s = result.PutSize();
  for( UInt4 i=0; i<s; i++ ){
    result(i) -> MulMySelf( d );
  }
  return result;
}
////////////////////////////////////////////////////////
ElementContainerMatrix &ElementContainerMatrix::
MulMySelf( Double d ){
  UInt4 s = PutSize();
  for( UInt4 i=0; i<s; i++ ){
    PutPointer(i) -> MulMySelf( d );
  }
  return *this;
}
////////////////////////////////////////////////////////
ElementContainerMatrix
ElementContainerMatrix::
Mul( Double d, Double e ){
  ElementContainerMatrix result = (*this);
  UInt4 s = result.PutSize();
  for( UInt4 i=0; i<s; i++ ){
    result(i) -> MulMySelf( d, e );
  }
  return result;
}
////////////////////////////////////////////////////////
ElementContainerMatrix &ElementContainerMatrix::
MulMySelf( Double d, Double e ){
  UInt4 s = PutSize();
  for( UInt4 i=0; i<s; i++ ){
    PutPointer(i) -> MulMySelf( d, e );
  }
  return *this;
}
////////////////////////////////////////////////////////

////////////////////////////////////
ElementContainerMatrix
ElementContainerMatrix::
Plus( Double d ){
  ElementContainerMatrix result = (*this);
  UInt4 s = result.PutSize();
  for( UInt4 i=0; i<s; i++ ){
    result(i) -> PlusMySelf( d );
  }
  return result;
}
////////////////////////////////////////////////////////
ElementContainerMatrix &ElementContainerMatrix::
PlusMySelf( Double d ){
  UInt4 s = PutSize();
  for( UInt4 i=0; i<s; i++ ){
    PutPointer(i) -> PlusMySelf( d );
  }
  return *this;
}
////////////////////////////////////////////////////////
ElementContainerMatrix
ElementContainerMatrix::
Plus( Double d, Double e ){
  ElementContainerMatrix result = (*this);
  UInt4 s = result.PutSize();
  for( UInt4 i=0; i<s; i++ ){
    result(i) -> PlusMySelf( d, e );
  }
  return result;
}
////////////////////////////////////////////////////////
ElementContainerMatrix &ElementContainerMatrix::
PlusMySelf( Double d, Double e ){
  UInt4 s = PutSize();
  for( UInt4 i=0; i<s; i++ ){
    PutPointer(i) -> PlusMySelf( d, e );
  }
  return *this;
}

////////////////////////////////////
ElementContainerMatrix
ElementContainerMatrix::
Pow( Double d ){
  ElementContainerMatrix result = (*this);
  UInt4 s = result.PutSize();
  for( UInt4 i=0; i<s; i++ ){
    result(i) -> PowMySelf( d );
  }
  return result;
}
////////////////////////////////////////////////////////
ElementContainerMatrix &ElementContainerMatrix::
PowMySelf( Double d ){
  UInt4 s = PutSize();
  for( UInt4 i=0; i<s; i++ ){
    PutPointer(i) -> PowMySelf( d );
  }
  return *this;
}

////////////////////////////////////////////////////////
ElementContainerMatrix ElementContainerMatrix::
MergeWithWeight( ElementContainerMatrix &ecm ){

  ElementContainerMatrix r = ElementContainerMatrix( PutHeader() );
  for( UInt4 i=0; i<PutSize(); i++ ){
    r.Add( PutPointer(i)->MergeWithWeight( *( ecm(i) ) ) );
  }

  return r;
}
////////////////////////////////////////////////////////
