"""Persistent CookieJar based on MS Internet Explorer cookie database.

Copyright 2003-2004 John J Lee <jjl@pobox.com>

This code is free software; you can redistribute it and/or modify it under
the terms of the BSD License (see the file COPYING included with the
distribution).

**********************************************************************
THIS DOESN'T WORK!

It's just a sketch, to check the base class is OK.

**********************************************************************

"""

from ClientCookie import MSIEBase, CookieJar
from _Util import time2netscape

def set_cookie_hdr_from_cookie(cookie):
    params = []
    if cookie.name is not None:
        params.append("%s=%s" % cookie.name, cookie.value)
    else:
        params.append(cookie.name)
    if cookie.expires:
        params.append("expires=" % time2netscape(cookie.expires))
    if cookie.domain_specified:
        params.append("Domain=%s" % cookie.domain)
    if cookie.path_specified:
        params.append("path=%s" % cookie.path)
    if cookie.port_specified:
        if cookie.port is None:
            params.append("Port")
        else:
            params.append("Port=%s" % cookie.port)
    if cookie.secure:
        params.append("secure")
##     if cookie.comment:
##         params.append("Comment=%s" % cookie.comment)
##     if cookie.comment_url:
##         params.append("CommentURL=%s" % cookie.comment_url)
    return "; ".join(params)

class MSIEDBCookieJar(MSIEBase, CookieJar):
    """A CookieJar that relies on MS Internet Explorer's cookie database.

    XXX Require ctypes or write C extension?  win32all probably requires
    latter.

    **********************************************************************
    THIS DOESN'T WORK!

    It's just a sketch, to check the base class is OK.

    **********************************************************************

    MSIEDBCookieJar, unlike MSIECookieJar, keeps no state for itself, but
    relies on the MS Internet Explorer's cookie database.  It uses the win32
    API functions InternetGetCookie() and InternetSetCookie(), from the wininet
    library.

    Note that MSIE itself may impose additional conditions on cookie processing
    on top of that done by CookiePolicy.  For cookie setting, the class tries
    to foil that by providing the request details and Set-Cookie header it
    thinks MSIE wants to see.  For returning cookies to the server, it's up to
    MSIE.

    Note that session cookies ARE NOT written to disk and won't be accessible
    from other processes.  .clear_session_cookies() has no effect.

    .clear_expired_cookies() has no effect: MSIE is responsible for this.

    .clear() will raise NotImplementedError unless all three arguments are
    given.

    """
    def __init__(self, policy=None):
        MSIEBase.__init__(self)
        FileCookieJar.__init__(self, policy)
    def clear_session_cookies(self): pass
    def clear_expired_cookies(self): pass
    def clear(self, domain=None, path=None, name=None):
        if None in [domain, path, name]:
            raise NotImplementedError()
        # XXXX
        url = self._fake_url(domain, path)
        hdr = "%s=; domain=%s; path=%s; max-age=0" % (name, domain, path)
        r = windll.InternetSetCookie(url, None, hdr)
        # XXX return value of InternetSetCookie?
    def _fake_url(self, domain, path):
        # to convince MSIE that Set-Cookie is OK
        return "http://%s%s" % (domain, path)
    def set_cookie(self, cookie):
        # XXXX
        url = self._fake_url(cookie.domain, cookie.path)
        r = windll.InternetSetCookie(
            url, None, set_cookie_hdr_from_cookie(cookie))
        # XXX return value of InternetSetCookie?
    def add_cookie_header(self, request, unverifiable=False):
        # XXXX
        cookie_header = windll.InternetGetCookie(request.get_full_url())
        # XXX return value of InternetGetCookie?
        request.add_unredirected_header(cookie_header)
    def __iter__(self):
        self._load_index_dat()
        return CookieJar.__iter__(self)
    def _cookies_for_request(self, request):
        raise NotImplementedError()  # XXXX
    def _cookies_for_domain(self, domain, request):
        #raise NotImplementedError()  # XXXX
        debug("Checking %s for cookies to return", domain)
        if not self._policy.domain_return_ok(domain, request):
            return []

        # XXXX separate out actual loading of cookie data, so only index.dat is
        #  read in ._load_index_dat(), and ._really_load() calls that, then
        #  ._delayload_domain for all domains if not self.delayload.
        #  We then just call ._load_index_dat()
        self._delayload = False
        self._really_load()

        cookies_by_path = self._cookies.get(domain)
        if cookies_by_path is None:
            return []

        cookies = []
        for path in cookies_by_path.keys():
            if not self._policy.path_return_ok(path, request, unverifiable):
                continue
            for name, cookie in cookies_by_path[path].items():
                if not self._policy.return_ok(cookie, request, unverifiable):
                    debug("   not returning cookie")
                    continue
                debug("   it's a match")
                cookies.append(cookie)

        return cookies

