class ActiveLdap::DistinguishedName::Parser

def attribute_type_is_missing

def attribute_type_is_missing
  invalid_dn(_("attribute type is missing"))
end

def attribute_value_is_missing

def attribute_value_is_missing
  invalid_dn(_("attribute value is missing"))
end

def collect_pairs(scanner)

def collect_pairs(scanner)
  result = ""
  while scanner.scan(PAIR_RE)
    if scanner[2]
      result << [scanner[2].hex].pack("C*")
    else
      result << scanner[1]
    end
  end
  result.force_encoding("utf-8") if result.respond_to?(:force_encoding)
  result
end

def found_unmatched_quotation

def found_unmatched_quotation
  invalid_dn(_("found unmatched quotation"))
end

def initialize(source)

def initialize(source)
  @dn = nil
  source = source.to_s if source.is_a?(DN)
  unless source.is_a?(String)
    raise DistinguishedNameInputInvalid.new(source)
  end
  @source = source
end

def invalid_dn(reason)

def invalid_dn(reason)
  DistinguishedNameInvalid.new(@source, reason)
end

def name_component_is_missing

def name_component_is_missing
  invalid_dn(_("name component is missing"))
end

def parse

def parse
  return @dn if @dn
  rdns = []
  scanner = StringScanner.new(@source)
  scanner.scan(/\s*/)
  raise rdn_is_missing if scanner.scan(/\s*\+\s*/)
  raise name_component_is_missing if scanner.scan(/\s*,\s*/)
  rdn = {}
  until scanner.eos?
    type = scan_attribute_type(scanner)
    skip_attribute_type_and_value_separator(scanner)
    value = scan_attribute_value(scanner)
    rdn[type] = value
    if scanner.scan(/\s*\+\s*/)
      raise rdn_is_missing if scanner.eos?
    elsif scanner.scan(/\s*\,\s*/)
      rdns << rdn
      rdn = {}
      raise name_component_is_missing if scanner.eos?
    else
      scanner.scan(/\s*/)
      rdns << rdn if scanner.eos?
    end
  end
  @dn = DN.new(*rdns)
  @dn
end

def rdn_is_missing

def rdn_is_missing
  invalid_dn(_("relative distinguished name (RDN) is missing"))
end

def scan_attribute_type(scanner)

def scan_attribute_type(scanner)
  raise attribute_type_is_missing unless scanner.scan(ATTRIBUTE_TYPE_RE)
  scanner[1]
end

def scan_attribute_value(scanner)



def scan_attribute_value(scanner)
  if scanner.scan(HEX_STRING_RE)
    value = scanner[1].scan(/../).collect do |hex_pair|
      hex_pair.hex
    end.pack("C*")
  elsif scanner.scan(/\"/)
    value = scan_quoted_attribute_value(scanner)
  else
    value = scan_not_quoted_attribute_value(scanner)
  end
  raise attribute_value_is_missing if value.blank?
  value
end

def scan_not_quoted_attribute_value(scanner)

def scan_not_quoted_attribute_value(scanner)
  result = ""
  until scanner.eos?
    prev_size = result.size
    pairs = collect_pairs(scanner)
    strings = scanner.scan(STRING_CHARS_RE)
    result << pairs if !pairs.nil? and !pairs.empty?
    unless strings.nil?
      if scanner.peek(1) == ","
        result << strings.rstrip
      else
        result << strings
      end
    end
    break if prev_size == result.size
  end
  result
end

def scan_quoted_attribute_value(scanner)

def scan_quoted_attribute_value(scanner)
  result = ""
  until scanner.scan(/\"/)
    scanner.scan(/([^\\\"]*)/)
    quoted_strings = scanner[1]
    pairs = collect_pairs(scanner)
    if scanner.eos? or (quoted_strings.empty? and pairs.empty?)
      raise found_unmatched_quotation
    end
    result << quoted_strings
    result << pairs
  end
  result
end

def skip_attribute_type_and_value_separator(scanner)

def skip_attribute_type_and_value_separator(scanner)
  raise attribute_value_is_missing unless scanner.scan(/\s*=\s*/)
end