/*
 * Copyright (C) 2014 ~ 2018 Deepin Technology Co., Ltd.
 *
 * Author:     jouyouyun <jouyouwen717@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package main

import (
	"fmt"
	"testing"

	"github.com/stretchr/testify/suite"
	"github.com/linuxdeepin/go-lib/dbusutil"
)

const (
	originImg               = "testdata/origin_1920x1080.jpg"
	originImgWidth          = 1920
	originImgHeight         = 1080
	originImgDominantColorH = 198.6
	originImgDominantColorS = 0.40
	originImgDominantColorV = 0.43

	originImgPngSmall = "testdata/origin_small_200x200.png"
	originImgPngIcon1 = "testdata/origin_icon_1_48x48.png"
	originImgPngIcon2 = "testdata/origin_icon_2_48x48.png"
)

type UnitTest struct {
	suite.Suite
	g *Graphic
}

// data uri for originImgPngIcon2
const testDataUri = `data:image/png;base64, `

func delta(x, y float64) float64 {
	if x >= y {
		return x - y
	}
	return y - x
}

func (suite *UnitTest) SetupSuite() {
	var err error
	suite.g = &Graphic{}
	suite.g.service, err = dbusutil.NewSessionService()
	if err != nil {
		suite.T().Skip(fmt.Sprintf("failed to get service: %v", err))
	}
}

func (suite *UnitTest) TestBlurImage() {
	resultFile := "testdata/test_blurimage.png"
	err := suite.g.BlurImage(originImg, resultFile, 50, 1, "png")
	suite.Require().Nil(err)
}

func (suite *UnitTest) TestClipImage() {
	resultFile := "testdata/test_clipimage_100x200.png"
	err := suite.g.ClipImage(originImg, resultFile, 0, 0, 100, 200, "png")
	suite.Require().Nil(err)
}

func (suite *UnitTest) TestConvertImage() {
	resultFile := "testdata/test_convertimage.png"
	err := suite.g.ConvertImage(originImg, resultFile, "png")
	suite.Require().Nil(err)
}

func (suite *UnitTest) TestConvertImageToDataUri() {
	dataUri, err := suite.g.ConvertImageToDataUri(originImgPngIcon2)
	suite.Require().Nil(err)
	suite.Equal(dataUri, testDataUri)
}

func (suite *UnitTest) TestConvertDataUriToImage() {
	resultFile := "testdata/test_convertdatauri.png"
	err := suite.g.ConvertDataUriToImage(testDataUri, resultFile, "png")
	suite.Require().Nil(err)
}

func (suite *UnitTest) TestCompositeImage() {
	resultFile := "testdata/test_compositeimage.png"
	err := suite.g.CompositeImage(originImgPngSmall, originImgPngIcon1, resultFile, 0, 0, "png")
	suite.Require().Nil(err)

	err = suite.g.CompositeImage(resultFile, originImgPngIcon2, resultFile, 24, 24, "png")
	suite.Require().Nil(err)
}

func (suite *UnitTest) TestCompositeImageUri() {
	resultFile := "testdata/test_compositeimageuri.png"
	srcImageUri, _ := suite.g.ConvertImageToDataUri(originImgPngSmall)
	compImageUri1, _ := suite.g.ConvertImageToDataUri(originImgPngIcon1)
	compImageUri2, _ := suite.g.ConvertImageToDataUri(originImgPngIcon2)
	resultDataUri, _ := suite.g.CompositeImageUri(srcImageUri, compImageUri1, 0, 0, "png")
	resultDataUri, _ = suite.g.CompositeImageUri(resultDataUri, compImageUri2, 24, 24, "png")
	err := suite.g.ConvertDataUriToImage(resultDataUri, resultFile, "png")
	suite.Require().Nil(err)
}

func (suite *UnitTest) TestGetDominantColorOfImage() {
	h, s, v, err := suite.g.GetDominantColorOfImage(originImg)
	suite.Require().Nil(err)

	if delta(h, originImgDominantColorH) > 1 ||
		delta(s, originImgDominantColorS) > 0.1 ||
		delta(v, originImgDominantColorV) > 0.1 {
		suite.T().Error("h,s, v = ", h, s, v)
	}
}

func (suite *UnitTest) TestFillImage() {
	resultFile := "testdata/test_flllimage_tile_200x200.png"
	err := suite.g.FillImage(originImg, resultFile, 200, 200, "tile", "png")
	suite.Require().Nil(err)

	resultFile = "testdata/test_flllimage_tile_1600x1000.png"
	err = suite.g.FillImage(originImg, resultFile, 1600, 1000, "tile", "png")
	suite.Require().Nil(err)

	resultFile = "testdata/test_flllimage_center_400x400.png"
	err = suite.g.FillImage(originImg, resultFile, 400, 400, "center", "png")
	suite.Require().Nil(err)

	resultFile = "testdata/test_flllimage_center_1600x1000.png"
	err = suite.g.FillImage(originImg, resultFile, 1600, 1000, "center", "png")
	suite.Require().Nil(err)
}

func (suite *UnitTest) TestFlipImageHorizontal() {
	resultFile := "testdata/test_flipimagehorizontal.png"
	err := suite.g.FlipImageHorizontal(originImg, resultFile, "png")
	suite.Require().Nil(err)
}

func (suite *UnitTest) TestFlipImageVertical() {
	resultFile := "testdata/test_flipimagevertical.png"
	err := suite.g.FlipImageVertical(originImg, resultFile, "png")
	suite.Require().Nil(err)
}

func (suite *UnitTest) TestHsv() {
	for r := 0; r < 255; r += 7 {
		for gg := 0; gg < 255; gg += 5 {
			for b := 0; b < 255; b += 3 {
				r0, g0, b0 := uint8(r), uint8(gg), uint8(b)
				h, s, v, _ := suite.g.Rgb2Hsv(r0, g0, b0)
				r1, g1, b1, _ := suite.g.Hsv2Rgb(h, s, v)
				if delta(float64(r0), float64(r1)) > 1 || delta(float64(g0), float64(g1)) > 1 || delta(float64(b0), float64(b1)) > 1 {
					suite.T().Fatalf("r0, g0, b0 = %d, %d, %d   r1, g1, b1 = %d, %d, %d", r0, g0, b0, r1, g1, b1)
				}
			}
		}
	}
}

func (suite *UnitTest) TestGetImageSize() {
	w, h, err := suite.g.GetImageSize(originImg)
	suite.Require().Nil(err)

	suite.Equal(int(w), originImgWidth)
	suite.Equal(int(h), originImgHeight)
}

func (suite *UnitTest) TestResizeImage() {
	resultFile := "testdata/test_scaleimage_500x600.png"
	err := suite.g.ResizeImage(originImg, resultFile, 500, 600, "png")
	suite.Require().Nil(err)

	w, h, err := suite.g.GetImageSize(resultFile)
	suite.Require().Nil(err)
	suite.Equal(int(w), 500)
	suite.Equal(int(h), 600)
}

func (suite *UnitTest) TestThumbnailImage() {
	resultFile := "testdata/test_thumbnail.png"
	maxWidth, maxHeight := 200, 200
	err := suite.g.ThumbnailImage(originImg, resultFile, uint32(maxWidth), uint32(maxHeight), "png")
	suite.Require().Nil(err)

	w, h, _ := suite.g.GetImageSize(resultFile)
	suite.Equal(int(w) <= maxWidth, true)
	suite.Equal(int(h) <= maxHeight, true)
}

func (suite *UnitTest) TestRotateImageLeft() {
	resultFile := "testdata/test_rotateimageleft.png"
	err := suite.g.RotateImageLeft(originImg, resultFile, "png")
	suite.Require().Nil(err)
}

func (suite *UnitTest) TestRotateImageRight() {
	resultFile := "testdata/test_rotateimageright.png"
	err := suite.g.RotateImageRight(originImg, resultFile, "png")
	suite.Require().Nil(err)
}

func TestUnitTestSuite(t *testing.T) {
	suite.Run(t, new(UnitTest))
}
