### ----------------------------------------------------
### -- LibXML
### -- Licenses: Artistic-2.0
### -- Authors: David Warring
### -- File: lib/LibXML/Node.rakumod
### ----------------------------------------------------
### -- Chunk 2 of 2
 code
    and without comments
      =begin code :lang<xpath>
      (. | .//node() | .//@* | .//namespace::*)[not(self::comment())]
      =end code

    An optional parameter :$selector can be used to pass an L<LibXML::XPathContext> object defining the context for evaluation of $xpath-expression. This is useful
    for mapping namespace prefixes used in the XPath expression to namespace URIs.
    Note, however, that $node will be used as the context node for the evaluation,
    not the context node of :$selector.

    :v(v1.1) can be passed to specify v1.1 of the C14N specification. The `:$eclusve` flag is not applicable to this level.
=end pod

proto method Str(|) is also<serialize gist> handles <Int Num> {*}
multi method Str(LibXML::Node:U:) { nextsame }
multi method Str(LibXML::Node:D: :$C14N! where .so, |c) {
    self.canonicalize(|c);
}
=begin pod
    =head3 multi method Str :C14N

        multi method Str(Bool :C14N!, *%opts) returns Str

    `$node.Str( :C14N, |%opts)` is equivalent to `$node.canonicalize(|%opts)`
=end pod

multi method Str(LibXML::Node:D: :$html = self.isHTMLish, |c) is default {
    my $options = output-options(:$html, |c);
    self.raw.Str(:$options);
}
=begin pod
    =head3 multi method Str() returns Str

        method Str(
            Bool :$format, Bool :$tag-expansion,
            Bool :$skip-xml-declaration,
            Bool :$html = self.isHTMLish,
            LibXML::Config :$config, # defaults for :skip-xml-declaration and :tag-expansion
        ) returns Str;

    This method is similar to the method C<Str> of a L<LibXML::Document> but for a single node. It returns a string consisting of XML serialization of
    the given node and all its descendants.
=end pod

=begin pod
    =head3 method serialize

        method serialize(*%opts) returns Str

    An alias for Str. This function name was added to be more consistent
    with libxml2.
=end pod

method Blob(Str :$enc, Bool :$html = self.isHTMLish, |c) {
    my $options = output-options(:$html, |c);
    self.raw.Blob(:$enc, :$options);
}
=begin pod
    =head3 method Blob() returns Blob

        method Blob(
            xmlEncodingStr :$enc = 'UTF-8',
            Bool :$format,
            Bool :$tag-expansion,
            Bool :$html = self.isHTMLish,
        ) returns Blob;

   Returns a binary representation  of the XML
   node and its descendants encoded as `:$enc`.
=end pod

#| Data serialization
method ast returns Pair {
       self.ast-key => self.nodeValue
}
=begin pod
    =para
    This method performs a deep data-serialization of the node. The L<LibXML::Item> X<ast-to-xml()> function can then be used to create a deep copy of the node;

        use LibXML::Item :ast-to-xml;
        my $ast = $node.ast;
        my LibXML::Node $copy = ast-to-xml($ast);

=end pod

multi method save(IO::Handle :$io!, Bool :$format = False) {
    $io.write: self.Blob(:$format);
}

multi method save(IO() :io($path)!, |c) {
    my IO::Handle $io = $path.open(:bin, :w);
    $.save(:$io, |c);
    $io;
}

multi method save(IO() :file($io)!, |c) {
    $.save(:$io, |c).close;
}

method protect(&action) {
    self.lock // die "couldn't get lock";
    my $rv = try { &action(); }
    self.unlock;
    die $_ with $!;
    $rv;
}

#| DOM level-2 feature introspection
method isSupported(Str:D() $feature, Version $?) {
    $feature ~~ /:i ^[xml|html|core]$ /;
}
=para e.g. `$doc.issupported('HTML');

########################################################################
=head2 Namespace Methods

#| Returns the local name of a tag.
method localName is also<localname> returns Str { self.raw.name.subst(/^.*':'/,'') }
=para This is the part after the colon.

#| Returns the prefix of a tag
method prefix    returns Str { do with self.raw.ns {.prefix} // Str }
=para This is the part before the colon.

method addNamespace(Str $uri, NCName $prefix?) {
    $.setNamespace($uri, $prefix, :!activate);
}
method setNamespace(Str $uri, NCName $prefix?, Bool :$activate = True) {
    ? self.raw.setNamespace($uri, $prefix, :$activate);
}
method clearNamespace {
    ? self.raw.setNamespace(Str, Str, :activate);
}
method localNS(--> LibXML::Namespace) is dom-boxed {...}
method getNamespaces is also<namespaces> {
    self.iterate-list(LibXML::Namespace);
}
=begin pod
    =head3 method getNamespaces

        method getNamespaces returns LibXML::Node::List
        my LibXML::Namespace @ns = $node.getNamespaces;

    If a node has any namespaces defined, this function will return these
    namespaces. Note, that this will not return all namespaces that are in scope,
    but only the ones declared explicitly for that node.

    Although getNamespaces is available for all nodes, it only makes sense if used
    with element nodes.
=end pod

#| Returns the URI of the current namespace.
method namespaceURI(--> Str) is also<getNamespaceURI> { do with self.raw.ns {.href} // Str }

# handled by native method
=begin pod
    =head3 method lookupNamespaceURI

      method lookupNamespaceURI( NCName $prefix ) returns Str;

    Find a namespace URI by its prefix starting at the current node.

    =head3 method lookupNamespacePrefix

      method lookupNamespacePrefix( Str $URI ) returns NCName;

    Find a namespace prefix by its URI starting at the current node.

    I<NOTE> Only the namespace URIs are meant to be unique. The prefix is only document
    related. Also the document might have more than a single prefix defined for a
    namespace.

    =head3 method normalize

        method normalize() returns Str

    This function normalizes adjacent text nodes. This function is not as strict as
    libxml2's xmlTextMerge() function, since it will not free a node that is still
    referenced by Raku.

=end pod

########################################################################
=head2 Associative Interface

=begin pod
  =head3 methods AT-KEY, keys

      say $node.AT-KEY("species");
      #-OR-
      say $node<species>;

      say $node<species>.keys; # (disposition text() @name humps)
      say $node<species/humps>;
      say $node<species><humps>;

  This is a lightweight associative interface, based on xpath expressions. `$node.AT-KEY($foo)` is equivalent to `$node.findnodes($foo, :deref)`.

=end pod

multi method AT-KEY(NCName:D $tag) {
    self.iterate-set(LibXML::Node, self.raw.getChildrenByLocalName($tag), :deref);
}
multi method AT-KEY(QName:D $tag) {
    self.iterate-set(LibXML::Node, self.raw.getChildrenByTagName($tag), :deref);
}
multi method AT-KEY(Str:D $xpath) {
    $.xpath-context.AT-KEY($xpath);
}

method DELETE-KEY(Str:D $xpath) {
    my $unlinked = $.xpath-context.AT-KEY($xpath);
    .unlink for $unlinked.list;
    $unlinked;
}

method Hash(|c) handles <keys pairs kv> { $.childNodes(|c).Hash }

=begin pod

=head2 Copyright

2001-2007, AxKit.com Ltd.

2002-2006, Christian Glahn.

2006-2009, Petr Pajas.

=head2 License

This program is free software; you can redistribute it and/or modify it under
the terms of the Artistic License 2.0 L<http://www.perlfoundation.org/artistic_license_2_0>.

=end pod


