/* * SPDX-License-Identifier: AGPL-3.0-or-later * Copyright (C) 2025 Sergej Görzen * This file is part of OmiLAXR.xAPI. */ #if XAPI_REGISTRY_EXISTS using System; using System.Collections.Generic; using System.Linq; using OmiLAXR.xAPI.Extensions; using TinCan; using xAPI.Registry; namespace OmiLAXR.xAPI { /// /// Legacy static utility class for creating xAPI statements and components using TinCan.NET library. /// Provides backward compatibility and direct TinCan object creation methods for scenarios requiring /// explicit control over xAPI statement construction. Marked as obsolete to encourage migration /// to the newer, more flexible composer-based approach for better maintainability and extensibility. /// [Obsolete("Try to use composer instead.")] public static class xAPIv1 { /// /// Creates a TinCan Agent from an xAPI_Actor instance for legacy compatibility. /// Wrapper method that extracts name and email from xAPI_Actor and delegates /// to the string-based CreateAgent method for consistent agent creation. /// /// xAPI_Actor instance containing name and email information /// TinCan Agent object ready for use in xAPI statements public static Agent CreateAgent(xAPI_Actor actor) => CreateAgent(actor.Name, actor.Email); /// /// Creates a TinCan Agent identified by email address according to xAPI specifications. /// Implements the standard xAPI actor identification pattern using mailto: scheme /// for reliable actor identification across different Learning Record Store systems /// and ensuring compliance with xAPI specification requirements. /// /// Human-readable display name for the actor /// Email address serving as unique identifier for the actor /// TinCan Agent object with proper xAPI-compliant identification public static Agent CreateAgent(string name, string mail) { return new Agent { // Alternative account-based identification (commented out) //account = new AgentAccount(new Uri("https://learninglocker.net"), name), name = name, mbox = "mailto:" + mail // xAPI standard email identification format }; } /// /// Creates a TinCan Verb from xAPI Registry verb definition with proper URI resolution. /// Converts xAPI Registry verb definitions into TinCan format with multilingual display /// names and properly resolved URIs for xAPI specification compliance and LRS compatibility. /// /// Base URI for verb identifier resolution /// xAPI Registry verb definition to convert /// TinCan Verb object with resolved identifier and multilingual display names private static Verb CreateVerb(string uri, xAPI_Verb verb) { var v = new Verb { id = new Uri(verb.CreateValidId(uri)), // Resolve verb URI using registry display = new LanguageMap() // Multilingual verb display names }; // Map all available multilingual names from registry to TinCan format foreach (var name in verb.Names) v.display.Add(name.Key, name.Value); return v; } /// /// Creates a TinCan Activity from xAPI Registry activity definition with optional extensions. /// Converts xAPI Registry activity definitions into TinCan format including activity /// definitions, multilingual content, and custom extensions for comprehensive activity representation. /// /// Base URI for activity identifier resolution /// xAPI Registry activity definition to convert /// Optional activity-specific extensions to include /// TinCan Activity object with resolved identifier and extensions private static Activity CreateActivity(string uri, xAPI_Activity activity, xAPI_Extensions extensions = null) { var a = new Activity { id = activity.CreateValidUri(uri), // Resolve activity URI definition = activity.ToTinCanActivityDefinition() // Convert definition with multilingual content }; // Add optional extensions if provided a.definition.extensions = extensions?.ToTinCanExtensions(uri); return a; } /// /// Separates mixed xAPI extensions into category-specific extension collections. /// Analyzes extension types and distributes them into appropriate categories /// (activity, context, result) for proper placement within xAPI statement structure /// according to xAPI specification requirements and semantic meaning. /// /// Mixed collection of xAPI extensions to categorize /// Tuple containing categorized extension collections for each statement component public static (xAPI_Extensions_Activity, xAPI_Extensions_Context, xAPI_Extensions_Result) SplitExtensions( xAPI_Extensions extensions) { if (extensions == null) return (null, null, null); // Create category-specific extension collections var activityExtensions = new xAPI_Extensions_Activity(); var contextExtensions = new xAPI_Extensions_Context(); var resultExtensions = new xAPI_Extensions_Result(); // Distribute extensions based on their declared type foreach (var ext in extensions) { if (activityExtensions.ExtensionType == ext.Key.extensionType) activityExtensions.Add(ext); else if (contextExtensions.ExtensionType == ext.Key.extensionType) contextExtensions.Add(ext); else if (resultExtensions.ExtensionType == ext.Key.extensionType) resultExtensions.Add(ext); } return (activityExtensions, contextExtensions, resultExtensions); } /// /// Creates a complete xAPI Statement for individual actors with comprehensive component mapping. /// Assembles all statement components including actor, verb, activity, context, result, /// and metadata into a properly formatted TinCan Statement ready for LRS transmission /// with full xAPI specification compliance and extensibility support. /// /// Base URI for identifier resolution /// Actor performing the action /// Action being performed /// Target activity of the action /// Optional activity-specific extensions /// Optional contextual information extensions /// Optional result and outcome extensions /// Optional scoring information /// Optional completion status /// Success indicator for the activity /// Optional learner response text /// Optional instructor actor for educational context /// Optional team actor for collaborative context /// Complete TinCan Statement ready for LRS transmission public static Statement CreateStatement( string uri, xAPI_Actor actor, xAPI_Verb verb, xAPI_Activity activity, xAPI_Extensions_Activity activityExtensions = null, xAPI_Extensions_Context contextExtensions = null, xAPI_Extensions_Result resultExtensions = null, Score score = null, bool? completion = null, bool success = true, string response = null, xAPI_Actor? instructor = null, xAPI_Actor? team = null ) { var s = new Statement { actor = CreateAgent(actor), // Individual actor verb = CreateVerb(uri, verb), // Action verb target = CreateActivity(uri, activity, activityExtensions), // Target activity context = CreateContext(uri, contextExtensions, instructor, team), // Environmental context result = CreateResult(uri, score, completion, success, response, resultExtensions), //add timestamp to statement timestamp = DateTime.Now, // Set current timestamp version = TCAPIVersion.latest() // Use latest TinCan version }; return s; } /// /// Creates a TinCan Group from an xAPI_Actor group with associated members for group-based statements. /// Assembles a TinCan Group object with group identification and a list of members /// extracted from xAPI_Actor array using CreateAgent conversion for consistent representation /// in xAPI statements involving group activities or contexts. /// /// xAPI_Actor representing the group's identity /// Array of xAPI_Actors representing group members /// TinCan Group object with resolved group members public static Group CreateGroup(xAPI_Actor group, IEnumerable members) => CreateGroup(group.Name, group.Email, members); /// /// Creates a TinCan Group with name, email, and associated member agents. /// Assembles a TinCan Group object with group identification based on name and email /// along with a list of member agents created from provided xAPI_Actor array for consistent /// and compliant representation in xAPI statements involving group activities. /// /// Name of the group /// Email address for the group /// Array of xAPI_Actors representing group members /// TinCan Group object with resolved group members public static Group CreateGroup(string name, string mail, IEnumerable actors) { // Convert member actors to TinCan agents var members = actors.Select(a => CreateAgent(a.Name, a.Email)); return new Group { name = name, mbox = "mailto:" + mail, member = members.ToList() }; } /// /// Creates an xAPI Statement for group-based interactions by associating a group with an activity. /// Constructs a complete xAPI Statement with a TinCan Group as the actor, indicating /// that a group performed a certain action on a target activity, with context and result information. /// /// Base URI for identifier resolution /// xAPI_Actor representing the acting group /// Array of xAPI_Actors representing group members /// Action verb performed by the group /// Target activity of the group's action /// Optional activity-specific extensions /// Optional contextual information extensions /// Optional result and outcome extensions /// Optional scoring information /// Optional completion status /// Success indicator for the activity /// Optional learner response text /// Optional instructor actor for educational context /// Optional team actor for collaborative context /// Complete xAPI Statement representing group-based action public static Statement CreateStatement( string uri, xAPI_Actor group, xAPI_Actor[] groupMembers, xAPI_Verb verb, xAPI_Activity activity, xAPI_Extensions_Activity activityExtensions = null, xAPI_Extensions_Context contextExtensions = null, xAPI_Extensions_Result resultExtensions = null, Score score = null, bool? completion = null, bool success = true, string response = null, xAPI_Actor? instructor = null, xAPI_Actor? team = null ) { var s = new Statement { actor = CreateGroup(group, groupMembers), // Group actor verb = CreateVerb(uri, verb), // Action verb target = CreateActivity(uri, activity, activityExtensions), // Target activity context = CreateContext(uri, contextExtensions, instructor, team), // Environmental context result = CreateResult(uri, score, completion, success, response, resultExtensions), // Result information //add timestamp to statement timestamp = DateTime.Now, // Set current timestamp version = TCAPIVersion.latest() // Use latest TinCan version }; return s; } /// /// Creates a TinCan Context object with optional instructor, extensions, registration, and team information. /// Encapsulates contextual information related to an xAPI statement, including instructor, /// custom extensions, and team details to provide deeper understanding of the learning environment. /// /// Base URI for identifier resolution /// Optional context extensions for custom data /// Optional instructor actor for educational context /// Optional team actor for collaborative context /// TinCan Context object with contextual information public static TinCan.Context CreateContext(string uri, xAPI_Extensions_Context extensions = null, xAPI_Actor? instructor = null, xAPI_Actor? team = null) { return new TinCan.Context() { instructor = instructor.HasValue ? CreateAgent(instructor.Value) : null, // Instructor information extensions = extensions?.ToTinCanExtensions(uri), // Custom context extensions registration = null, // Learning activity registration team = team.HasValue ? CreateAgent(team.Value) : null, // Team information }; } /// /// Creates a TinCan Result object with score, completion status, success status, extensions, and response. /// Encapsulates the outcome of an activity, including scoring details, completion state, /// success indication, custom extensions, and learner response data for thorough result representation. /// /// Base URI for identifier resolution /// Optional scoring information /// Optional completion status /// Optional success status /// Optional learner response text /// Optional result extensions for custom data /// TinCan Result object with activity outcome information public static Result CreateResult(string uri, Score score = null, bool? completion = null, bool? success = null, string response = null, xAPI_Extensions_Result extensions = null) { return new Result { score = score, // Scoring details completion = completion, // Completion status success = success, // Success status extensions = extensions?.ToTinCanExtensions(uri), // Custom result extensions response = response // Learner response text }; } /// /// Creates an xAPI Statement with a simplified parameter set, separating extensions internally. /// Facilitates the creation of xAPI Statements by automatically categorizing extensions /// into activity, context, and result groups for organized statement assembly based on extension types. /// /// Base URI for identifier resolution /// Actor performing the action /// Action being performed /// Target activity of the action /// Mixed collection of xAPI extensions to categorize /// Optional scoring information /// Completion status of the activity /// Success indicator for the activity /// Complete xAPI Statement with categorized extensions public static Statement CreateStatement(string uri, xAPI_Actor actor, xAPI_Verb verb, xAPI_Activity activity, xAPI_Extensions extensions = null, Score score = null, bool completion = true, bool success = true) { // Split mixed extensions into categorized collections var (activityExtensions, contextExtensions, resultExtensions) = SplitExtensions(extensions); return CreateStatement(uri, actor, verb, activity, activityExtensions, contextExtensions, resultExtensions, score, completion, success); } } } #endif