// ---------------------------------------------------------------------
//
// Copyright (C) 1999 - 2017 by the deal.II authors
//
// This file is part of the deal.II library.
//
// The deal.II library is free software; you can use it, redistribute
// it, and/or modify it under the terms of the GNU Lesser General
// Public License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// The full text of the license can be found in the file LICENSE at
// the top level of the deal.II distribution.
//
// ---------------------------------------------------------------------

#ifndef dealii_block_vector_templates_h
#define dealii_block_vector_templates_h


#include <deal.II/base/config.h>
#include <deal.II/lac/block_vector.h>
#include <deal.II/lac/trilinos_parallel_block_vector.h>
#include <cmath>
#include <algorithm>

DEAL_II_NAMESPACE_OPEN

template <typename Number>
BlockVector<Number>::BlockVector (const unsigned int n_blocks,
                                  const size_type block_size)
{
  reinit (n_blocks, block_size);
}



template <typename Number>
BlockVector<Number>::BlockVector (const std::vector<size_type> &block_sizes)
{
  reinit (block_sizes, false);
}


template <typename Number>
BlockVector<Number>::BlockVector (const BlockIndices &n)
{
  reinit (n, false);
}


template <typename Number>
BlockVector<Number>::BlockVector (const BlockVector<Number> &v)
  :
  BlockVectorBase<Vector<Number> > ()
{
  this->components.resize (v.n_blocks());
  this->block_indices = v.block_indices;

  for (size_type i=0; i<this->n_blocks(); ++i)
    this->components[i] = v.components[i];
}



template <typename Number>
template <typename OtherNumber>
BlockVector<Number>::BlockVector (const BlockVector<OtherNumber> &v)
{
  reinit (v, true);
  *this = v;
}



#ifdef DEAL_II_WITH_TRILINOS

template <typename Number>
BlockVector<Number>::BlockVector (const TrilinosWrappers::MPI::BlockVector &v)
{
  this->block_indices = v.get_block_indices();
  this->components.resize(this->n_blocks());

  for (size_type i=0; i<this->n_blocks(); ++i)
    this->components[i] = v.block(i);

  BaseClass::collect_sizes();
}

#endif


template <typename Number>
void BlockVector<Number>::reinit (const unsigned int n_blocks,
                                  const size_type    block_size,
                                  const bool         omit_zeroing_entries)
{
  std::vector<size_type> block_sizes(n_blocks, block_size);
  reinit(block_sizes, omit_zeroing_entries);
}


template <typename Number>
void BlockVector<Number>::reinit (const std::vector<size_type> &block_sizes,
                                  const bool                    omit_zeroing_entries)
{
  this->block_indices.reinit (block_sizes);
  if (this->components.size() != this->n_blocks())
    this->components.resize(this->n_blocks());

  for (size_type i=0; i<this->n_blocks(); ++i)
    this->components[i].reinit(block_sizes[i], omit_zeroing_entries);
}


template <typename Number>
void BlockVector<Number>::reinit (
  const BlockIndices &n,
  const bool omit_zeroing_entries)
{
  this->block_indices = n;
  if (this->components.size() != this->n_blocks())
    this->components.resize(this->n_blocks());

  for (size_type i=0; i<this->n_blocks(); ++i)
    this->components[i].reinit(n.block_size(i), omit_zeroing_entries);
}


template <typename Number>
template <typename Number2>
void BlockVector<Number>::reinit (const BlockVector<Number2> &v,
                                  const bool omit_zeroing_entries)
{
  this->block_indices = v.get_block_indices();
  if (this->components.size() != this->n_blocks())
    this->components.resize(this->n_blocks());

  for (size_type i=0; i<this->n_blocks(); ++i)
    this->block(i).reinit(v.block(i), omit_zeroing_entries);
}



#ifdef DEAL_II_WITH_TRILINOS
template <typename Number>
inline
BlockVector<Number> &
BlockVector<Number>::operator= (const TrilinosWrappers::MPI::BlockVector &v)
{
  BaseClass::operator= (v);
  return *this;
}
#endif


template <typename Number>
void BlockVector<Number>::swap (BlockVector<Number> &v)
{
  std::swap(this->components, v.components);

  dealii::swap (this->block_indices, v.block_indices);
}



template <typename Number>
void BlockVector<Number>::print (std::ostream       &out,
                                 const unsigned int  precision,
                                 const bool          scientific,
                                 const bool          across) const
{
  for (size_type i=0; i<this->n_blocks(); ++i)
    {
      if (across)
        out << 'C' << i << ':';
      else
        out << "Component " << i << std::endl;
      this->components[i].print(out, precision, scientific, across);
    }
}



template <typename Number>
void BlockVector<Number>::block_write (std::ostream &out) const
{
  for (size_type i=0; i<this->n_blocks(); ++i)
    this->components[i].block_write(out);
}



template <typename Number>
void BlockVector<Number>::block_read (std::istream &in)
{
  for (size_type i=0; i<this->n_blocks(); ++i)
    this->components[i].block_read(in);
}



DEAL_II_NAMESPACE_CLOSE

#endif
