//=============================================================================
Epetra_IntSerialDenseMatrix& Epetra_IntSerialDenseMatrix::operator = (const Epetra_IntSerialDenseMatrix& Source) {
  if(this == &Source)
		return(*this); // Special case of source same as target
	if((CV_ == View) && (Source.CV_ == View) && (A_ == Source.A_))
		return(*this); // Special case of both are views to same data.

	if(std::strcmp(Label(), Source.Label()) != 0)
		throw ReportError("operator= type mismatch (lhs = " + string(Label()) + 
											", rhs = " + string(Source.Label()) + ").", -5);
	
	if(Source.CV_ == View) {
		if(CV_ == Copy) { // C->V only
			CleanupData();
			CV_ = View;
		}
		M_ = Source.M_; // C->V and V->V
		N_ = Source.N_;
		LDA_ = Source.LDA_;
		A_ = Source.A_;
	}
	else {
		if(CV_ == View) { // V->C
			CV_ = Copy;
			M_ = Source.M_;
			N_ = Source.N_;
			LDA_ = Source.M_;
			const int newsize = LDA_ * N_;
			if(newsize > 0) {
				A_ = new int[newsize];
				A_Copied_ = true;
			}
			else {
				A_ = 0;
				A_Copied_ = false;
			}
		}
		else { // C->C
			if((Source.M_ <= LDA_) && (Source.N_ == N_)) { // we don't need to reallocate
				M_ = Source.M_;
				N_ = Source.N_;
			}
			else { // we need to allocate more space (or less space)
				CleanupData();
				M_ = Source.M_;
				N_ = Source.N_;
				LDA_ = Source.M_;
				const int newsize = LDA_ * N_;
				if(newsize > 0) {
					A_ = new int[newsize];
					A_Copied_ = true;
				}
			}
		}
		CopyMat(Source.A_, Source.LDA_, M_, N_, A_, LDA_); // V->C and C->C
	}
	
  return(*this);
}
//=============================================================================
int Epetra_IntSerialDenseMatrix::Reshape(int NumRows, int NumCols) {
	if(NumRows < 0 || NumCols < 0)
		return(-1);

	int* A_tmp = 0;
	const int newsize = NumRows * NumCols;

	if(newsize > 0) {
		// Allocate space for new matrix
		A_tmp = new int[newsize];
		for(int k = 0; k < newsize; k++) 
			A_tmp[k] = 0; // Zero out values
		int M_tmp = EPETRA_MIN(M_, NumRows);
		int N_tmp = EPETRA_MIN(N_, NumCols);
		if(A_ != 0) 
			CopyMat(A_, LDA_, M_tmp, N_tmp, A_tmp, NumRows); // Copy principal submatrix of A to new A
	}
  
  CleanupData(); // Get rid of anything that might be already allocated  
  M_ = NumRows;
  N_ = NumCols;
  LDA_ = M_;
  A_ = A_tmp; // Set pointer to new A
  A_Copied_ = (newsize>0);
  return(0);
}
//=============================================================================
Epetra_SerialComm& Epetra_SerialComm::operator= (const Epetra_SerialComm & Comm) {
	if((this != &Comm) && (SerialCommData_ != Comm.SerialCommData_)) {
		CleanupData();
		SerialCommData_ = Comm.SerialCommData_;
		SerialCommData_->IncrementReferenceCount();
	}
	return(*this);
}
//=============================================================================
Epetra_BlockMap & Epetra_BlockMap::operator= (const Epetra_BlockMap & map)
{
  if((this != &map) && (BlockMapData_ != map.BlockMapData_)) {
    CleanupData();
    BlockMapData_ = map.BlockMapData_;
    BlockMapData_->IncrementReferenceCount();
  }

  return(*this);
}
//==============================================================================
void Epetra_BlockMap::CheckValidNGE(long long numGlobalElements) {
  // Check to see if user's value for numGlobalElements is either -1 
  // (in which case we use our computed value) or matches ours.
  if ((numGlobalElements != -1) && (numGlobalElements != BlockMapData_->NumGlobalElements_)) {
    long long BmdNumGlobalElements = BlockMapData_->NumGlobalElements_;
    CleanupData();
    throw ReportError("Invalid NumGlobalElements.  NumGlobalElements = " + toString(numGlobalElements) + 
          ".  Should equal " + toString(BmdNumGlobalElements) + 
          ", or be set to -1 to compute automatically", -4);
  }
}
//=============================================================================
int Epetra_IntSerialDenseMatrix::MakeViewOf(const Epetra_IntSerialDenseMatrix& Source) {
	if(std::strcmp(Label(), Source.Label()) != 0)
		return(-1);

	if(CV_ == Copy) {
		CleanupData();
		CV_ = View;
	}
	M_ = Source.M_;
	N_ = Source.N_;
	LDA_ = Source.LDA_;
	A_ = Source.A_;

	return(0);
}
//=============================================================================
int Epetra_IntSerialDenseMatrix::Shape(int NumRows, int NumCols) {
	if(NumRows < 0 || NumCols < 0)
		return(-1);

  CleanupData(); // Get rid of anything that might be already allocated
  M_ = NumRows;
  N_ = NumCols;
  LDA_ = M_;
	const int newsize = LDA_ * N_;
	if(newsize > 0) {
		A_ = new int[newsize];
#ifdef Epetra_HAVE_OMP
#pragma omp parallel for
#endif
		for(int k = 0; k < newsize; k++)
			A_[k] = 0; // Zero out values
		A_Copied_ = true;
	}

  return(0);
}
//=============================================================================
Epetra_IntSerialDenseMatrix::~Epetra_IntSerialDenseMatrix()
{
  CleanupData();
}
//=============================================================================
Epetra_SerialComm::~Epetra_SerialComm()  {
	CleanupData();
}
//=============================================================================
Epetra_LongLongSerialDenseMatrix::~Epetra_LongLongSerialDenseMatrix()
{
  CleanupData();
}
//==============================================================================
Epetra_BlockMap::~Epetra_BlockMap()  {
  CleanupData();
}
//=============================================================================
Epetra_MpiComm::~Epetra_MpiComm()  {
	CleanupData();
}