package thumbnail

import (
	"bytes"
	"image"
	"image/jpeg"
	"image/png"

	"golang.org/x/image/bmp"
	"golang.org/x/image/draw"
)

func (this *DirectThumbnailer) scaleImage(src image.Image) (image.Image, error) {
	srcW := src.Bounds().Max.X
	srcH := src.Bounds().Max.Y
	var srcCopyPosition, destCopyPosition image.Rectangle

	switch this.cfg.Aspect {
	case FitInside:

		var destW, destH int

		if srcW > srcH {
			destW = this.cfg.Width
			destH = this.cfg.Height * srcH / srcW
		} else {
			destW = this.cfg.Width * srcW / srcH
			destH = this.cfg.Height
		}

		offsetX := (this.cfg.Width - destW) / 2
		offsetY := (this.cfg.Height - destH) / 2

		srcCopyPosition = src.Bounds()
		destCopyPosition = image.Rect(offsetX, offsetY, destW+offsetX, destH+offsetY)

	case FitOutside:

		var srcSmallestDim, offsetX, offsetY int
		if srcW > srcH {
			// Landscape
			srcSmallestDim = srcH
			offsetY = 0
			offsetX = (srcW - srcH) / 2
		} else {
			// Portrait (or square)
			srcSmallestDim = srcW
			offsetY = (srcH - srcW) / 2
			offsetX = 0
		}

		srcCopyPosition = image.Rect(offsetX, offsetY, srcSmallestDim+offsetX, srcSmallestDim+offsetY)
		destCopyPosition = image.Rect(0, 0, this.cfg.Width, this.cfg.Height)

	case Stretch:
		srcCopyPosition = src.Bounds()
		destCopyPosition = image.Rect(0, 0, this.cfg.Width, this.cfg.Height)

	default:
		return nil, ErrInvalidOption
	}

	//

	dest := image.NewRGBA(image.Rect(0, 0, this.cfg.Width, this.cfg.Height))

	// For a transparent destination, Op.Src is faster than Op.Over

	switch this.cfg.Scale {
	case NearestNeighbour:
		draw.NearestNeighbor.Scale(dest, destCopyPosition, src, srcCopyPosition, draw.Src, nil)

	case BilinearFast:
		draw.ApproxBiLinear.Scale(dest, destCopyPosition, src, srcCopyPosition, draw.Src, nil)

	case BilinearAccurate:
		draw.BiLinear.Scale(dest, destCopyPosition, src, srcCopyPosition, draw.Src, nil)

	case Bicubic:
		draw.CatmullRom.Scale(dest, destCopyPosition, src, srcCopyPosition, draw.Src, nil)
	}

	return dest, nil
}

func (this *DirectThumbnailer) encode(dest image.Image) ([]byte, error) {

	switch this.cfg.Output {
	case Png:
		buff := bytes.Buffer{}
		err := png.Encode(&buff, dest)
		if err != nil {
			return nil, err
		}
		return buff.Bytes(), nil

	case PngCrush:
		return crushFast(dest)

	case Jpeg:
		buff := bytes.Buffer{}
		err := jpeg.Encode(&buff, dest, &jpeg.Options{Quality: jpeg.DefaultQuality})
		if err != nil {
			return nil, err
		}

		return buff.Bytes(), nil

	case Bmp:
		buff := bytes.Buffer{}
		err := bmp.Encode(&buff, dest)
		if err != nil {
			return nil, err
		}
		return buff.Bytes(), nil

	default:
		return nil, ErrInvalidOption

	}

}
