package main

import (
	"math"
)

type Color interface {
	GetColor(Vector3) Vector3
}
type ScaledColor struct {
	color Color
	scale float64
}

func (sColor ScaledColor) GetColor(p Vector3) Vector3 {
	return sColor.color.GetColor(p).Scale(sColor.scale)
}

type GridColor struct {
	color1 Color
	color2 Color
	size   float64
}

func (grid GridColor) GetColor(p Vector3) Vector3 {
	ix := int(math.Floor(p.X / grid.size))
	iy := int(math.Floor(p.Y / grid.size))
	iz := int(math.Floor(p.Z/grid.size)) * 0

	if (ix+iy+iz)%2 == 0 {
		return grid.color1.GetColor(p)
	}
	return grid.color2.GetColor(p)
}

type Material interface {
	GetMaterialBrut() MaterialBrut
}

type MaterialBrut struct {
	ambiantColor    Color
	diffuseColor    Color
	diffuseFac      float64
	specularColor   Color
	specularFac     float64
	specularExp     float64
	reflectanceFac  float64
	reflectanceTint Color
	refractFac      float64
	refractIndice   float64
}

func (mat MaterialBrut) GetMaterialBrut() MaterialBrut {
	return mat
}

func MixMat(mat1 MaterialBrut, mat2 MaterialBrut, t float64, p Vector3) MaterialBrut {
	return MaterialBrut{
		(mat1.ambiantColor.GetColor(p).Scale(1 - t)).Add((mat2.ambiantColor.GetColor(p)).Scale(t)),
		(mat1.diffuseColor.GetColor(p).Scale(1 - t)).Add((mat2.diffuseColor.GetColor(p)).Scale(t)),
		mat1.diffuseFac*(1-t) + mat2.diffuseFac*t,
		mat1.specularColor.GetColor(p).Scale(1 - t).Add((mat2.specularColor.GetColor(p)).Scale(t)),
		mat1.specularFac*(1-t) + mat2.specularFac*t,
		mat1.specularExp*(1-t) + mat2.specularExp*t,
		mat1.reflectanceFac*(1-t) + mat2.reflectanceFac*t,
		mat1.reflectanceTint.GetColor(p).Scale(1 - t).Add((mat2.reflectanceTint.GetColor(p)).Scale(t)),
		mat1.refractFac*(1-t) + mat2.refractFac*t,
		mat1.refractIndice*(1-t) + mat2.refractIndice*t,
	}
}

type MixedMaterial struct {
	mat1 Material
	mat2 Material
	t    float64
	p    Vector3
}

func (mixedMat MixedMaterial) GetMaterialBrut() MaterialBrut {
	return MixMat((mixedMat.mat1).GetMaterialBrut(), (mixedMat.mat2).GetMaterialBrut(), mixedMat.t, mixedMat.p)
}

func DefaultMaterial(diffuseColor Color) MaterialBrut {
	return MaterialBrut{
		ambiantColor:    ScaledColor{diffuseColor, 0.2},
		diffuseColor:    diffuseColor,
		diffuseFac:      1,
		specularColor:   Vector3{255, 255, 255},
		specularFac:     1,
		specularExp:     35.0,
		reflectanceFac:  0.5,
		reflectanceTint: Vector3{255, 255, 255},
		refractFac:      0.0,
		refractIndice:   1.0,
	}
}

// Colors

var RED = Vector3{125, 0, 0}
var GREEN = Vector3{0, 255, 0}
var BLUE = Vector3{0, 0, 255}
var WHITE = Vector3{255, 255, 255}
var GREY = Vector3{127, 127, 127}

var WHITE_GREY_GRID = GridColor{WHITE, GREY, 5}
var RED_BLUE_GRID = GridColor{RED, BLUE, 5}

var GRID_OF_GRID = GridColor{WHITE_GREY_GRID, RED_BLUE_GRID, 10}

// Materials

var RED_MAT = DefaultMaterial(RED)
var GREEN_MAT = DefaultMaterial(GREEN)
var BLUE_MAT = DefaultMaterial(BLUE)
var WHITE_MAT = DefaultMaterial(WHITE)
var GREY_MAT = DefaultMaterial(GREY)

var WHITE_GREY_GRID_MAT = DefaultMaterial(WHITE_GREY_GRID)
var GRID_OF_GRID_MAT = DefaultMaterial(GRID_OF_GRID)
