/*
 *
 * Copyright (c) 2003 Kresimir Fresl, Toon Knapen and Karl Meerbergen
 *
 * Distributed under the Boost Software License, Version 1.0.
 * (See accompanying file LICENSE_1_0.txt or copy at
 * http://www.boost.org/LICENSE_1_0.txt)
 *
 * KF acknowledges the support of the Faculty of Civil Engineering,
 * University of Zagreb, Croatia.
 *
 */

#ifndef BOOST_NUMERIC_BINDINGS_TRAITS_UBLAS_SPARSE_MATRIX_H
#define BOOST_NUMERIC_BINDINGS_TRAITS_UBLAS_SPARSE_MATRIX_H

#include <cstddef>
#ifndef BOOST_UBLAS_HAVE_BINDINGS
#  include <boost/numeric/ublas/matrix_sparse.hpp>
#endif
#include <Core/Utils/numeric/bindings/traits/sparse_traits.hpp>
#include <Core/Utils/numeric/bindings/traits/detail/ublas_ordering.hpp>
#include <algorithm>


namespace boost { namespace numeric { namespace bindings { namespace traits {

  // ublas::compressed_matrix<>
  template <typename T, typename F, std::size_t IB, typename IA, typename TA,
            typename MType
            >
  struct sparse_matrix_detail_traits<
    boost::numeric::ublas::compressed_matrix<T,F,IB,IA,TA>,
    MType
  >
  {
#ifndef BOOST_NUMERIC_BINDINGS_NO_SANITY_CHECK
    BOOST_STATIC_ASSERT(
      (boost::is_same<
         boost::numeric::ublas::compressed_matrix<T,F,IB,IA,TA>,
         typename boost::remove_const<MType>::type
       >::value)
    );
#endif

    typedef
      boost::numeric::ublas::compressed_matrix<T,F,IB,IA,TA> identifier_type;
    typedef MType matrix_type;

    typedef general_t matrix_structure;
    typedef compressed_t storage_format;
    typedef typename detail::ublas_ordering<
      typename F::orientation_category
    >::type ordering_type;
    typedef F layout_type;

    typedef T value_type;

  private:
    typedef typename detail::generate_const<MType,TA>::type val_array_t;
    typedef typename detail::generate_const<MType,IA>::type idx_array_t;

  public:
    typedef typename vector_traits<val_array_t>::pointer value_pointer;
    typedef typename vector_traits<idx_array_t>::pointer index_pointer;

    BOOST_STATIC_CONSTANT (std::size_t, index_base = IB);

    static index_pointer index1_storage (matrix_type& cm) {
      //assert (cm.filled1() == layout_type::num_rows (cm.size1(), cm.size2()) + 1);
      return vector_traits<idx_array_t>::storage (cm.index1_data());
    }
    static index_pointer index2_storage (matrix_type& cm) {
      return vector_traits<idx_array_t>::storage (cm.index2_data());
    }
    static value_pointer value_storage (matrix_type& cm) {
      return vector_traits<val_array_t>::storage (cm.value_data());
    }

    static std::ptrdiff_t num_rows (matrix_type& cm) { return cm.size1(); }
    static std::ptrdiff_t num_columns (matrix_type& cm) { return cm.size2(); }
    static std::ptrdiff_t num_nonzeros (matrix_type& cm) {
      return cm.nnz();
      // Joerg, this isn't very intuitive :o(
      // return cm.non_zeros();
    }
  };


  // ublas::coordinate_matrix<>
  template <typename T, typename F, std::size_t IB, typename IA, typename TA,
            typename MType
            >
  struct sparse_matrix_detail_traits<
    boost::numeric::ublas::coordinate_matrix<T,F,IB,IA,TA>,
    MType
  >
  {
#ifndef BOOST_NUMERIC_BINDINGS_NO_SANITY_CHECK
    BOOST_STATIC_ASSERT(
      (boost::is_same<
         boost::numeric::ublas::coordinate_matrix<T,F,IB,IA,TA>,
         typename boost::remove_const<MType>::type
       >::value)
    );
#endif

    typedef
      boost::numeric::ublas::coordinate_matrix<T,F,IB,IA,TA> identifier_type;
    typedef MType matrix_type;

    typedef general_t matrix_structure;
    typedef coordinate_t storage_format;
    typedef typename detail::ublas_ordering<
      typename F::orientation_category
    >::type ordering_type;

    typedef T value_type;

  private:
    typedef typename detail::generate_const<MType,TA>::type val_array_t;
    typedef typename detail::generate_const<MType,IA>::type idx_array_t;

  public:
    typedef typename vector_traits<val_array_t>::pointer value_pointer;
    typedef typename vector_traits<idx_array_t>::pointer index_pointer;

    BOOST_STATIC_CONSTANT (std::size_t, index_base = IB);

    static index_pointer index1_storage (matrix_type& cm) {
      return vector_traits<idx_array_t>::storage (cm.index1_data());
    }
    static index_pointer index2_storage (matrix_type& cm) {
      return vector_traits<idx_array_t>::storage (cm.index2_data());
    }
    static value_pointer value_storage (matrix_type& cm) {
      return vector_traits<val_array_t>::storage (cm.value_data());
    }

    static int num_rows (matrix_type& cm) { return cm.size1(); }
    static int num_columns (matrix_type& cm) { return cm.size2(); }
    static int num_nonzeros (matrix_type& cm) {
      return cm.nnz();
      // Joerg, this isn't very intuitive :o(
      // return cm.non_zeros();
    }
  };

}}}}

#endif // BOOST_NUMERIC_BINDINGS_TRAITS_UBLAS_SPARSE_MATRIX_H
