# Web::Request
# Copyright(c) 2002-2004 MoonWolf <moonwolf@moonwolf.com>
require 'web/common'
require 'web/cookie'

module Web
  # リクエスト
  class Request
    # クエリー値を保持する
    class QueryParam < Common::ParamHash
    end
    
    # フォームの値を保持する
    class FormParam < Common::ParamHash
    end
    
    def initialize
      # リクエストID(mod_unique_idがあれば、その値)
      @request_id = nil
      
      # セッションID
      @session_id = nil
      
      # サーバ環境
      @env    = Hash.new
      
      # メソッド(GET|POST|HEAD)
      @method = nil

      #
      @server_name = nil
      @server_protocol = nil
      @server_port = nil
      
      # PATH
      @path_info = nil
      @path_translated = nil
      
      # SCRIPT_NAME
      @script_name = nil
      
      # クエリー文字列
      @query_string = nil

      @remote_addr  = nil
      @remote_host  = nil
      @auth_type    = nil
      @remote_ident = nil
      @remote_user  = nil
      
      # HTTPリクエストヘッダに書かれている情報
      @header = Common::Header.new

      # HTTPリクエストボディ
      @body   = nil

      # クエリー文字列によるパラメータ
      @query  = QueryParam.new
      # フォームによるパラメータ
      @form   = FormParam.new
      # クッキー
      @cookies = Cookie::Cookies.new

      @https = false
    end
    attr_accessor :request_id, :session_id, :https
    attr_accessor :server_name, :server_protocol, :server_port
    attr_accessor :method, :query_string, :path_info, :path_translated, :script_name
    attr_accessor :remote_addr, :remote_host, :auth_type, :remote_ident, :remote_user
    attr_reader :env, :header, :query, :form, :cookies
    
    def cleanup
      @form.each {|key,value|
        value.each {|v|
          if v.respond_to? :cleanup
            v.cleanup
          end
        }
      }
    end
    
    def clear
      cleanup
      @query.clear
      @form.clear
    end
    
    %w(
      Accept
      Accept-Charset
      Accept-Encoding
      Accept-Language
      Authorization
      Content-Type
      Expect
      From
      Host
      If-Match
      If-Modified-Since
      If-None-Match
      If-Range
      If-Unmodified-Since
      Max-Forwards
      Proxy-Authorization
      Range
      Referer
      TE
      User-Agent
    ).each {|field|
      method = field.downcase.tr('-','_')
      eval( <<-END )
        def #{method}(index=0)
          @header['#{field}',index]
        end
        def #{method}=(value)
          @header['#{field}']=value
        end
      END
    }
    
    # Query/Form
    def has_key?(key)
      @query.has_key?(key) || @form.has_key?(key)
    end
    
    def include?(key)
      has_key?(key)
    end
    
    def key?(key)
      has_key?(key)
    end
    
    def member?(key)
      has_key?(key)
    end
    
    def get(key,index=0)
      return nil unless @query.has_key?(key) || @form.has_key?(key)
      val = @query[key, nil] + @form[key, nil]
      return val[index]
    end
    
    def [](key, index=0)
      if index
        get(key, index)
      else
        @query[key, nil] + @form[key, nil]
      end
    end
    
    #
    def body
      @body
    end

    def body=(text)
      @body = text.to_s
    end
    
    def query_encode()
      query = []
      @query.each {|key,values|
        values.each {|value|
          query << "#{Web::escape(key)}=#{Web::escape(value)}"
        }
      }
      @query_string = query.join("&")
    end
    
    def form_encode
      enctype = @header['content-type']
      unless enctype
        @header['content-type'] = enctype = "application/x-www-form-urlencoded"
      end
      case enctype
      when /multipart\/form-data/i
        boundary = "%012d" % (rand 1000000000000)
        @header['content-type'] = "multipart/form-data; boundary=#{boundary}"
        query = ""
        @form.each {|key,values|
          values.each {|value|
            query << "--" << boundary << "\r\n"
            if value.is_a? Web::Common::FileData
              query << "Content-Disposition: form-data; name=\"#{Web::escape(key)}\";filename=\"#{value.filename}\"\r\n"
            else
              query << "Content-Disposition: form-data; name=\"#{Web::escape(key)}\";\r\n"
            end
            query << "\r\n" << value.to_s << "\r\n"
          }
        }
        unless query.empty?
          query << "--" << boundary << "--\r\n"
        end
        @body = query
        @header['content-length'] = @body.size.to_s
      else
        query = []
        @form.each {|key,values|
          values.each {|value|
            query << "#{Web::escape(key)}=#{Web::escape(value)}"
          }
        }
        @body = query.join("&")
        @header['content-length'] = @body.size.to_s
      end
    end
  end # Request
end # Web
