// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package vp8l

// This file deals with image transforms, specified in section 3.

// nTiles returns the number of tiles needed to cover size pixels, where each
// tile's side is 1<<bits pixels long.
func nTiles( int32,  uint32) int32 {
	return ( + 1<< - 1) >> 
}

const (
	transformTypePredictor     = 0
	transformTypeCrossColor    = 1
	transformTypeSubtractGreen = 2
	transformTypeColorIndexing = 3
	nTransformTypes            = 4
)

// transform holds the parameters for an invertible transform.
type transform struct {
	// transformType is the type of the transform.
	transformType uint32
	// oldWidth is the width of the image before transformation (or
	// equivalently, after inverse transformation). The color-indexing
	// transform can reduce the width. For example, a 50-pixel-wide
	// image that only needs 4 bits (half a byte) per color index can
	// be transformed into a 25-pixel-wide image.
	oldWidth int32
	// bits is the log-2 size of the transform's tiles, for the predictor
	// and cross-color transforms. 8>>bits is the number of bits per
	// color index, for the color-index transform.
	bits uint32
	// pix is the tile values, for the predictor and cross-color
	// transforms, and the color palette, for the color-index transform.
	pix []byte
}

var inverseTransforms = [nTransformTypes]func(*transform, []byte, int32) []byte{
	transformTypePredictor:     inversePredictor,
	transformTypeCrossColor:    inverseCrossColor,
	transformTypeSubtractGreen: inverseSubtractGreen,
	transformTypeColorIndexing: inverseColorIndexing,
}

func inversePredictor( *transform,  []byte,  int32) []byte {
	if .oldWidth == 0 ||  == 0 {
		return 
	}
	// The first pixel's predictor is mode 0 (opaque black).
	[3] += 0xff
	,  := int32(4), int32(1)<<.bits-1
	for  := int32(1);  < .oldWidth; ++ {
		// The rest of the first row's predictor is mode 1 (L).
		[+0] += [-4]
		[+1] += [-3]
		[+2] += [-2]
		[+3] += [-1]
		 += 4
	}
	,  := 0, nTiles(.oldWidth, .bits)
	for  := int32(1);  < ; ++ {
		// The first column's predictor is mode 2 (T).
		[+0] += [+0]
		[+1] += [+1]
		[+2] += [+2]
		[+3] += [+3]
		,  = +4, +4

		 := 4 * ( >> .bits) * 
		 := .pix[+1] & 0x0f
		 += 4
		for  := int32(1);  < .oldWidth; ++ {
			if & == 0 {
				 = .pix[+1] & 0x0f
				 += 4
			}
			switch  {
			case 0: // Opaque black.
				[+3] += 0xff

			case 1: // L.
				[+0] += [-4]
				[+1] += [-3]
				[+2] += [-2]
				[+3] += [-1]

			case 2: // T.
				[+0] += [+0]
				[+1] += [+1]
				[+2] += [+2]
				[+3] += [+3]

			case 3: // TR.
				[+0] += [+4]
				[+1] += [+5]
				[+2] += [+6]
				[+3] += [+7]

			case 4: // TL.
				[+0] += [-4]
				[+1] += [-3]
				[+2] += [-2]
				[+3] += [-1]

			case 5: // Average2(Average2(L, TR), T).
				[+0] += avg2(avg2([-4], [+4]), [+0])
				[+1] += avg2(avg2([-3], [+5]), [+1])
				[+2] += avg2(avg2([-2], [+6]), [+2])
				[+3] += avg2(avg2([-1], [+7]), [+3])

			case 6: // Average2(L, TL).
				[+0] += avg2([-4], [-4])
				[+1] += avg2([-3], [-3])
				[+2] += avg2([-2], [-2])
				[+3] += avg2([-1], [-1])

			case 7: // Average2(L, T).
				[+0] += avg2([-4], [+0])
				[+1] += avg2([-3], [+1])
				[+2] += avg2([-2], [+2])
				[+3] += avg2([-1], [+3])

			case 8: // Average2(TL, T).
				[+0] += avg2([-4], [+0])
				[+1] += avg2([-3], [+1])
				[+2] += avg2([-2], [+2])
				[+3] += avg2([-1], [+3])

			case 9: // Average2(T, TR).
				[+0] += avg2([+0], [+4])
				[+1] += avg2([+1], [+5])
				[+2] += avg2([+2], [+6])
				[+3] += avg2([+3], [+7])

			case 10: // Average2(Average2(L, TL), Average2(T, TR)).
				[+0] += avg2(avg2([-4], [-4]), avg2([+0], [+4]))
				[+1] += avg2(avg2([-3], [-3]), avg2([+1], [+5]))
				[+2] += avg2(avg2([-2], [-2]), avg2([+2], [+6]))
				[+3] += avg2(avg2([-1], [-1]), avg2([+3], [+7]))

			case 11: // Select(L, T, TL).
				 := int32([-4])
				 := int32([-3])
				 := int32([-2])
				 := int32([-1])
				 := int32([-4])
				 := int32([-3])
				 := int32([-2])
				 := int32([-1])
				 := int32([+0])
				 := int32([+1])
				 := int32([+2])
				 := int32([+3])
				 := abs(-) + abs(-) + abs(-) + abs(-)
				 := abs(-) + abs(-) + abs(-) + abs(-)
				if  <  {
					[+0] += uint8()
					[+1] += uint8()
					[+2] += uint8()
					[+3] += uint8()
				} else {
					[+0] += uint8()
					[+1] += uint8()
					[+2] += uint8()
					[+3] += uint8()
				}

			case 12: // ClampAddSubtractFull(L, T, TL).
				[+0] += clampAddSubtractFull([-4], [+0], [-4])
				[+1] += clampAddSubtractFull([-3], [+1], [-3])
				[+2] += clampAddSubtractFull([-2], [+2], [-2])
				[+3] += clampAddSubtractFull([-1], [+3], [-1])

			case 13: // ClampAddSubtractHalf(Average2(L, T), TL).
				[+0] += clampAddSubtractHalf(avg2([-4], [+0]), [-4])
				[+1] += clampAddSubtractHalf(avg2([-3], [+1]), [-3])
				[+2] += clampAddSubtractHalf(avg2([-2], [+2]), [-2])
				[+3] += clampAddSubtractHalf(avg2([-1], [+3]), [-1])
			}
			,  = +4, +4
		}
	}
	return 
}

func inverseCrossColor( *transform,  []byte,  int32) []byte {
	var , ,  int32
	, ,  := int32(0), int32(1)<<.bits-1, nTiles(.oldWidth, .bits)
	for  := int32(0);  < ; ++ {
		 := 4 * ( >> .bits) * 
		for  := int32(0);  < .oldWidth; ++ {
			if & == 0 {
				 = int32(int8(.pix[+0]))
				 = int32(int8(.pix[+1]))
				 = int32(int8(.pix[+2]))
				 += 4
			}
			 := [+0]
			 := [+1]
			 := [+2]
			 += uint8(uint32(*int32(int8())) >> 5)
			 += uint8(uint32(*int32(int8())) >> 5)
			 += uint8(uint32(*int32(int8())) >> 5)
			[+0] = 
			[+2] = 
			 += 4
		}
	}
	return 
}

func inverseSubtractGreen( *transform,  []byte,  int32) []byte {
	for  := 0;  < len();  += 4 {
		 := [+1]
		[+0] += 
		[+2] += 
	}
	return 
}

func inverseColorIndexing( *transform,  []byte,  int32) []byte {
	if .bits == 0 {
		for  := 0;  < len();  += 4 {
			 := 4 * uint32([+1])
			[+0] = .pix[+0]
			[+1] = .pix[+1]
			[+2] = .pix[+2]
			[+3] = .pix[+3]
		}
		return 
	}

	, ,  := uint32(0), int32(0), uint32(8>>.bits)
	switch .bits {
	case 1:
		,  = 0x0f, 0x01
	case 2:
		,  = 0x03, 0x03
	case 3:
		,  = 0x01, 0x07
	}

	, , ,  := 0, 0, uint32(0), make([]byte, 4*.oldWidth*)
	for  := int32(0);  < ; ++ {
		for  := int32(0);  < .oldWidth; ++ {
			if & == 0 {
				 = uint32([+1])
				 += 4
			}

			 := 4 * ( & )
			[+0] = .pix[+0]
			[+1] = .pix[+1]
			[+2] = .pix[+2]
			[+3] = .pix[+3]
			 += 4

			 >>= 
		}
	}
	return 
}

func abs( int32) int32 {
	if  < 0 {
		return -
	}
	return 
}

func avg2(,  uint8) uint8 {
	return uint8((int32() + int32()) / 2)
}

func clampAddSubtractFull(, ,  uint8) uint8 {
	 := int32() + int32() - int32()
	if  < 0 {
		return 0
	}
	if  > 255 {
		return 255
	}
	return uint8()
}

func clampAddSubtractHalf(,  uint8) uint8 {
	 := int32() + (int32()-int32())/2
	if  < 0 {
		return 0
	}
	if  > 255 {
		return 255
	}
	return uint8()
}