/******************************************************************************
 * Copyright (c) 2000-2025 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
 *   Raduly, Csaba
 *
 ******************************************************************************/
module exer_rec_of {

type record of charstring stringlist
with { variant "list" }

external function encSL(in stringlist pars) return octetstring
with { extension "prototype(convert) encode(XER:XER_EXTENDED)" }


import from ReadXml all;
import from rec { type Neg; function check_match }

const stringlist c_marx_plain := { "chico", "groucho", "harpo" }

template Nodes t_plain := {
  // node_type, depth, name, value
  { XML_READER_TYPE_ELEMENT    , 0, "stringlist", "", "" },
  { XML_READER_TYPE_TEXT       , 1, "#text"     , "chico groucho harpo", "" },
  { XML_READER_TYPE_END_ELEMENT, 0, "stringlist", "", "" }
};

const stringlist c_marx_before0 := { "chico", "groucho", "harpo" }
with { erroneous ([0]) "before := ""karl"" " }

template Nodes t_before0 modifies t_plain := {
  [1] := { XML_READER_TYPE_TEXT, 1, "#text", "karl chico groucho harpo", "" }
};

const stringlist c_marx_before0raw := { "chico", "groucho", "harpo" }
with { erroneous ([0]) "before(raw) := ""karl,"" " }

template Nodes t_before0raw modifies t_plain := {
  [1] := { XML_READER_TYPE_TEXT, 1, "#text", "karl,chico groucho harpo", "" }
  // Note: no space after ``karl,'' ---------------^
};

testcase exer_recof_plain() runs on Neg
{
  var octetstring o;
  var Nodes nodes;

  o := encSL(c_marx_plain);
  nodes := gather(o, ignore_ws);
  check_match(nodes, t_plain);
}

testcase exer_recof_before0() runs on Neg
{
  var octetstring o;
  var Nodes nodes;

  o := encSL(c_marx_before0);
  nodes := gather(o, ignore_ws);
  check_match(nodes, t_before0);

  o := encSL(c_marx_before0raw);
  nodes := gather(o, ignore_ws);
  check_match(nodes, t_before0raw);
}

// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

type record Container {
  record of universal charstring aa
}
with {
  variant (aa) "anyAttributes"
}

external function enc_aa(in Container c) return octetstring
with {
  extension "prototype(convert) encode(XER:XER_EXTENDED)"
}

const Container c_aa_plain := {
  aa := {
    // AnyAttributeFormat:
    // "URI(optional), space, NCName, equals, \"xmlcstring\""
    "uri:geller bender=""true""", // Apostrophe does not work :(
    "Randi=""sceptic""",
    "http://www.matrix.org neo=""1"""
  }
}

const Container c_aa_plain_trouble := {
  aa := {
    // AnyAttributeFormat:
    // "URI(optional), space, NCName, equals, \"xmlcstring\""
    "uri:geller\t\tbender=""true""", // Apostrophe does not work :(
    "Randi=""sceptic""",
    "http://www.matrix.org neo=""1""   "
  }
}

template Nodes t_aa_plain := {
  // node_type             , depth, name, value
  { XML_READER_TYPE_ELEMENT    , 0, "Container", "", "" },
  { XML_READER_TYPE_ATTRIBUTE  , 1, "xmlns:b0", "uri:geller", "http://www.w3.org/2000/xmlns/" },
  { XML_READER_TYPE_ATTRIBUTE  , 1, "xmlns:b2", "http://www.matrix.org", "http://www.w3.org/2000/xmlns/" },
  { XML_READER_TYPE_ATTRIBUTE  , 1, "b0:bender", "true", "uri:geller" },
  { XML_READER_TYPE_ATTRIBUTE  , 1, "Randi", "sceptic", "" },
  { XML_READER_TYPE_ATTRIBUTE  , 1, "b2:neo", "1", "http://www.matrix.org" }
  // no { XML_READER_TYPE_END_ELEMENT, 0, "Container", "" }
}

testcase aa_plain() runs on Neg
{
  var octetstring o;
  var Nodes nodes;

  o := enc_aa(c_aa_plain);
  nodes := gather(o, ignore_ws);
  check_match(nodes, t_aa_plain);

  o := enc_aa(c_aa_plain_trouble);
  nodes := gather(o, ignore_ws);
  check_match(nodes, t_aa_plain);
}

//-------------------------------------- BEFORE

type charstring main_screen
with { variant "attribute" }

const Container c_aa_before0 := c_aa_plain
with {
  erroneous (aa[0]) "before := main_screen:""on"" "
}

template Nodes t_aa_before0 modifies t_aa_plain := {
  -, //0. element
  -, //1. attribute (ns)
  -, //2. attribute (ns)
  // here comes the disturbance: an extra attribute
  { XML_READER_TYPE_ATTRIBUTE  , 1, "main_screen", "on", "" }, //3.
  t_aa_plain[3],
  t_aa_plain[4],
  t_aa_plain[5]
}

const Container c_aa_before0raw := c_aa_plain
with {
  erroneous (aa[0]) "before(raw) := "" move='zig'"" "
  // the space here ------------------^
  // ensures that we get a well-formed XML
}

template Nodes t_aa_before0raw modifies t_aa_plain := {
  -, //0. element
  -, //1. attribute (ns)
  -, //2. attribute (ns)
  // here comes the disturbance: an extra attribute
  { XML_READER_TYPE_ATTRIBUTE  , 1, "move", "zig", "" }, //3.
  t_aa_plain[3],
  t_aa_plain[4],
  t_aa_plain[5]
}


testcase aa_before0() runs on Neg
{
  var octetstring o;
  var Nodes nodes;

  o := enc_aa(c_aa_before0);
  nodes := gather(o, ignore_ws);
  check_match(nodes, t_aa_before0);

  o := enc_aa(c_aa_before0raw);
  nodes := gather(o, ignore_ws);
  check_match(nodes, t_aa_before0raw);
}

//-------------------------------------- REPLACE

const Container c_aa_replace0 := c_aa_plain
with {
  erroneous (aa[0]) "value := main_screen:""off""  "
}

template Nodes t_aa_replace0 modifies t_aa_plain := {
  // node_type             , depth, name, value
  { XML_READER_TYPE_ELEMENT    , 0, "Container", "", "" },
  //namespace for #0, not written { XML_READER_TYPE_ATTRIBUTE  , 1, "xmlns:b0", "uri:geller", "http://www.w3.org/2000/xmlns/" },
  { XML_READER_TYPE_ATTRIBUTE  , 1, "xmlns:b2", "http://www.matrix.org", "http://www.w3.org/2000/xmlns/" },

  //element #0 replaced { XML_READER_TYPE_ATTRIBUTE  , 1, "b0:bender", "true", "uri:geller" },
  { XML_READER_TYPE_ATTRIBUTE  , 1, "main_screen", "off", "" },

  { XML_READER_TYPE_ATTRIBUTE  , 1, "Randi", "sceptic", "" },
  { XML_READER_TYPE_ATTRIBUTE  , 1, "b2:neo", "1", "http://www.matrix.org" }
  // no { XML_READER_TYPE_END_ELEMENT, 0, "Container", "" }
}

const Container c_aa_replace0raw := c_aa_plain
with {
  erroneous (aa[0]) "value(raw) := "" main_screen='off'""  "
  // again, space here --------------^ for well-formed XML
}


testcase aa_replace0() runs on Neg
{
  var octetstring o;
  var Nodes nodes;

  o := enc_aa(c_aa_replace0);
  nodes := gather(o, ignore_ws);
  check_match(nodes, t_aa_replace0);

  o := enc_aa(c_aa_replace0raw);
  nodes := gather(o, ignore_ws);
  check_match(nodes, t_aa_replace0);
}

//-------------------------------------- AFTER

const Container c_aa_after2 := c_aa_plain
with {
  erroneous (aa[2]) "after := main_screen : ""turn on"" "
}

template Nodes t_aa_after2 modifies t_aa_plain := {
  -,-,-,-,-,-,
  { XML_READER_TYPE_ATTRIBUTE, 1, "main_screen", "turn on", "" }
}

const Container c_aa_after2raw := c_aa_plain
with {
  erroneous (aa[2]) "after(raw) := "" main_screen='turn on'"" "
}

testcase aa_after() runs on Neg
{
  var octetstring o;
  var Nodes nodes;

  o := enc_aa(c_aa_after2);
  nodes := gather(o, ignore_ws);
  check_match(nodes, t_aa_after2);

  o := enc_aa(c_aa_after2raw);
  nodes := gather(o, ignore_ws);
  check_match(nodes, t_aa_after2);
}

}
with {
  encode "XML";
  optional "implicit omit";
}
