require 'uri'
module Web
  class Agent
    class CookieManager
      def initialize
        @db=Hash.new # @db['www.moonwolf.com']=Web::Cookie::Cookies
      end
      
      def search(url)
        u = URI.parse(url)
        result = []
        time = Time.now
        tokens = u.host.split(/\./)
        while tokens.size >= 2
          domain = tokens.join('.')
          if cookies = @db[domain]
            cookies.each {|name,cookie_ary|
              cookie_ary.each {|cookie|
                if u.path.index(cookie.path)==0 && (cookie.expires==nil || cookie.expires > time)
                  result << cookie
                end
              }
            }
          end
          break if tokens.last=~/\A\d+\z/
          tokens.shift
        end
        result
      end
      
      def get(req)
        time = Time.now
        req.header.delete 'Cookie'
        tokens = req.server_name.split(/\./) # ["www","moonwolf","com"]
        while tokens.size >= 2
          domain = tokens.join('.')
          if cookies = @db[domain]
            cookies.each {|name,cookie_ary|
              cookie_ary.each {|cookie|
                if (cookie.path==nil || req.script_name.index(cookie.path)==0) && (cookie.expires==nil || cookie.expires > time)
                  req.header.add 'Cookie', cookie.to_request_header
                end
              }
            }
          end
          break if tokens.last=~/\A\d+\z/
          tokens.shift
        end
      end

      def set(req, rsp)
        rsp.cookies.each {|name,cookie_ary|
          cookie_ary.each {|cookie|
            domain = cookie.domain.sub(/\A\./,'')
            next unless Regexp.compile(Regexp.quote(domain)+"\\z").match(req.server_name)
            if old_cookies = @db[domain]
              if old = old_cookies[name,nil]
                match = false
                old.each {|old_cookie|
                  if cookie.name == old_cookie.name && cookie.path == old_cookie.path
                    old_cookie.value = cookie.value
                    old_cookie.expires = cookie.expires
                    matche = true
                    break
                  end
                }
                unless match
                  old_cookies.add name, cookie
                end
              else
                old_cookies.add name, cookie
              end
            else
              cookies = Web::Cookie::Cookies.new
              cookies.add name, cookie
              @db[domain] = cookies
            end
          }
        }
      end

      def clear
        @db.clear
      end

      def cleanup
        time = Time.now
        @db.each {|domain,cookies|
          cookies.keys.each {|key|
            ary = cookies[key,nil]
            ary.delete_if {|cookie|
              (cookie.expires == nil) || (cookie.expires < time)
            }
            if ary.empty?
              cookies.delete(key)
            end
          }
        }
      end
    end # CookieManager
  end # Agent
end # Web
