//
// Copyright (c) 2008, Brian Frank and Andy Frank
// Licensed under the Academic Free License version 3.0
//
// History:
//    7 Nov 08  Brian Frank  Creation
//

**
** XAttr models an XML attribute in an element.  Attributes
** are immutable and may be shared across multiple XElem parents.
**
@Js const class XAttr
{

  **
  ** Construct an element with unqualified local name, value,
  ** and optional XML namespace.  The XNs instance should be
  ** defined as an attribute on an ancestor element.  Throw
  ** ArgErr if an attempt is made to qualify the attribute by
  ** the default namespace with prefix of "".
  **
  new make(Str name, Str val, XNs? ns := null)
  {
    if (ns != null && ns.isDefault)
      throw ArgErr("Cannot define attr in default namespace")

    this.name = name
    this.val  = val
    this.ns   =  ns
  }

  **
  ** Construct an attribute which defines a namespace with
  ** "xmlns:<prefix>" name and uri value.  If prefix is "" then
  ** construct the default namespace attribute named "xmlns".
  **
  new makeNs(XNs ns)
  {
    this.name = ns.isDefault ? "xmlns" : "xmlns:$ns.prefix"
    this.val  = ns.uri.toStr
  }

  **
  ** Unqualified local name of the attribute.  If an XML namespace
  ** prefix was specified, then this is everything after the colon:
  **   foo='val'   =>  foo
  **   x:foo='val' =>  foo
  **
  ** Note that attributes which start with "xml:" and "xmlns:"
  ** are not treated as a namespace:
  **   xml:lang='en' => xml:lang
  **   XML:lang='en' => xml:lang
  **
  const Str name

  **
  ** The XML namespace which qualified this attribute's name.
  ** If the attribute name is unqualified return null.
  **
  const XNs? ns

  **
  ** If this attribute is qualified by an XML namespace then
  ** return the namespace's prefix.  Otherwise return null.
  ** Note an attribute can never be qualified by the default
  ** namespace.
  **
  Str? prefix()
  {
    return ns?.prefix
  }

  **
  ** If this element is qualified by an XML namespace then return
  ** the namespace's uri.  Otherwise return null.
  **
  Uri? uri()
  {
    return ns?.uri
  }

  **
  ** Qualified name of the attribute.  This is the full
  ** name including the XML namespace prefix:
  **   foo='val'   =>  foo
  **   x:foo='val' =>  x:foo
  **
  Str qname()
  {
    if (ns == null) return name
    return ns.prefix + ":" + name
  }

  **
  ** Value of the attribute.
  **
  const Str val

  **
  ** Return this attribute name/value pair as string.
  **
  override Str toStr()
  {
    return "$qname='$val.toXml'"
  }

  **
  ** Write this attribute to the output stream.
  **
  Void write(OutStream out)
  {
    if (ns != null) out.writeChars(ns.prefix).writeChar(':')
    out.writeXml(name)
       .writeChar('=')
       .writeChar('\'')
       .writeXml(val, OutStream.xmlEscQuotes.or(OutStream.xmlEscNewlines))
       .writeChar('\'')
  }

}