// Copyright 2016 The CMux Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.

package cmux

import (
	
	
)

// patriciaTree is a simple patricia tree that handles []byte instead of string
// and cannot be changed after instantiation.
type patriciaTree struct {
	root     *ptNode
	maxDepth int // max depth of the tree.
}

func newPatriciaTree( ...[]byte) *patriciaTree {
	 := 0
	for ,  := range  {
		if  < len() {
			 = len()
		}
	}
	return &patriciaTree{
		root:     newNode(),
		maxDepth:  + 1,
	}
}

func newPatriciaTreeString( ...string) *patriciaTree {
	 := make([][]byte, len())
	for ,  := range  {
		[] = []byte()
	}
	return newPatriciaTree(...)
}

func ( *patriciaTree) ( io.Reader) bool {
	 := make([]byte, .maxDepth)
	,  := io.ReadFull(, )
	return .root.match([:], true)
}

func ( *patriciaTree) ( io.Reader) bool {
	 := make([]byte, .maxDepth)
	,  := io.ReadFull(, )
	return .root.match([:], false)
}

type ptNode struct {
	prefix   []byte
	next     map[byte]*ptNode
	terminal bool
}

func newNode( [][]byte) *ptNode {
	if len() == 0 {
		return &ptNode{
			prefix:   []byte{},
			terminal: true,
		}
	}

	if len() == 1 {
		return &ptNode{
			prefix:   [0],
			terminal: true,
		}
	}

	,  := splitPrefix()
	 := &ptNode{
		prefix: ,
	}

	 := make(map[byte][][]byte)
	for ,  := range  {
		if len() == 0 {
			.terminal = true
			continue
		}
		[[0]] = append([[0]], [1:])
	}

	.next = make(map[byte]*ptNode)
	for ,  := range  {
		.next[] = ()
	}

	return 
}

func splitPrefix( [][]byte) ( []byte,  [][]byte) {
	if len() == 0 || len([0]) == 0 {
		return , 
	}

	if len() == 1 {
		return [0], [][]byte{{}}
	}

	for  := 0; ; ++ {
		var  byte
		 := true
		for ,  := range  {
			if len() <=  {
				 = false
				break
			}

			if  == 0 {
				 = []
				continue
			}

			if  != [] {
				 = false
				break
			}
		}

		if ! {
			break
		}

		 = append(, )
	}

	 = make([][]byte, 0, len())
	for ,  := range  {
		 = append(, [len():])
	}

	return , 
}

func ( *ptNode) ( []byte,  bool) bool {
	 := len(.prefix)
	if  > 0 {
		if  > len() {
			 = len()
		}
		if !bytes.Equal([:], .prefix) {
			return false
		}
	}

	if .terminal && ( || len(.prefix) == len()) {
		return true
	}

	if  >= len() {
		return false
	}

	,  := .next[[]]
	if ! {
		return false
	}

	if  == len() {
		 = [:]
	} else {
		 = [+1:]
	}
	return .(, )
}