# Web::Interface::Basic
# Copyright(c) 2002 MoonWolf <moonwolf@moonwolf.com>
require 'web/request'
require 'web/escape'

module Web
  module Interface
    class Basic
      # Parse query
      def parse_query(str,param)
        return if str.nil?
        str.scan(/([^=&;]+)(?:=([^&;]*))?[&;]?/n) {|key,value|
          key   = Web::unescape(key)
          value = Web::unescape(value) if value
          param.add key,value
        }
      end
      
      # Parse multipart/form-data
      def parse_multipart(io, boundary, param)
        boundary_start = "--"     << boundary << "\r\n"
        boundary_str   = "\r\n"   << boundary_start
        boundary_eof   = "\r\n--" << boundary << "--\r\n"
        boundary_str_size = boundary_str.size
        boundary_size  = boundary_eof.size
        read_size = (boundary_size < 65536 ? 65536 : boundary_size)
        eof_flag = false
        #
        buf = io.read(read_size) || ''
        if buf.index(boundary_start)==0
          buf = buf[boundary_start.size..-1]
        else
          raise "multipart/form-data parse error"
        end
        until eof_flag
          name = nil
          filename = nil
          content_type = nil
          
          #ヘッダの処理
          until buf=~/\r\n/mn
            raise "multipart/form-data eof error" if io.eof?
            buf << io.read(read_size)
          end
          buf  = $'.dup
          text = $`.dup
          loop do
            case text
            when /^Content-Disposition:/i
              hash = Web::Common::parse_semi($')
              name = hash["name"]
              filename = hash["filename"]
            when /^Content-Type:\s+/
              #Content-Type: text/plain
              content_type = $'
            when ''
              break
            end
            until buf=~/\r\n/mn
              STDERR.puts buf.inspect
              raise "multipart/form-data eof error" if io.eof?
              buf << io.read(read_size)
            end
            buf  = $'.dup
            text = $`.dup
          end
          
          #ボディの読み込み
          if filename
            #ファイルアップロード
            filedata = Web::Common::FileData.new(filename, content_type)
            open(filedata.path,'wb') {|f|
              while buf.size < boundary_size
                raise "multipart/form-data eof error" if io.eof?
                buf << io.read(read_size)
              end
              loop do
                if idx = buf.index(boundary_str)
                  f.write buf[0,idx]
                  buf = buf[idx+boundary_str_size..-1]
                  break
                elsif idx = buf.index(boundary_eof)
                  f.write buf[0,idx]
                  eof_flag = true
                  break
                else
                  idx = buf.size - boundary_str_size
                  if idx > 0
                    f.write buf[0,idx]
                    buf = buf[idx..-1]
                  end
                  while buf.size < boundary_size
                    raise "multipart/form-data eof error" if io.eof?
                    buf << io.read(read_size)
                  end
                end
              end
            }
            param.add name, filedata
          else
            #フォーム値
            value = ''
            while buf.size < boundary_size
              raise "multipart/form-data eof error" if io.eof?
              buf << io.read(read_size)
            end
            loop do
              if idx = buf.index(boundary_str)
                value << buf[0,idx]
                buf = buf[idx+boundary_str_size..-1]
                break
              elsif idx = buf.index(boundary_eof)
                value << buf[0,idx]
                eof_flag = true
                break
              else
                idx = buf.size - boundary_str_size
                if idx > 0
                  value << buf[0,idx]
                  buf = buf[idx..-1]
                end
                while buf.size < boundary_size
                  raise "multipart/form-data eof error" if io.eof?
                  buf << io.read(read_size)
                end
              end
            end
            param.add name, value
          end
          
        end
      end # parse_multipart
      
      # Interface
      def request(arg={})
      end
      
      def response(req,rsp)
        # Content-Length
        if rsp.body.instance_of?(String) && !rsp.content_length
          rsp.content_length = rsp.body.size.to_s
        end
        
        #
        set_session_id req, rsp
        
      end
      
      def each
        while req=request()
          yield req
        end
      end
      
      def get_session_id(req)
        key = '_session_id'
        req.session_id = req.cookies[key] || req.form[key]
      end

      def set_session_id(req, rsp)
        id=req.session_id
        return unless id
        key = '_session_id'
        unless rsp.cookies[key]
          cookie = Web::Cookie.new(key,id)
          rsp.cookies[key] = cookie
        end
      end
      
    end
  end # Interface
end # Web
