/**
 * @license
 * Copyright 2020 Google LLC. 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.
 * =============================================================================
 */
import {getTestImageAsTensor4d} from '../../image_test_util';
import * as tf from '../../index';
import {BROWSER_ENVS, describeWithFlags} from '../../jasmine_util';
import {expectArraysClose} from '../../test_util';

describeWithFlags('rotateWithOffset', BROWSER_ENVS, () => {
  it('should rotate counterclockwise 90 degrees', async () => {
    const rotatedPixels =
        tf.image.rotateWithOffset(getTestImageAsTensor4d(), 90 * Math.PI / 180)
            .toInt();
    const rotatedPixelsData = await rotatedPixels.data();

    const expected = [
      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
      0,   0,   230, 133, 18,  255, 233, 148, 31,  255, 222, 164, 41,  255, 191,
      170, 61,  255, 135, 166, 86,  255, 71,  143, 97,  255, 15,  115, 105, 255,
      0,   102, 113, 255, 241, 153, 43,  255, 250, 177, 64,  255, 247, 201, 81,
      255, 218, 210, 103, 255, 162, 206, 127, 255, 98,  181, 135, 255, 39,  150,
      141, 255, 6,   133, 140, 255, 224, 156, 55,  255, 241, 188, 82,  255, 243,
      220, 106, 255, 213, 230, 126, 255, 155, 226, 146, 255, 94,  206, 156, 255,
      37,  177, 164, 255, 3,   158, 162, 255, 212, 157, 75,  255, 230, 193, 104,
      255, 235, 227, 128, 255, 201, 236, 142, 255, 141, 232, 162, 255, 87,  220,
      175, 255, 35,  200, 186, 255, 4,   182, 186, 255, 200, 155, 98,  255, 220,
      190, 128, 255, 225, 228, 151, 255, 191, 239, 165, 255, 130, 235, 179, 255,
      76,  225, 193, 255, 30,  209, 205, 255, 0,   194, 204, 255, 183, 138, 109,
      255, 202, 174, 137, 255, 211, 216, 162, 255, 184, 234, 181, 255, 121, 231,
      192, 255, 64,  219, 201, 255, 19,  203, 211, 255, 0,   189, 209, 255, 171,
      120, 117, 255, 186, 152, 140, 255, 199, 198, 168, 255, 179, 226, 194, 255,
      119, 226, 206, 255, 62,  217, 213, 255, 19,  204, 222, 255, 0,   192, 221,
      255
    ];

    expectArraysClose(expected, rotatedPixelsData);
  });

  it('should rotate clockwise 90 degrees', async () => {
    const rotatedPixels =
        tf.image.rotateWithOffset(getTestImageAsTensor4d(), -90 * Math.PI / 180)
            .toInt();
    const rotatedPixelsData = await rotatedPixels.data();

    const expected = [
      0,   0,   0,   0,   0,   193, 228, 255, 18,  200, 224, 255, 55,  207, 212,
      255, 108, 214, 202, 255, 163, 208, 187, 255, 179, 176, 159, 255, 168, 129,
      130, 255, 0,   0,   0,   0,   0,   192, 221, 255, 19,  204, 222, 255, 62,
      217, 213, 255, 119, 226, 206, 255, 179, 226, 194, 255, 199, 198, 168, 255,
      186, 152, 140, 255, 0,   0,   0,   0,   0,   189, 209, 255, 19,  203, 211,
      255, 64,  219, 201, 255, 121, 231, 192, 255, 184, 234, 181, 255, 211, 216,
      162, 255, 202, 174, 137, 255, 0,   0,   0,   0,   0,   194, 204, 255, 30,
      209, 205, 255, 76,  225, 193, 255, 130, 235, 179, 255, 191, 239, 165, 255,
      225, 228, 151, 255, 220, 190, 128, 255, 0,   0,   0,   0,   4,   182, 186,
      255, 35,  200, 186, 255, 87,  220, 175, 255, 141, 232, 162, 255, 201, 236,
      142, 255, 235, 227, 128, 255, 230, 193, 104, 255, 0,   0,   0,   0,   3,
      158, 162, 255, 37,  177, 164, 255, 94,  206, 156, 255, 155, 226, 146, 255,
      213, 230, 126, 255, 243, 220, 106, 255, 241, 188, 82,  255, 0,   0,   0,
      0,   6,   133, 140, 255, 39,  150, 141, 255, 98,  181, 135, 255, 162, 206,
      127, 255, 218, 210, 103, 255, 247, 201, 81,  255, 250, 177, 64,  255, 0,
      0,   0,   0,   0,   102, 113, 255, 15,  115, 105, 255, 71,  143, 97,  255,
      135, 166, 86,  255, 191, 170, 61,  255, 222, 164, 41,  255, 233, 148, 31,
      255
    ];

    expectArraysClose(expected, rotatedPixelsData);
  });

  it('offset center of rotation', async () => {
    const rotatedPixels =
        tf.image
            .rotateWithOffset(
                getTestImageAsTensor4d(), 45 * Math.PI / 180, 0, [0.25, 0.75])
            .toInt();
    const rotatedPixelsData = await rotatedPixels.data();

    const expected = [
      224, 156, 55,  255, 250, 177, 64,  255, 247, 201, 81,  255, 222, 164, 41,
      255, 0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
      0,   0,   230, 193, 104, 255, 243, 220, 106, 255, 247, 201, 81,  255, 218,
      210, 103, 255, 135, 166, 86,  255, 0,   0,   0,   0,   0,   0,   0,   0,
      0,   0,   0,   0,   225, 228, 151, 255, 235, 227, 128, 255, 213, 230, 126,
      255, 162, 206, 127, 255, 98,  181, 135, 255, 71,  143, 97,  255, 0,   0,
      0,   0,   0,   0,   0,   0,   225, 228, 151, 255, 191, 239, 165, 255, 141,
      232, 162, 255, 94,  206, 156, 255, 98,  181, 135, 255, 39,  150, 141, 255,
      0,   102, 113, 255, 0,   0,   0,   0,   184, 234, 181, 255, 130, 235, 179,
      255, 76,  225, 193, 255, 87,  220, 175, 255, 37,  177, 164, 255, 6,   133,
      140, 255, 6,   133, 140, 255, 0,   0,   0,   0,   119, 226, 206, 255, 64,
      219, 201, 255, 76,  225, 193, 255, 30,  209, 205, 255, 4,   182, 186, 255,
      3,   158, 162, 255, 0,   0,   0,   0,   0,   0,   0,   0,   62,  217, 213,
      255, 62,  217, 213, 255, 19,  203, 211, 255, 0,   194, 204, 255, 0,   194,
      204, 255, 0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   55,
      207, 212, 255, 19,  204, 222, 255, 0,   192, 221, 255, 0,   189, 209, 255,
      0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
      0
    ];

    expectArraysClose(expected, rotatedPixelsData);
  });

  it('offset center of rotation with white fill', async () => {
    const rotatedPixels =
        tf.image
            .rotateWithOffset(
                getTestImageAsTensor4d(), 45 * Math.PI / 180, 255, [0.25, 0.75])
            .toInt();
    const rotatedPixelsData = await rotatedPixels.data();

    const expected = [
      224, 156, 55,  255, 250, 177, 64,  255, 247, 201, 81,  255, 222, 164, 41,
      255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
      255, 255, 230, 193, 104, 255, 243, 220, 106, 255, 247, 201, 81,  255, 218,
      210, 103, 255, 135, 166, 86,  255, 255, 255, 255, 255, 255, 255, 255, 255,
      255, 255, 255, 255, 225, 228, 151, 255, 235, 227, 128, 255, 213, 230, 126,
      255, 162, 206, 127, 255, 98,  181, 135, 255, 71,  143, 97,  255, 255, 255,
      255, 255, 255, 255, 255, 255, 225, 228, 151, 255, 191, 239, 165, 255, 141,
      232, 162, 255, 94,  206, 156, 255, 98,  181, 135, 255, 39,  150, 141, 255,
      0,   102, 113, 255, 255, 255, 255, 255, 184, 234, 181, 255, 130, 235, 179,
      255, 76,  225, 193, 255, 87,  220, 175, 255, 37,  177, 164, 255, 6,   133,
      140, 255, 6,   133, 140, 255, 255, 255, 255, 255, 119, 226, 206, 255, 64,
      219, 201, 255, 76,  225, 193, 255, 30,  209, 205, 255, 4,   182, 186, 255,
      3,   158, 162, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62,  217, 213,
      255, 62,  217, 213, 255, 19,  203, 211, 255, 0,   194, 204, 255, 0,   194,
      204, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 55,
      207, 212, 255, 19,  204, 222, 255, 0,   192, 221, 255, 0,   189, 209, 255,
      255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
      255
    ];

    expectArraysClose(expected, rotatedPixelsData);
  });

  it('throws when input is int32', async () => {
    expect(
        () => tf.image.rotateWithOffset(
            tf.tensor4d([1, 2, 3, 255], [1, 1, 1, 4], 'int32'),
            90 * Math.PI / 180))
        .toThrowError(
            /Argument 'image' passed to 'rotateWithOffset' must be float32/);
  });
});
