# Path: bustard/constants.py
# HTTP_STATUS_CODES = {
#     100:    'Continue',
#     101:    'Switching Protocols',
#     102:    'Processing',
#     200:    'OK',
#     201:    'Created',
#     202:    'Accepted',
#     203:    'Non Authoritative Information',
#     204:    'No Content',
#     205:    'Reset Content',
#     206:    'Partial Content',
#     207:    'Multi Status',
#     226:    'IM Used',              # see RFC 3229
#     300:    'Multiple Choices',
#     301:    'Moved Permanently',
#     302:    'Found',
#     303:    'See Other',
#     304:    'Not Modified',
#     305:    'Use Proxy',
#     307:    'Temporary Redirect',
#     400:    'Bad Request',
#     401:    'Unauthorized',
#     402:    'Payment Required',     # unused
#     403:    'Forbidden',
#     404:    'Not Found',
#     405:    'Method Not Allowed',
#     406:    'Not Acceptable',
#     407:    'Proxy Authentication Required',
#     408:    'Request Timeout',
#     409:    'Conflict',
#     410:    'Gone',
#     411:    'Length Required',
#     412:    'Precondition Failed',
#     413:    'Request Entity Too Large',
#     414:    'Request URI Too Long',
#     415:    'Unsupported Media Type',
#     416:    'Requested Range Not Satisfiable',
#     417:    'Expectation Failed',
#     418:    'I\'m a teapot',  # see RFC 2324
#     422:    'Unprocessable Entity',
#     423:    'Locked',
#     424:    'Failed Dependency',
#     426:    'Upgrade Required',
#     428:    'Precondition Required',  # see RFC 6585
#     429:    'Too Many Requests',
#     431:    'Request Header Fields Too Large',
#     449:    'Retry With',  # proprietary MS extension
#     451:    'Unavailable For Legal Reasons',
#     500:    'Internal Server Error',
#     501:    'Not Implemented',
#     502:    'Bad Gateway',
#     503:    'Service Unavailable',
#     504:    'Gateway Timeout',
#     505:    'HTTP Version Not Supported',
#     507:    'Insufficient Storage',
#     510:    'Not Extended'
# }
# 
# Path: bustard/utils.py
# def json_dumps_default(obj):
#     if isinstance(obj, collections.UserDict):
#         return obj.to_dict()
#     return obj
# 
# class MultiDict(collections.UserDict):
# 
#     def getlist(self, key):
#         return self.data[key]
# 
#     def to_dict(self):
#         return self.data
# 
#     def __getitem__(self, key):
#         return self.data[key][-1]
# 
#     def __setitem__(self, key, value):
#         if isinstance(value, (list, tuple)):
#             self.data[key] = list(value)
#         else:
#             self.data[key] = [value]
# 
#     def __repr__(self):
#         return '{}({})'.format(self.__class__.__name__, self.data)
# 
# def parse_query_string(query_string, encoding='utf-8'):
#     query_dict = collections.defaultdict(list)
#     for query_item in query_string.split('&'):
#         if '=' not in query_item:
#             continue
#         keyword, value = query_item.split('=', 1)
#         value = urllib.parse.unquote_plus(value)
#         query_dict[keyword].append(to_text(value, encoding=encoding))
#     return query_dict
# 
# def to_header_key(key):
#     return '-'.join(x.capitalize() for x in key.split('-'))
# 
# def to_text(st, encoding='utf-8'):
#     if isinstance(st, str):
#         return st
#     elif isinstance(st, collections.ByteString):
#         return st.decode(encoding)
#     else:
#         return str(st)
# 
# def to_bytes(bt, encoding='utf-8'):
#     if isinstance(bt, collections.ByteString):
#         return bt
#     elif isinstance(bt, str):
#         return bt.encode(encoding)
#     else:
#         return bytes(bt)
# 
# def parse_basic_auth_header(value):
#     try:
#         auth_type, auth_info = to_bytes(value).split(None, 1)
#     except ValueError:
#         return
#     auth_type = auth_type.lower()
# 
#     if auth_type == b'basic':
#         try:
#             username, password = base64.b64decode(auth_info).split(b':', 1)
#         except (binascii.Error, ValueError):
#             return
# 
#         return Authorization(
#             to_text(auth_type),
#             username=to_text(username),
#             password=to_text(password)
#         )


import cgi
import io
import json
from http.cookies import SimpleCookie
from .constants import HTTP_STATUS_CODES
from .utils import (
    json_dumps_default, MultiDict, parse_query_string,
    to_header_key, to_text, to_bytes, parse_basic_auth_header
)

    @property
    def cookies(self):
        return self._cookies

    def set_cookie(self, key, value='', max_age=None, expires=None, path='/',
                   domain=None, secure=False, httponly=False):
        cookie = cookie_dump(
            key, value=value, max_age=max_age, expires=expires, path=path,
            domain=domain, secure=secure, httponly=httponly
        )
        self._cookies.load(cookie)

    def delete_cookie(self, key, max_age=0,
                      expires='Thu, 01-Jan-1970 00:00:00 GMT'):
        self.set_cookie(key, value='', max_age=max_age, expires=expires)

    @property
    def headers_list(self):
        # normal headers
        headers_list = list(self.headers.to_list())

        # set-cookies
        headers_list.extend(
            ('Set-Cookie', value.OutputString())
            for value in self.cookies.values()
        )
        return headers_list

    def json(self):

# Path: bustard/constants.py
# HTTP_STATUS_CODES = {
#     100:    'Continue',
#     101:    'Switching Protocols',
#     102:    'Processing',
#     200:    'OK',
#     201:    'Created',
#     202:    'Accepted',
#     203:    'Non Authoritative Information',
#     204:    'No Content',
#     205:    'Reset Content',
#     206:    'Partial Content',
#     207:    'Multi Status',
#     226:    'IM Used',              # see RFC 3229
#     300:    'Multiple Choices',
#     301:    'Moved Permanently',
#     302:    'Found',
#     303:    'See Other',
#     304:    'Not Modified',
#     305:    'Use Proxy',
#     307:    'Temporary Redirect',
#     400:    'Bad Request',
#     401:    'Unauthorized',
#     402:    'Payment Required',     # unused
#     403:    'Forbidden',
#     404:    'Not Found',
#     405:    'Method Not Allowed',
#     406:    'Not Acceptable',
#     407:    'Proxy Authentication Required',
#     408:    'Request Timeout',
#     409:    'Conflict',
#     410:    'Gone',
#     411:    'Length Required',
#     412:    'Precondition Failed',
#     413:    'Request Entity Too Large',
#     414:    'Request URI Too Long',
#     415:    'Unsupported Media Type',
#     416:    'Requested Range Not Satisfiable',
#     417:    'Expectation Failed',
#     418:    'I\'m a teapot',  # see RFC 2324
#     422:    'Unprocessable Entity',
#     423:    'Locked',
#     424:    'Failed Dependency',
#     426:    'Upgrade Required',
#     428:    'Precondition Required',  # see RFC 6585
#     429:    'Too Many Requests',
#     431:    'Request Header Fields Too Large',
#     449:    'Retry With',  # proprietary MS extension
#     451:    'Unavailable For Legal Reasons',
#     500:    'Internal Server Error',
#     501:    'Not Implemented',
#     502:    'Bad Gateway',
#     503:    'Service Unavailable',
#     504:    'Gateway Timeout',
#     505:    'HTTP Version Not Supported',
#     507:    'Insufficient Storage',
#     510:    'Not Extended'
# }
# 
# Path: bustard/utils.py
# def json_dumps_default(obj):
#     if isinstance(obj, collections.UserDict):
#         return obj.to_dict()
#     return obj
# 
# class MultiDict(collections.UserDict):
# 
#     def getlist(self, key):
#         return self.data[key]
# 
#     def to_dict(self):
#         return self.data
# 
#     def __getitem__(self, key):
#         return self.data[key][-1]
# 
#     def __setitem__(self, key, value):
#         if isinstance(value, (list, tuple)):
#             self.data[key] = list(value)
#         else:
#             self.data[key] = [value]
# 
#     def __repr__(self):
#         return '{}({})'.format(self.__class__.__name__, self.data)
# 
# def parse_query_string(query_string, encoding='utf-8'):
#     query_dict = collections.defaultdict(list)
#     for query_item in query_string.split('&'):
#         if '=' not in query_item:
#             continue
#         keyword, value = query_item.split('=', 1)
#         value = urllib.parse.unquote_plus(value)
#         query_dict[keyword].append(to_text(value, encoding=encoding))
#     return query_dict
# 
# def to_header_key(key):
#     return '-'.join(x.capitalize() for x in key.split('-'))
# 
# def to_text(st, encoding='utf-8'):
#     if isinstance(st, str):
#         return st
#     elif isinstance(st, collections.ByteString):
#         return st.decode(encoding)
#     else:
#         return str(st)
# 
# def to_bytes(bt, encoding='utf-8'):
#     if isinstance(bt, collections.ByteString):
#         return bt
#     elif isinstance(bt, str):
#         return bt.encode(encoding)
#     else:
#         return bytes(bt)
# 
# def parse_basic_auth_header(value):
#     try:
#         auth_type, auth_info = to_bytes(value).split(None, 1)
#     except ValueError:
#         return
#     auth_type = auth_type.lower()
# 
#     if auth_type == b'basic':
#         try:
#             username, password = base64.b64decode(auth_info).split(b':', 1)
#         except (binascii.Error, ValueError):
#             return
# 
#         return Authorization(
#             to_text(auth_type),
#             username=to_text(username),
#             password=to_text(password)
#         )


# Path: bustard/http.py
import cgi
import io
import json
from http.cookies import SimpleCookie
from .constants import HTTP_STATUS_CODES
from .utils import (
    json_dumps_default, MultiDict, parse_query_string,
    to_header_key, to_text, to_bytes, parse_basic_auth_header
)


    @property
    def cookies(self):
        return self._cookies

    def set_cookie(self, key, value='', max_age=None, expires=None, path='/',
                   domain=None, secure=False, httponly=False):
        cookie = cookie_dump(
            key, value=value, max_age=max_age, expires=expires, path=path,
            domain=domain, secure=secure, httponly=httponly
        )
        self._cookies.load(cookie)

    def delete_cookie(self, key, max_age=0,
                      expires='Thu, 01-Jan-1970 00:00:00 GMT'):
        self.set_cookie(key, value='', max_age=max_age, expires=expires)

    @property
    def headers_list(self):
        # normal headers
        headers_list = list(self.headers.to_list())

        # set-cookies
        headers_list.extend(
            ('Set-Cookie', value.OutputString())
            for value in self.cookies.values()
        )
        return headers_list

    def json(self):

        return json.loads(to_text(self.data))