package murmur3

import (
	//"encoding/binary"
	
	
)

const (
	c1_128 = 0x87c37b91114253d5
	c2_128 = 0x4cf5ad432745937f
)

// Make sure interfaces are correctly implemented.
var (
	_ hash.Hash = new(digest128)
	_ Hash128   = new(digest128)
	_ bmixer    = new(digest128)
)

// Hash128 represents a 128-bit hasher
// Hack: the standard api doesn't define any Hash128 interface.
type Hash128 interface {
	hash.Hash
	Sum128() (uint64, uint64)
}

// digest128 represents a partial evaluation of a 128 bites hash.
type digest128 struct {
	digest
	h1 uint64 // Unfinalized running hash part 1.
	h2 uint64 // Unfinalized running hash part 2.
}

// New128 returns a 128-bit hasher
func () Hash128 { return New128WithSeed(0) }

// New128WithSeed returns a 128-bit hasher set with explicit seed value
func ( uint32) Hash128 {
	 := new(digest128)
	.seed = 
	.bmixer = 
	.Reset()
	return 
}

func ( *digest128) () int { return 16 }

func ( *digest128) () { .h1, .h2 = uint64(.seed), uint64(.seed) }

func ( *digest128) ( []byte) []byte {
	,  := .Sum128()
	return append(,
		byte(>>56), byte(>>48), byte(>>40), byte(>>32),
		byte(>>24), byte(>>16), byte(>>8), byte(),

		byte(>>56), byte(>>48), byte(>>40), byte(>>32),
		byte(>>24), byte(>>16), byte(>>8), byte(),
	)
}

func ( *digest128) ( []byte) ( []byte) {
	,  := .h1, .h2

	 := len() / 16
	for  := 0;  < ; ++ {
		 := (*[2]uint64)(unsafe.Pointer(&[*16]))
		,  := [0], [1]

		 *= c1_128
		 = ( << 31) | ( >> 33) // rotl64(k1, 31)
		 *= c2_128
		 ^= 

		 = ( << 27) | ( >> 37) // rotl64(h1, 27)
		 += 
		 = *5 + 0x52dce729

		 *= c2_128
		 = ( << 33) | ( >> 31) // rotl64(k2, 33)
		 *= c1_128
		 ^= 

		 = ( << 31) | ( >> 33) // rotl64(h2, 31)
		 += 
		 = *5 + 0x38495ab5
	}
	.h1, .h2 = , 
	return [*.Size():]
}

func ( *digest128) () (,  uint64) {

	,  = .h1, .h2

	var ,  uint64
	switch len(.tail) & 15 {
	case 15:
		 ^= uint64(.tail[14]) << 48
		fallthrough
	case 14:
		 ^= uint64(.tail[13]) << 40
		fallthrough
	case 13:
		 ^= uint64(.tail[12]) << 32
		fallthrough
	case 12:
		 ^= uint64(.tail[11]) << 24
		fallthrough
	case 11:
		 ^= uint64(.tail[10]) << 16
		fallthrough
	case 10:
		 ^= uint64(.tail[9]) << 8
		fallthrough
	case 9:
		 ^= uint64(.tail[8]) << 0

		 *= c2_128
		 = ( << 33) | ( >> 31) // rotl64(k2, 33)
		 *= c1_128
		 ^= 

		fallthrough

	case 8:
		 ^= uint64(.tail[7]) << 56
		fallthrough
	case 7:
		 ^= uint64(.tail[6]) << 48
		fallthrough
	case 6:
		 ^= uint64(.tail[5]) << 40
		fallthrough
	case 5:
		 ^= uint64(.tail[4]) << 32
		fallthrough
	case 4:
		 ^= uint64(.tail[3]) << 24
		fallthrough
	case 3:
		 ^= uint64(.tail[2]) << 16
		fallthrough
	case 2:
		 ^= uint64(.tail[1]) << 8
		fallthrough
	case 1:
		 ^= uint64(.tail[0]) << 0
		 *= c1_128
		 = ( << 31) | ( >> 33) // rotl64(k1, 31)
		 *= c2_128
		 ^= 
	}

	 ^= uint64(.clen)
	 ^= uint64(.clen)

	 += 
	 += 

	 = fmix64()
	 = fmix64()

	 += 
	 += 

	return , 
}

func fmix64( uint64) uint64 {
	 ^=  >> 33
	 *= 0xff51afd7ed558ccd
	 ^=  >> 33
	 *= 0xc4ceb9fe1a85ec53
	 ^=  >> 33
	return 
}

/*
func rotl64(x uint64, r byte) uint64 {
	return (x << r) | (x >> (64 - r))
}
*/

// Sum128 returns the MurmurHash3 sum of data. It is equivalent to the
// following sequence (without the extra burden and the extra allocation):
//     hasher := New128()
//     hasher.Write(data)
//     return hasher.Sum128()
func ( []byte) ( uint64,  uint64) { return Sum128WithSeed(, 0) }

// Sum128WithSeed returns the MurmurHash3 sum of data. It is equivalent to the
// following sequence (without the extra burden and the extra allocation):
//     hasher := New128WithSeed(seed)
//     hasher.Write(data)
//     return hasher.Sum128()
func ( []byte,  uint32) ( uint64,  uint64) {
	 := &digest128{h1: uint64(), h2: uint64()}
	.seed = 
	.tail = .bmix()
	.clen = len()
	return .Sum128()
}