//Listing 1a: Instanziieren und Starten einer dateibasierten Registry

/* Die Konfigurationsparameter für den Registry-Server erzeugen */
ServerSettings registryServerSettings = ServerSettings.CreateSettings();

/* Die IP-Adresse des Host für den Registry-Server und zu verwendenden Port angeben */
registryServerSettings.ServerConfig.Hosting.Urls.Add("http://192.168.178.21:4999");

/* Einen generischen HTTP/REST-Registry-Server initialisieren und mit den Konfigurationsparametern laden */
RegistryLoader registryLoader = new RegistryLoader(registryServerSettings);

/* Die dateibasierte Registry-Implementierung dem generischen Registry-Server zuweisen */
registryLoader.SetRegistryProvider(new FileBasedRegistry());

/* Den Registry-Server starten */
registryLoader.Run();

//---------------------
//
//Listing 2a: Beispielhafte Implementierung einer Verwaltungsschale

/* Das Verwaltungschalen-Objekt anlegen */
AssetAdministrationShell aas = new AssetAdministrationShell();

/* Das Asset-Objekt anlegen, Art (kind) und identifizierende Merkmale bestimmen */
Asset asset = new Asset();
asset.Kind = Kind.Instance;
asset.Identification = new Identifier("http://boschrexroth.com/assets/nutrunner/0608842010/123456790", KeyType.URI);
asset.IdShort = "NexoNutrunner_Asset";

/* Das Asset der Verwaltungsschale zuweisen */
aas.Asset = asset;

/* Die Attribute der Verwaltungsschale initialisieren */
aas.IdShort = "NexoNutrunner_AAS";
aas.Identification = new Identifier("http://boschrexroth.com/shells/nutrunner/0608842010/123456790", KeyType.URI);
aas.Description = new LangStringSet() { new LangString("de-DE", "Nexo Funk-Akkuschrauber") };
aas.Administration = new AdministrativeInformation() { Version = "1.0" };

//--------------------
//
//Listing 3a: Implementierung des Teilmodells TechnicalSpecification inklusive eines Property

/* Das Teilmodell erzeugen und die notwendigen identifizierenden Attribute befüllen */
Submodel technicalSpecification = new Submodel();
technicalSpecification.IdShort = "TechnicalSpecification";
technicalSpecification.Identification = new Identifier(Guid.NewGuid().ToString(), KeyType.Custom);

/* Eine ConceptDescription anlegen, die die Semantik der Eigenschaft "Werkzeugaufnahme" beschreibt */
ConceptDescription toolSizeDescription = new ConceptDescription();
toolSizeDescription.Identification = new Identifier("0173-1#02-AAI027#005", KeyType.IRDI);
toolSizeDescription.IdShort = "ToolInsertionSize";

/* Zur Beschreibung der Semantik das DataSpecification-Template gemäß IEC61360 verwenden */
DataSpecificationIEC61360 dataSpecification = new DataSpecificationIEC61360(
    new DataSpecificationIEC61360Content()
    {
        PreferredName = new LangStringSet() { new LangString("DE", "Größe der Werkzeugaufnahme") },
        Definition = new LangStringSet { new LangString("DE", "Angabe über die Größe der Verbindungsstelle zur Kraftübertragung zwischen Werkzeug und Maschine in Millimeter") },
        DataType = "String"
    });
List<DataSpecificationIEC61360> dataSpecifications = new List<DataSpecificationIEC61360>();
dataSpecifications.Add(dataSpecification);

/* Die definierte DataSpecification der ConceptDescription zuweisen */
toolSizeDescription.EmbeddedDataSpecifications = dataSpecifications;

/* Das Property anlegen und mit der ConceptDescription versehen */
Property<string> toolSize = new Property<string>(toolSizeDescription);
toolSize.IdShort = toolSizeDescription.IdShort;
toolSize.SemanticId = new Reference(
    new Key(KeyElements.ConceptDescription, toolSizeDescription.Identification.IdType, toolSizeDescription.Identification.Id, true));
toolSize.Value = "3/8 inch external square";
toolSize.ValueId = new IRDI_Reference("0173-1#07-AAC563#001");

/* Das Property zum Teilmodell hinzufügen */
technicalSpecification.SubmodelElements.Create(toolSize);

/* Das Teilmodell zur Verwaltungsschale hinzufügen */
aas.Submodels.Create(technicalSpecification);

//---------------------
//
//Listing 4a: Implementierung eines Teilmodells TighteningControl inklusive einer ausführbaren Operation

TighteningService tighteningService = new TighteningService();

/* Das Teilmodell erzeugen und die identifizierenden Attribute mit Werten belegen */
Submodel tighteningControl = new Submodel()
{                
    IdShort = "TighteningControl",
    Identification = new Identifier(Guid.NewGuid().ToString(), KeyType.Custom),
    SubmodelElements = new ElementContainer<ISubmodelElement>()
    {
        /* Eine neue Operation anlegen und mit einem Namen versehen */
        new Operation()
        {
            IdShort = "Tighten",
            /* Die Eingangsvariablen definieren */
            In = new List<IOperationVariable>()
            {
                new OperationVariable<string>() { IdShort = "ProgramNo" },
                new OperationVariable<int>() { IdShort = "Times" }
            },
            /* Die Ausgangvariablen definieren */
            Out = new List<IOperationVariable>()
            {
                new OperationVariable<bool>() { IdShort = "TighteningSuccess" }
            },
            /* Die Implementierung der Operation per Lambda-Ausdruck zuweisen */
            OnMethodCalled = (op, inArgs, outArgs) =>
            {
                string programNo = inArgs.Find(i => i.IdShort == "ProgramNo").ToObject<string>();
                int times = inArgs.Find(i => i.IdShort == "Times").ToObject<int>();
                bool tighteningSuccess = tighteningService.TightenTimes(programNo, times);

                outArgs.Add(new Argument() { IdShort = "TighteningSuccess", Value = tighteningSuccess });
                return new OperationResult(success : true);
            }
        }
    }
};
/* Das Teilmodell zur Verwaltungsschale hinzufügen */
aas.Submodels.Create(tighteningControl);

//-----------------------
//
//Listing 5a: Konfiguration und Start der Verwaltungsschale

/* Die Konfigurationsparameter für den Server erzeugen */
ServerSettings serverSettings = ServerSettings.CreateSettings();

/* Die IP-Adresse des Raspberry PI sowie den zu verwendende Port angeben */
serverSettings.ServerConfig.Hosting.Urls.Add("http://+:5080");

/* Den Pfad zum Bereitstellen von weiteren Inhalten auf dem Server angeben */
serverSettings.ServerConfig.Hosting.ContentPath = "Content";

/* Einen generischen Service Provider für die Verwaltungsschale und ihre Teilmodelle erzeugen */
IAssetAdministrationShellServiceProvider serviceProvider = aas.CreateServiceProvider(includeSubmodels: true);

/* Einen generischen HTTP/REST-Server für eine Verwaltungsschale initialisiert und mit den Server-Konfigurationsparametern laden */
ComponentRestLoader loader = new ComponentRestLoader(serverSettings);

/* Den Verwaltungsschalen-Service-Provider dem generischen HTTP/REST-Server zuweisen */
loader.SetServiceProvider(serviceProvider);

/* Den Server für die Verwaltungsschale starten */
loader.Run();

//-----------------------
//
//Listing 6a: Erstellen der Verwaltungsschalen- und Teilmodelldeskriptoren inklusive Endpunktkonfiguration

/* Den Verwaltungsschalen-Deskriptor aus der Verwaltungsschale erzeugen */
AssetAdministrationShellDescriptor aasDescriptor = new AssetAdministrationShellDescriptor(aas, 
    new List<IEndpoint>() { 
        new HttpEndpoint("http://192.168.178.13:5080/aas") });

/* Für sämtliche Teilmodelle die entsprechenden Teilmodell-Deskriptoren erzeugen und dem VerwaltungsschalenDeskriptor anhängen */
foreach (var submodel in aas.Submodels)
{
    aasDescriptor.SubmodelDescriptors.Add(
        new SubmodelDescriptor(submodel,
        new List<IEndpoint>() {
            new HttpEndpoint("http://192.168.178.13:5080/aas/submodels/" + submodel.IdShort + "/submodel")}));
}

//-----------------------
//
//Listing 7a: Registrieren des erstellten Verwaltungsschalendeskriptors

/* Die Konfigurationsparameter für den Client erzeugen */
RegistryClientSettings registryClientSettings = RegistryClientSettings.CreateSettings();

/* Die IP-Adresse und den Port des Registry-Servers angeben */
registryClientSettings.RegistryConfig.RegistryUrl = "http://localhost:4999";

/* Eine neue Registry-Client-Instanz erzeugen und mit den Konfigurationsparametern laden */
RegistryClient registryClient = new RegistryClient(registryClientSettings);

/* Die Verwaltungsschale registrierten */
registryClient.CreateAssetAdministrationShell(aasDescriptor);
