require 'openid/fetchers'

module OpenID
  module Yadis
    module XRI

      # The '(' is for cross-reference authorities, and hopefully has a
      # matching ')' somewhere.
      XRI_AUTHORITIES = ["!", "=", "@", "+", "$", "("]

      def self.identifier_scheme(identifier)
        if (!identifier.nil? and
            identifier.length > 0 and
            (identifier.match('^xri://') or
             XRI_AUTHORITIES.member?(identifier[0].chr)))
          return :xri
        else
          return :uri
        end
      end

      # Transform an XRI reference to an IRI reference.  Note this is
      # not not idempotent, so do not apply this to an identifier more
      # than once.  XRI Syntax section 2.3.1
      def self.to_iri_normal(xri)
        iri = xri.dup
        iri.insert(0, 'xri://') if not iri.match('^xri://')
        return escape_for_iri(iri)
      end

      # Note this is not not idempotent, so do not apply this more than
      # once.  XRI Syntax section 2.3.2
      def self.escape_for_iri(xri)
        esc = xri.dup
        # encode all %
        esc.gsub!(/%/, '%25')
        esc.gsub!(/\((.*?)\)/) { |xref_match|
          xref_match.gsub(/[\/\?\#]/) { |char_match|
            CGI::escape(char_match)
          }
        }
        return esc
      end

      # Transform an XRI reference to a URI reference.  Note this is not
      # not idempotent, so do not apply this to an identifier more than
      # once.  XRI Syntax section 2.3.1
      def self.to_uri_normal(xri)
        return iri_to_uri(to_iri_normal(xri))
      end

      # RFC 3987 section 3.1
      def self.iri_to_uri(iri)
        uri = iri.dup
        # for char in ucschar or iprivate
        # convert each char to %HH%HH%HH (as many %HH as octets)
        return uri
      end

      def self.provider_is_authoritative(provider_id, canonical_id)
        lastbang = canonical_id.rindex('!')
        return false unless lastbang
        parent = canonical_id[0...lastbang]
        return parent == provider_id
      end

      def self.root_authority(xri)
        xri = xri[6..-1] if xri.index('xri://') == 0
        authority = xri.split('/', 2)[0]
        if authority[0].chr == '('
          root = authority[0...authority.index(')')+1]
        elsif XRI_AUTHORITIES.member?(authority[0].chr)
          root = authority[0].chr
        else
          root = authority.split(/[!*]/)[0]
        end

        self.make_xri(root)
      end

      def self.make_xri(xri)
        if xri.index('xri://') != 0
          xri = 'xri://' + xri
        end
        return xri
      end
    end
  end
end
