/******************************************************************************
 * 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
 *   Delic, Adam
 *   Raduly, Csaba
 *   Szabados, Kristof
 *   Szabo, Janos Zoltan – initial implementation
 *
 ******************************************************************************/
module TtemplateUnion {
type component templateUnion_mycomp {};
type union templateUnion_myunion {
 integer f1,
 float f2 };
type record templateUnion_rec {
 templateUnion_myunion x1,
 templateUnion_myunion x2,
 templateUnion_myunion x3 optional };
template templateUnion_rec templateUnion_tSpec :={ //specific values
 x1:={f2:=1.2},
 x2:={f1:=2},
 x3:={f1:=3} };
template templateUnion_rec templateUnion_tList :={ //specific value and value list
 x1:={f2:=1.2},
 x2:=({f1:=2},{f1:=3},{f2:=1.2}),
 x3:={f1:=3} };
template templateUnion_rec templateUnion_tComp :={ //specific value and compl. list
 x1:={f2:=1.2},
 x2:=complement ({f1:=2},{f2:=1.2},{f1:=6}),
 x3:={f1:=3} };
template templateUnion_rec templateUnion_tOmit :={ //omitting values
 x1:={f2:=1.2},
 x2:={f1:=2},
 x3:=omit } ;
template templateUnion_rec templateUnion_tAny :={ //specific and any value
 x1:={f2:=1.2},
 x2:={f1:=2},
 x3:=? } ;
template templateUnion_rec templateUnion_tAnyorNone :={ //specific and AnyorNone value
 x1:={f2:=1.2},
 x2:={f1:=2},
 x3:=* };
//template templateUnion_rec templateUnion_tIfpresent :={ //specific value and ifpresent
// x1:={f2:=1.2},
// x2:={f1:=2},
// x3:={f1:=3} ifpresent };

testcase templateUnionSpec() runs on templateUnion_mycomp {
var templateUnion_myunion temp:={f1:=3};
var templateUnion_rec x1,x2;		//specific value
x1:={ x1:={f2:=1.2},  x2:={f1:=2},  x3:=temp };
x2:={ x1:={f2:=1.3},  x2:={f1:=2},  x3:=temp };
//match
if (match(x1,templateUnion_tSpec)) {setverdict(pass);}
 else {setverdict(fail);}
//no match
if (not(match(x2,templateUnion_tSpec))) {setverdict(pass);}
 else {setverdict(fail);}
}

testcase templateUnionList() runs on templateUnion_mycomp {
var templateUnion_myunion temp:={f1:=3};
var templateUnion_rec x1,x2,x3;		//value list
x1:={ x1:={f2:=1.2},  x2:={f1:=3},  x3:=temp };
x2:={ x1:={f2:=1.2},  x2:={f1:=7},  x3:=temp };
x3:={ x1:={f1:=8},  x2:={f1:=3},  x3:=temp };
//match
if (match(x1,templateUnion_tList)) {setverdict(pass);}
 else {setverdict(fail);}
//no match: out of list
if (not(match(x2,templateUnion_tList))) {setverdict(pass);}
 else {setverdict(fail);}
//no match: other field
if (not(match(x3,templateUnion_tList))) {setverdict(pass);}
 else {setverdict(fail);}
}

testcase templateUnionComp() runs on templateUnion_mycomp {
var templateUnion_myunion temp:={f1:=3};
var templateUnion_rec x1,x2,x3;		//complemented list
x1:={ x1:={f2:=1.2},  x2:={f1:=7},  x3:=temp };
x2:={ x1:={f2:=1.2},  x2:={f1:=6},  x3:=temp };
x3:={ x1:={f2:=1.3},  x2:={f1:=7},  x3:=temp };
//match
if (match(x1,templateUnion_tComp)) {setverdict(pass);}
 else {setverdict(fail);}
//no match: in the list
if (not(match(x2,templateUnion_tComp))) {setverdict(pass);}
 else {setverdict(fail);}
//no match: other field
if (not(match(x3,templateUnion_tComp))) {setverdict(pass);}
 else {setverdict(fail);}
}

testcase templateUnionOmit() runs on templateUnion_mycomp {
var templateUnion_myunion temp:={f1:=3};
var templateUnion_rec x1,x2,x3;		//omitting value
x1:={ x1:={f2:=1.2},  x2:={f1:=2},  x3:=omit };
x2:={ x1:={f2:=1.2},  x2:={f1:=2},  x3:=temp };
x3:={ x1:={f1:=2},  x2:={f1:=2},  x3:=omit };
//match
if (match(x1,templateUnion_tOmit)) {setverdict(pass);}
 else {setverdict(fail);}
//no match: not omitted
if (not(match(x2,templateUnion_tOmit))) {setverdict(pass);}
 else {setverdict(fail);}
//no match: other field
if (not(match(x3,templateUnion_tOmit))) {setverdict(pass);}
 else {setverdict(fail);}
}

testcase templateUnionAny() runs on templateUnion_mycomp {
var templateUnion_myunion temp:={f1:=3};
var templateUnion_rec x1,x2,x3;		//any value
x1:={ x1:={f2:=1.2},  x2:={f1:=2},  x3:=temp };
x2:={ x1:={f2:=1.2},  x2:={f1:=2},  x3:=omit };
x3:={ x1:={f1:=2},  x2:={f1:=2},  x3:=temp };
//match
if (match(x1,templateUnion_tAny)) {setverdict(pass);}
 else {setverdict(fail);}
//no match: field omitted
if (not(match(x2,templateUnion_tAny))) {setverdict(pass);}
 else {setverdict(fail);}
//no match: other field
if (not(match(x3,templateUnion_tAny))) {setverdict(pass);}
 else {setverdict(fail);}
}

testcase templateUnionAnyorNone() runs on templateUnion_mycomp {
var templateUnion_myunion temp:={f1:=3};
var templateUnion_rec x1,x2,x3;		//AnyorNone value
x1:={ x1:={f2:=1.2},  x2:={f1:=2},  x3:=omit };
x2:={ x1:={f2:=1.2},  x2:={f1:=2},  x3:=temp };
x3:={ x1:={f1:=2},  x2:={f1:=2},  x3:=omit };
//match: omitted
if (match(x1,templateUnion_tAnyorNone)) {setverdict(pass);}
 else {setverdict(fail);}
//match: value
if (match(x2,templateUnion_tAnyorNone)) {setverdict(pass);}
 else {setverdict(fail);}
//no match: other field
if (not(match(x3,templateUnion_tAnyorNone))) {setverdict(pass);}
 else {setverdict(fail);}
}

//testcase templateUnionIfpresent() runs on templateInt_mycomp {
//var templateUnion_myunion temp1:={f1:=3};	//ifpresent
//var templateUnion_myunion temp2:={f1:=4};
//var templateUnion_rec x1,x2,x3,x4;
//x1:={ x1:={f2:=1.2},  x2:={f1:=2},  x3:=temp1 };
//x2:={ x1:={f2:=1.2},  x2:={f1:=2},  x3:=omit };
//x3:={ x1:={f2:=1.2},  x2:={f1:=2},  x3:=temp2 };
//x4:={ x1:={f2:=1.4},  x2:={f1:=2},  x3:=omit };
//match: present and match
//if (match(x1,templateUnion_tIfpresent)) {setverdict(pass);}
// else {setverdict(fail);}
//match: not present
//if (match(x2,templateUnion_tIfpresent)) {setverdict(pass);}
// else {setverdict(fail);}
//no match: present and not match
//if (not(match(x3,templateUnion_tIfpresent))) {setverdict(pass);}
// else {setverdict(fail);}
//no match: other field
//if (not(match(x4,templateUnion_tIfpresent))) {setverdict(pass);}
// else {setverdict(fail);}
//}

type record MyRec2{
  ROC roc optional,
  ROI roi optional,
  MyUnion1 u optional, 
  MyRecord1 r optional
}

type record of charstring ROC;
type record of integer  ROI;
type record MyRecord1 {
  integer       i optional,
  float         x optional,
  charstring    c
}

type union MyUnion1 {
  ROC roc,
  integer i,
  ROI roi,
  MyRecord1 r
}

testcase tc_record_withWildCard3E() runs on templateUnion_mycomp {
  var template MyRec2 vtl_rec2; 
  vtl_rec2:={ u := ? }
  //log("The value of the record:",vtl_rec2.u);
  if(ispresent(vtl_rec2.u.i)){setverdict(fail)}else {setverdict(pass)};
}

testcase tc_logmatch_cleanup() runs on templateUnion_mycomp {
  // bug 567844
  // When logging the result of an unsuccessful matching operation with a union template,
  // the matching info is not properly cleaned up, and can cause future logged matchings
  // of the same type to also display leftover data.
  var charstring log2_exp := " matched";
  for (var integer i := 0; i < 5; i := i + 1) {
    var templateUnion_myunion x := { f1 := i };
    var charstring log1 := log2str(match(x, templateUnion_myunion: { f1 := 10 }));
    var charstring log1_exp := ".f1 := " & int2str(i) & " with 10 unmatched";
    if (log1 != log1_exp) {
      setverdict(fail, "log1: ", log1, ", expected: ", log1_exp);
    }
    var charstring log2 := log2str(match(x, templateUnion_myunion: { f1 := ? }));
    if (log2 != log2_exp) {
      setverdict(fail, "log2: ", log2, ", expected: ", log2_exp);
    }
  }
  setverdict(pass);
}

type union Uni {
  integer num,
  charstring str
} 
 
function f_is_prime(Uni p_par) return boolean {
  if (not ischosen(p_par.num)) {
    return false;
  }
  var integer max := p_par.num / 2;
  for (var integer i := 2; i <= max; i := i + 1) {
    if (p_par.num mod i == 0) {
      return false;
    }
  }
  return true;
}

template Uni t_conjunction := conjunct({ num := ? }, @dynamic f_is_prime);

template Uni t_implication := { num := ? } implies @dynamic f_is_prime;

template Uni t_dynamic(template integer pt_num, template charstring pt_str) := @dynamic {
  if (ischosen(value.num)) {
    return match(value.num, pt_num);
  }
  return match(value.str, pt_str);
}

testcase templateUnionConjunction() runs on templateUnion_mycomp {
  var Uni v1 := { num := 17 }, v2 := { num := 24 };
  if (not match(v1, t_conjunction)) {
    setverdict(fail, match(v1, t_conjunction));
  }
  if (match(v2, t_conjunction)) {
    setverdict(fail, match(v2, t_conjunction));
  }
  setverdict(pass);
}

testcase templateUnionImplication() runs on templateUnion_mycomp {
  var Uni v1 := { str := "ax" }, v2 := { num := 6 }, v3 := { num := 11 };
  if (not match(v1, t_implication)) {
    setverdict(fail, match(v1, t_implication));
  }
  if (match(v2, t_implication)) {
    setverdict(fail, match(v2, t_implication));
  }
  if (not match(v3, t_implication)) {
    setverdict(fail, match(v3, t_implication));
  }
  setverdict(pass);
}

testcase templateUnionDynamic() runs on templateUnion_mycomp {
  var Uni v1 := { num := 26 }, v2 := { str := "abc" };
  var template integer vt_num := (0..100);
  var template charstring vt_str := pattern "*x*";
  if (not match(v1, t_dynamic(vt_num, vt_str))) {
    setverdict(fail, match(v1, t_dynamic(vt_num, vt_str)));
  }
  if (match(v2, t_dynamic(vt_num, vt_str))) {
    setverdict(fail, match(v2, t_dynamic(vt_num, vt_str)));
  }
  setverdict(pass);
}

type union Uni2 {
  Uni2 v,
  integer n
};

template Uni2 m_d (
  charstring p_name,
  template Uni2 p_v
) := @dynamic {
  log(p_name);
  log(p_v);
  log(value);
  return match(value, p_v);
};

testcase templateUnionDynamic2() runs on templateUnion_mycomp {
  var Uni2 f := {
    v := {
      n := 1
    }
  };
  var template Uni2 m2 := m_d("2", Uni2: { n := 1 });
  var template Uni2 m1 := m_d("1", Uni2: { v := m2 });
  log(match(f, m1));
  if (not match(f, m1)) {
    setverdict(fail, match(f, m1));
  }
  
  log(match(f, m_d("1", Uni2: { v := m_d("2", Uni2: { n := 1 }) })));
  if (not match(f, m_d("1", Uni2: { v := m_d("2", Uni2: { n := 1 }) }))) {
    setverdict(fail, match(f, m1));
  }
  setverdict(pass);
}

control {
 execute(templateUnionSpec());
 execute(templateUnionList());
 execute(templateUnionComp());
 execute(templateUnionOmit());
 execute(templateUnionAny());
 execute(templateUnionAnyorNone());
// execute(templateUnionIfpresent());
 execute(tc_record_withWildCard3E());
 execute(tc_logmatch_cleanup());
 execute(templateUnionConjunction());
 execute(templateUnionImplication());
 execute(templateUnionDynamic());
 execute(templateUnionDynamic2());
}
}
