package httphead

import (
	
	
)

// Version contains protocol major and minor version.
type Version struct {
	Major int
	Minor int
}

// RequestLine contains parameters parsed from the first request line.
type RequestLine struct {
	Method  []byte
	URI     []byte
	Version Version
}

// ResponseLine contains parameters parsed from the first response line.
type ResponseLine struct {
	Version Version
	Status  int
	Reason  []byte
}

// SplitRequestLine splits given slice of bytes into three chunks without
// parsing.
func ( []byte) (, ,  []byte) {
	return split3(, ' ')
}

// ParseRequestLine parses http request line like "GET / HTTP/1.0".
func ( []byte) ( RequestLine,  bool) {
	var  int
	for  = 0;  < len(); ++ {
		 := []
		if !OctetTypes[].IsToken() {
			if  > 0 &&  == ' ' {
				break
			}
			return
		}
	}
	if  == len() {
		return
	}

	var  []byte
	.Method = [:]
	.URI,  = split2([+1:], ' ')
	if len(.URI) == 0 {
		return
	}
	if , ,  := ParseVersion();  {
		.Version.Major = 
		.Version.Minor = 
		return , true
	}

	return , false
}

// SplitResponseLine splits given slice of bytes into three chunks without
// parsing.
func ( []byte) (, ,  []byte) {
	return split3(, ' ')
}

// ParseResponseLine parses first response line into ResponseLine struct.
func ( []byte) ( ResponseLine,  bool) {
	var (
		  []byte
		 []byte
	)
	, , .Reason = split3(, ' ')
	if , ,  := ParseVersion();  {
		.Version.Major = 
		.Version.Minor = 
	} else {
		return , false
	}
	if ,  := IntFromASCII();  {
		.Status = 
	} else {
		return , false
	}
	// TODO(gobwas): parse here r.Reason fot TEXT rule:
	//   TEXT = <any OCTET except CTLs,
	//           but including LWS>
	return , true
}

var (
	httpVersion10     = []byte("HTTP/1.0")
	httpVersion11     = []byte("HTTP/1.1")
	httpVersionPrefix = []byte("HTTP/")
)

// ParseVersion parses major and minor version of HTTP protocol.
// It returns parsed values and true if parse is ok.
func ( []byte) (,  int,  bool) {
	switch {
	case bytes.Equal(, httpVersion11):
		return 1, 1, true
	case bytes.Equal(, httpVersion10):
		return 1, 0, true
	case len() < 8:
		return
	case !bytes.Equal([:5], httpVersionPrefix):
		return
	}

	 = [5:]

	 := bytes.IndexByte(, '.')
	if  == -1 {
		return
	}
	,  = IntFromASCII([:])
	if ! {
		return
	}
	,  = IntFromASCII([+1:])
	if ! {
		return
	}

	return , , true
}

// ReadLine reads line from br. It reads until '\n' and returns bytes without
// '\n' or '\r\n' at the end.
// It returns err if and only if line does not end in '\n'. Note that read
// bytes returned in any case of error.
//
// It is much like the textproto/Reader.ReadLine() except the thing that it
// returns raw bytes, instead of string. That is, it avoids copying bytes read
// from br.
//
// textproto/Reader.ReadLineBytes() is also makes copy of resulting bytes to be
// safe with future I/O operations on br.
//
// We could control I/O operations on br and do not need to make additional
// copy for safety.
func ( *bufio.Reader) ([]byte, error) {
	var  []byte
	for {
		,  := .ReadSlice('\n')
		if  == bufio.ErrBufferFull {
			// Copy bytes because next read will discard them.
			 = append(, ...)
			continue
		}
		// Avoid copy of single read.
		if  == nil {
			 = 
		} else {
			 = append(, ...)
		}
		if  != nil {
			return , 
		}
		// Size of line is at least 1.
		// In other case bufio.ReadSlice() returns error.
		 := len()
		// Cut '\n' or '\r\n'.
		if  > 1 && [-2] == '\r' {
			 = [:-2]
		} else {
			 = [:-1]
		}
		return , nil
	}
}

// ParseHeaderLine parses HTTP header as key-value pair. It returns parsed
// values and true if parse is ok.
func ( []byte) (,  []byte,  bool) {
	 := bytes.IndexByte(, ':')
	if  == -1 {
		return
	}
	 = trim([:])
	for ,  := range  {
		if !OctetTypes[].IsToken() {
			return nil, nil, false
		}
	}
	 = trim([+1:])
	return , , true
}

// IntFromASCII converts ascii encoded decimal numeric value from HTTP entities
// to an integer.
func ( []byte) ( int,  bool) {
	// ASCII numbers all start with the high-order bits 0011.
	// If you see that, and the next bits are 0-9 (0000 - 1001) you can grab those
	// bits and interpret them directly as an integer.
	var  int
	if  = len();  < 1 {
		return 0, false
	}
	for  := 0;  < ; ++ {
		if []&0xf0 != 0x30 {
			return 0, false
		}
		 += int([]&0xf) * pow(10, --1)
	}
	return , true
}

const (
	toLower = 'a' - 'A'      // for use with OR.
	toUpper = ^byte(toLower) // for use with AND.
)

// CanonicalizeHeaderKey is like standard textproto/CanonicalMIMEHeaderKey,
// except that it operates with slice of bytes and modifies it inplace without
// copying.
func ( []byte) {
	 := true
	for ,  := range  {
		if  && 'a' <=  &&  <= 'z' {
			[] &= toUpper
		} else if ! && 'A' <=  &&  <= 'Z' {
			[] |= toLower
		}
		 =  == '-'
	}
}

// pow for integers implementation.
// See Donald Knuth, The Art of Computer Programming, Volume 2, Section 4.6.3
func pow(,  int) int {
	 := 1
	for  > 0 {
		if &1 != 0 {
			 *= 
		}
		 >>= 1
		 *= 
	}
	return 
}

func split3( []byte,  byte) (, ,  []byte) {
	 := bytes.IndexByte(, )
	 := bytes.IndexByte([+1:], )
	if  == -1 ||  == -1 {
		return , nil, nil
	}
	 +=  + 1
	return [:], [+1 : ], [+1:]
}

func split2( []byte,  byte) (,  []byte) {
	 := bytes.IndexByte(, )
	if  == -1 {
		return , nil
	}
	return [:], [+1:]
}

func trim( []byte) []byte {
	var ,  int
	for  = 0;  < len() && ([] == ' ' || [] == '\t'); {
		++
	}
	for  = len();  >  && ([-1] == ' ' || [-1] == '\t'); {
		--
	}
	return [:]
}