// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include "main.h"


template<int M1, int M2, int N1, int N2>
void test_blocks()
{
  Matrix<int, M1+M2, N1+N2> m_fixed;
  MatrixXi m_dynamic(M1+M2, N1+N2);

  Matrix<int, M1, N1> mat11; mat11.setRandom();
  Matrix<int, M1, N2> mat12; mat12.setRandom();
  Matrix<int, M2, N1> mat21; mat21.setRandom();
  Matrix<int, M2, N2> mat22; mat22.setRandom();

  MatrixXi matx11 = mat11, matx12 = mat12, matx21 = mat21, matx22 = mat22;

  {
    VERIFY_IS_EQUAL((m_fixed << mat11, mat12, mat21, matx22).finished(), (m_dynamic << mat11, matx12, mat21, matx22).finished());
    VERIFY_IS_EQUAL((m_fixed.template topLeftCorner<M1,N1>()), mat11);
    VERIFY_IS_EQUAL((m_fixed.template topRightCorner<M1,N2>()), mat12);
    VERIFY_IS_EQUAL((m_fixed.template bottomLeftCorner<M2,N1>()), mat21);
    VERIFY_IS_EQUAL((m_fixed.template bottomRightCorner<M2,N2>()), mat22);
    VERIFY_IS_EQUAL((m_fixed << mat12, mat11, matx21, mat22).finished(), (m_dynamic << mat12, matx11, matx21, mat22).finished());
  }

  if(N1 > 0)
  {
    if(M1 > 0)
    {
      VERIFY_RAISES_ASSERT((m_fixed << mat11, mat12, mat11, mat21, mat22));
    }
    if(M2 > 0)
    {
      VERIFY_RAISES_ASSERT((m_fixed << mat11, mat12, mat21, mat21, mat22));
    }
  }
  else
  {
    // allow insertion of zero-column blocks:
    VERIFY_IS_EQUAL((m_fixed << mat11, mat12, mat11, mat11, mat21, mat21, mat22).finished(), (m_dynamic << mat12, mat22).finished());
  }
  if(M1 != M2)
  {
    VERIFY_RAISES_ASSERT((m_fixed << mat11, mat21, mat12, mat22));
  }
}


template<int depth, int N=0>
struct test_block_recursion
{
  static void run()
  {
    test_block_recursion<depth-1, N>::run();
    test_block_recursion<depth-1, N + (1 << (depth-1))>::run();
  }
};

template<int N>
struct test_block_recursion<0,N>
{
  static void run() {
    test_blocks<(N>>6)&3, (N>>4)&3, (N>>2)&3, N & 3>();
  }
};

void test_basics() {
  Matrix3d m3;
  Matrix4d m4;

  VERIFY_RAISES_ASSERT( (m3 << 1, 2, 3, 4, 5, 6, 7, 8) );
  
  #ifndef _MSC_VER
  VERIFY_RAISES_ASSERT( (m3 << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) );
  #endif

  double data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
  Matrix3d ref = Map<Matrix<double,3,3,RowMajor> >(data);

  m3 = Matrix3d::Random();
  m3 << 1, 2, 3, 4, 5, 6, 7, 8, 9;
  VERIFY_IS_APPROX(m3, ref );

  Vector3d vec[3];
  vec[0] << 1, 4, 7;
  vec[1] << 2, 5, 8;
  vec[2] << 3, 6, 9;
  m3 = Matrix3d::Random();
  m3 << vec[0], vec[1], vec[2];
  VERIFY_IS_APPROX(m3, ref);

  vec[0] << 1, 2, 3;
  vec[1] << 4, 5, 6;
  vec[2] << 7, 8, 9;
  m3 = Matrix3d::Random();
  m3 << vec[0].transpose(),
        4, 5, 6,
        vec[2].transpose();
  VERIFY_IS_APPROX(m3, ref);
}

EIGEN_DECLARE_TEST(commainitializer)
{

  CALL_SUBTEST_1(test_basics());

  // recursively test all block-sizes from 0 to 3:
  CALL_SUBTEST_2(test_block_recursion<8>::run());
}
