#include "cubic_monomial_bases.h"
#include <cassert>

template <
  typename DerivedC,
  typename DerivedM,
  typename DerivedD,
  typename DerivedB>
IGL_INLINE void igl::cubic_monomial_bases(
  const Eigen::MatrixBase<DerivedC>& C,
  Eigen::PlainObjectBase<DerivedM>& M,
  Eigen::PlainObjectBase<DerivedD>& D,
  Eigen::PlainObjectBase<DerivedB>& B)
{
  // static assert that C has 4 rows or Dynamic
  static_assert(
    DerivedC::RowsAtCompileTime == 4 ||
    DerivedC::RowsAtCompileTime == Eigen::Dynamic,
    "C must have 4 rows.");
  // runtime assert that C has 4 rows
  assert(C.rows() == 4 && "C must have 4 rows.");
  const auto C0 = C.row(0);
  const auto C1 = C.row(1);
  const auto C2 = C.row(2);
  const auto C3 = C.row(3);
  // monomial coefficients for C(t)
  M.resize(4,C.cols());
  M <<
    C.row(0).eval(),
    3 * (C1 - C0),
    3 * (C0 - 2 * C1 + C2),
    C3 - C0 + 3 * (C1 - C2);
  // Monomial coefficients for dC/dt
  D.resize(3,C.cols());
  D << M.row(1),
     2 * M.row(2),
     3 * M.row(3);
  // Should work for row and column vectors
  B.resize(6);
  B.setConstant(0);
  for (int i = 0; i < 3; ++i)
  {
    for (int j = 0; j < 4; ++j)
    {
      B(i + j) += D.row(i).dot(M.row(j));
    }
  }
}

#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template void igl::cubic_monomial_bases<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 4, -1, 0, 4, -1>, Eigen::Matrix<double, 3, -1, 0, 3, -1>, Eigen::Matrix<double, 1, 6, 1, 1, 6>>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1>> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 4, -1, 0, 4, -1>>&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, -1, 0, 3, -1>>&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 6, 1, 1, 6>>&);
// generated by autoexplicit.sh
template void igl::cubic_monomial_bases<Eigen::Matrix<double, 4, -1, 0, 4, -1>, Eigen::Matrix<double, 4, -1, 0, 4, -1>, Eigen::Matrix<double, 3, -1, 0, 3, -1>, Eigen::Matrix<double, 6, 1, 0, 6, 1>>(Eigen::MatrixBase<Eigen::Matrix<double, 4, -1, 0, 4, -1>> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 4, -1, 0, 4, -1>>&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, -1, 0, 3, -1>>&, Eigen::PlainObjectBase<Eigen::Matrix<double, 6, 1, 0, 6, 1>>&);
// generated by autoexplicit.sh
template void igl::cubic_monomial_bases<Eigen::Matrix<double, 4, -1, 0, 4, -1>, Eigen::Matrix<double, 4, -1, 0, 4, -1>, Eigen::Matrix<double, 3, -1, 0, 3, -1>, Eigen::Matrix<double, 1, 6, 1, 1, 6>>(Eigen::MatrixBase<Eigen::Matrix<double, 4, -1, 0, 4, -1>> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 4, -1, 0, 4, -1>>&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, -1, 0, 3, -1>>&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 6, 1, 1, 6>>&);
#endif
