# Web::Common
# Copyright(c) 2002 MoonWolf <moonwolf@moonwolf.com>
require "socket"
require "thread"
require 'digest/md5'
require 'web/escape'

module Web
  module Common
    
    MUTEX = Mutex.new
    @@counter = rand(65536)
    HOST = Socket.gethostbyname(Socket.gethostname)[3]
    
    def self.unique_id()
      tm = Time.now.gmtime
      key = [tm.tv_sec, tm.tv_usec % 65536, Process.pid, Thread.current.id].pack("NnNN")
      key << HOST
      MUTEX.synchronize {
        @@counter = (@@counter + 1) % 65536
        key << [@@counter].pack("n")
      }
      
      [key].pack("m").chop.tr("+/","@-")
    end
    
    # Parse Semi-colon delimited values
    #  key1=value ; key2="value" ; key3
    #    => {"key1"="value", "key2"=>"value", "key3"=>nil}
    def self.parse_semi(str)
      hash = Hash.new
      str.scan(/(\w+)(?:\s*=\s*(?:(\w+)|"(.*?)"))?/) {
        hash[$1] = $2 || $3
      }
      hash
    end

    # Time to RFC1123 String
    def self.rfc1123date(tm)
      tm = tm.clone.gmtime
      tm.strftime("%a, %d %b %Y %H:%M:%S GMT")
    end

    #
    class ParamHash
      include Enumerable
      #
      def initialize
        @h = Hash.new
      end

      def to_hash
        hash = {}
        @h.each {|key,values|
          hash[key] = values.first
        }
        hash
      end

      private
      #キーを正規化する
      def normalize(key)
        key
      end

      public
      # for Enumberable
      def each
        return self unless block_given?
        @h.each {|k,v|
          yield k,v
        }
        self
      end

      # キーから値を１つ取り出す
      # 値が存在しなければnilを返す
      def get(key,index=0)
        key = normalize(key)
        return nil unless @h.has_key?(key)
        return @h[key][index]
      end
      
      # キーに値を設定する
      def set(key, value, index=0)
        key = normalize(key)
        arr = @h.fetch(key, [])
        arr[index] = value
        @h[key] = arr
      end
      
      def [](key, index=0)
        key = normalize(key)
        if index
          get(key, index)
        else
          @h.fetch(key,[])
        end
      end
      
      def []=(key, *arg)
        key = normalize(key)
        if arg.size>1
          index = arg.shift
          if index
            set(key, arg.first, index)
          else
            @h[key] = @h.fetch(key,[]) << arg
          end
        else
          set(key, arg.first, 0)
        end
      end

      def add(key,value)
        key = normalize(key)
        arr = @h.fetch(key, [])
        arr << value
        @h[key] = arr
      end

      def clear
        @h.clear
      end

      def delete(key)
        key = normalize(key)
        @h.delete(key)
      end

      def has_key?(key)
        key = normalize(key)
        @h.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 keys
        @h.keys
      end

      def size
        @h.size
      end

      def length
        @h.length
      end

    end # ParamHash

    # HTTPヘッダーを保持する
    class Header < ParamHash
      private
      def normalize(key)
        key.downcase
      end
    end


    #アップロードされたファイル
    class FileData
      def initialize(filename, content_type)
        @filename     = filename
        @content_type = content_type
        basename = 'web_' + Web::Common::unique_id
        @path = File.join('/tmp',basename)
      end
      attr_accessor :filename, :content_type, :path
      
      def cleanup
        File.unlink @path
      end
      
      def to_s
        str = nil
        open(@path,'rb') {|f|
          str = f.read || ''
        }
        str
      end
      
    end

  end # Common
end # Web
