/*
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <cmath>

#include "cobalt/math/matrix_interpolation.h"
#include "cobalt/math/transform_2d.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace cobalt {
namespace math {

namespace {
Matrix3F DecomposeAndRecompose(const Matrix3F& input) {
  return RecomposeMatrix(DecomposeMatrix(input));
}
}  // namespace

TEST(MatrixInterpolationTest, DecomposeAndRecomposeIsIdentityForXShear) {
  Matrix3F input(Matrix3F::FromValues(1, 1, 0, 0, 1, 0, 0, 0, 1));

  EXPECT_TRUE(input.IsNear(DecomposeAndRecompose(input), 0.001f));
}

TEST(MatrixInterpolationTest, DecomposeAndRecomposeIsIdentityForYShear) {
  Matrix3F input(Matrix3F::FromValues(1, 0, 0, 1, 1, 0, 0, 0, 1));

  EXPECT_TRUE(input.IsNear(DecomposeAndRecompose(input), 0.001f));
}

TEST(MatrixInterpolationTest, DecomposeAndRecomposeIsIdentityForRotation) {
  Matrix3F input(RotateMatrix(static_cast<float>(M_PI / 4)));

  EXPECT_TRUE(input.IsNear(DecomposeAndRecompose(input), 0.001f));
}

TEST(MatrixInterpolationTest, DecomposeAndRecomposeIsIdentityForScale) {
  Matrix3F input(ScaleMatrix(2.0f, 3.0f));

  EXPECT_TRUE(input.IsNear(DecomposeAndRecompose(input), 0.001f));
}

TEST(MatrixInterpolationTest, DecomposeAndRecomposeIsIdentityForTranslation) {
  Matrix3F input(TranslateMatrix(2.0f, 3.0f));

  EXPECT_TRUE(input.IsNear(DecomposeAndRecompose(input), 0.001f));
}

TEST(MatrixInterpolationTest,
     DecomposeAndRecomposeIsIdentityForShearAndTranslation) {
  // The W3C specification multiplies the translation values by the shear values
  // in matrix recomposition, but this is not how decomposition is done, and
  // thus an exact implementation of their algorithm will fail this test.
  // Failing this test (or any of these decompose and recompose tests) will
  // result in jarring animations when transitioning from within a transition.
  Matrix3F input(Matrix3F::FromValues(1, 1, 40, 0, 1, 40, 0, 0, 1));

  EXPECT_TRUE(input.IsNear(DecomposeAndRecompose(input), 0.001f));
}

TEST(MatrixInterpolationTest, InterpolatingIdentitiesGivesIdentity) {
  // We expect that interpolating two identity matrices will give us the
  // identity matrix back.
  Matrix3F a(Matrix3F::Identity());
  Matrix3F b(Matrix3F::Identity());

  static const int kNumSamples = 10;
  for (int i = 0; i < kNumSamples + 1; ++i) {
    math::Matrix3F interpolated =
        InterpolateMatrices(a, b, i / static_cast<float>(kNumSamples));
    EXPECT_EQ(Matrix3F::Identity(), interpolated);
  }
}

}  // namespace math
}  // namespace cobalt
