#comment reconnaitre un directory qui ne finit pas par / ?

=begin
The base URI is established according to the rules of Section 5.1 and
parsed into the four main components as described in Section 3.  Note
that only the scheme component is required to be present in the base
URI; the other components may be empty or undefined.  A component is
undefined if its preceding separator does not appear in the URI
reference; the path component is never undefined, though it may be
empty.  The base URI's query component is not used by the resolution
algorithm and may be discarded.

=end

class MalformedUrl < StandardError
end


class JF_URL
  attr_reader :hostname,  :port, :path, :fragment, :userinfo
  attr_reader :other, :scheme, :authority, :query
  attr_reader :isrelative, :subtree

  private

  def lookup_http(adr)
#rfc2396: ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
#      %r{(([^:/]+):)?(//([^:/]+))?(:(\d+))?(/[^?;]+|[^?;]+$)?(;([^?]+))?(\?([^#]+))?(#(.+))?}.match(adr)
    %r{^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?}.match(adr)
      [$2,$4,$5,$7,$9]
  end


  def initialize(adr)

    @scheme,@authority, @path,@query ,@fragment = lookup_http(adr)
    raise MalformedUrl.new(adr) if @scheme.nil?
    @scheme.downcase!
    @authority.downcase! unless @authority.nil?
    @path='/' if @path.empty?
    parse_auth

  end

  def parse_auth
    if http? or ftp?
      %r{^([^@]*@)?([^:]*)(:(\d*))?}.match(@authority)
        @userinfo= $1
        @hostname = $2
        @port = $3
    end
  end


  def full_path
      #$debug.puts "full_path : #@path"
#    str << ";"+@params unless @params.nil?
    @path + (@query.nil? ? '' : "?" + @query)
  end

  def full_host
     #$debug.puts "full_host : #@protocol"
    str = @scheme+':'
    str << '//'+@authority if @authority
    str.downcase # str != nil?
  end

  protected

  def merge(adr)
    @isrelative = false
    @subtree = false
    if adr.empty?
      @isrelative = true
      return
    end

    scheme, authority, path, @query, @fragment = lookup_http(adr)

    if scheme
      @scheme = scheme.downcase
      @authority = authority
      @authority.downcase! unless @authority.nil?
      @path = path
      parse_auth
      return
    end

    if authority
      @authority = authority.downcase
      @path = path
      @path='/' if @path.empty?
      parse_auth
      return
    end
# relative
    @isrelative = true
    return if path.empty?


    if path[0] == ?/
      @path = path
    else
      @subtree = true
      @path[@path.rindex('/')+1..-1]= path
      @path.gsub!( %r{/./}, '/')
      @path.sub!( %r{/.$}, '/')
      while @path.sub!( %r{/[^./]+/\.\.}, '') ; end
      @path.sub!( %r{^/../}, '/')
    end

  end



  def addPath(source, target)
    if target[0] == ?/
      target
    elsif source[-1] == ?/
      source << target
    else
      source[source.rindex('/')+1..-1]= target
#	  $debug.puts "source: #{source}"
    end
  end


  public
  def relative(adr)
  #    $debug.puts "relative #{adr}"
    return self if adr.empty?
    nurl = JF_URL.new(to_s)
    nurl.merge(adr)
    return nurl
  end

  def set_location(adr)
   #  $debug.puts "set_location: #{to_s}"
    merge adr
  end

  def to_s
    to_k + frag
  end
  def frag
    @fragment.nil? ? '' : "#"+@fragment
  end
  def to_k
    full_host + full_path
  end

  def http?
    @scheme == 'http' or @scheme == 'https'
  end
  def file?
    @scheme == 'file'
  end
  def ftp?
    @scheme == 'ftp'
  end
  def mailto?
    @scheme == 'mailto'
  end
end

