package shapes

import "image"
import "image/color"
import "git.tebibyte.media/sashakoshka/tomo/canvas"

// ColorLine draws a line from one point to another with the specified weight
// and color.
func ColorLine (
	destination canvas.Canvas,
	color       color.RGBA,
	weight      int,
	min         image.Point,
	max         image.Point,
) (
	updatedRegion image.Rectangle,
) {
	updatedRegion = image.Rectangle { Min: min, Max: max }.Canon()
	updatedRegion.Max.X ++
	updatedRegion.Max.Y ++
	
	data, stride := destination.Buffer()
	bounds := destination.Bounds()
	context := linePlottingContext {
		plottingContext: plottingContext {
			dstData:   data,
			dstStride: stride,
			color:     color,
			weight:    weight,
			bounds:    bounds,
		},
		min: min,
		max: max,
	}
	
	if abs(max.Y - min.Y) < abs(max.X - min.X) {
		if max.X < min.X { context.swap() }
		context.lineLow()
		
	} else {
		if max.Y < min.Y { context.swap() }
		context.lineHigh()
	}
	return
}

type linePlottingContext struct {
	plottingContext
	min image.Point
	max image.Point
}

func (context *linePlottingContext) swap () {
	temp := context.max
	context.max = context.min
	context.min = temp
}

func (context linePlottingContext) lineLow () {
	deltaX := context.max.X - context.min.X
	deltaY := context.max.Y - context.min.Y
	yi     := 1

	if deltaY < 0 {
		yi      = -1
		deltaY *= -1
	}

	D := (2 * deltaY) - deltaX
	point := context.min

	for ; point.X < context.max.X; point.X ++ {
		if !point.In(context.bounds) { break }
		context.plotColor(point)
		if D > 0 {
			D += 2 * (deltaY - deltaX)
			point.Y += yi
		} else {
			D += 2 * deltaY
		}
	}
}

func (context linePlottingContext) lineHigh () {
	deltaX := context.max.X - context.min.X
	deltaY := context.max.Y - context.min.Y
	xi     := 1

	if deltaX < 0 {
		xi      = -1
		deltaX *= -1
	}

	D := (2 * deltaX) - deltaY
	point := context.min

	for ; point.Y < context.max.Y; point.Y ++ {
		if !point.In(context.bounds) { break }
		context.plotColor(point)
		if D > 0 {
			point.X += xi
			D += 2 * (deltaX - deltaY)
		} else {
			D += 2 * deltaX
		}
	}
}

func abs (n int) int {
	if n < 0 { n *= -1}
	return n
}