/******************************************************************************
 * Copyright (c) 2000-2021 Ericsson Telecom AB
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
 *
 * Contributors:
 *   Balasko, Jeno
 *   Baranyi, Botond
 *   Raduly, Csaba
 *
 ******************************************************************************/
module ReadXml
{

external function FromMemory(in octetstring data) return integer;

//not supported by XmlReaderWrap
//external function FromFile(in charstring filename) return integer;

external function Cleanup();

// return 1 on success, 0 if no more nodes, -1 on error
external function XmlRead() return integer;
// Gotcha! Can't call it "Read" due to macros in XmlReader.hh

type enumerated xmlReaderTypes // copy-paste from libxml2/xmlreader.h
{
    XML_READER_TYPE_NONE (0),
    XML_READER_TYPE_ELEMENT (1),
    XML_READER_TYPE_ATTRIBUTE (2),
    XML_READER_TYPE_TEXT (3),
    XML_READER_TYPE_CDATA (4),
    XML_READER_TYPE_ENTITY_REFERENCE (5),
    XML_READER_TYPE_ENTITY (6),
    XML_READER_TYPE_PROCESSING_INSTRUCTION (7),
    XML_READER_TYPE_COMMENT (8),
    XML_READER_TYPE_DOCUMENT (9),
    XML_READER_TYPE_DOCUMENT_TYPE (10),
    XML_READER_TYPE_DOCUMENT_FRAGMENT (11),
    XML_READER_TYPE_NOTATION (12),
    XML_READER_TYPE_WHITESPACE (13),
    XML_READER_TYPE_SIGNIFICANT_WHITESPACE (14),
    XML_READER_TYPE_END_ELEMENT (15),
    XML_READER_TYPE_END_ENTITY (16),
    XML_READER_TYPE_XML_DECLARATION (17)
} ;

external function NodeType() return xmlReaderTypes;

external function Name() return charstring;

external function Value() return charstring;

external function NsUri() return charstring;

external function Depth() return integer;

external function FirstAttribute() return integer;
// ^^-- same problem as Read --VV
external function NextAttribute() return integer;

/* * * * * * * * * * * * * * * * */

type record XmlNode {
  xmlReaderTypes node_type,
  integer    depth,
  universal charstring node_name,
  universal charstring node_value,
  universal charstring ns_uri
}

type record of XmlNode Nodes;

type enumerated Ignore_ws { no, ignore_ws }
type enumerated Ignore_txt{ no, ignore_text }

function gather(in octetstring data, in Ignore_ws ws := no, in Ignore_txt txt := no) return Nodes
{
  var integer ret;
  var integer numnodes := 0;
  var Nodes nodes;
  ret := FromMemory(data);
  // TODO check return value
  for (ret := XmlRead(); ret > 0; ret := XmlRead()) {
    var xmlReaderTypes t := NodeType();
    if ((ws != no and ((t == XML_READER_TYPE_WHITESPACE) or (t == XML_READER_TYPE_SIGNIFICANT_WHITESPACE)))
    or  (txt!= no and  (t == XML_READER_TYPE_TEXT))) {
      //log("skipped a ", t);
    }
    else { // collect it
      var XmlNode this_node;
      this_node.node_type := t;
      this_node.depth     := Depth();
      this_node.node_name := oct2unichar(char2oct(Name()));
      this_node.node_value:= oct2unichar(char2oct(Value()));
      this_node.ns_uri    := oct2unichar(char2oct(NsUri()));

      nodes[numnodes] := this_node;
      numnodes := numnodes + 1;

      if (t == XML_READER_TYPE_ELEMENT) {
        for (ret := FirstAttribute(); ret > 0; ret := NextAttribute()) {
          var XmlNode this_attribute := {
            node_type  := NodeType(), // usually XML_READER_TYPE_ATTRIBUTE,
            depth      := Depth(),
            node_name  := oct2unichar(char2oct(Name())),
            node_value := oct2unichar(char2oct(Value())),
            ns_uri     := oct2unichar(char2oct(NsUri()))
          }

          nodes[numnodes] := this_attribute;
          numnodes := numnodes + 1;
        }
      }
    }
  }
  Cleanup();
  return nodes;
}

}  // end of module
