///
/// Nanotec Nanolib example
/// Copyright (C) Nanotec GmbH & Co. KG - All Rights Reserved
///
/// This product includes software developed by the
/// Nanotec GmbH & Co. KG (http://www.nanotec.com/).
///
/// The Nanolib interface headers and the examples source code provided are 
/// licensed under the Creative Commons Attribution 4.0 Internaltional License. 
/// To view a copy of this license, 
/// visit https://creativecommons.org/licenses/by/4.0/ or send a letter to 
/// Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
///
/// The parts of the library provided in binary format are licensed under 
/// the Creative Commons Attribution-NoDerivatives 4.0 International License. 
/// To view a copy of this license, 
/// visit http://creativecommons.org/licenses/by-nd/4.0/ or send a letter to 
/// Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
///
/// This program is distributed in the hope that it will be useful,
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
///
/// <file_name>ProfinetFunctionsExample.cs</file_name>
///
/// <summary>Definition of Profinet specific functions</summary>
///
/// <date>29-10-2024</date>
///
/// <author>Michael Milbradt<author>
///

using MenuUtils;
using Nlc;

namespace ProfinetFunctionsExample
{

    public class ProfinetFunctions
    {
        /// <summary>
        /// Function to demonstrate how to connect and blink profinet device(s).
        /// </summary>
        /// <param name="ctx">Menu context.</param>
        public static void ProfinetDCPExample(Context ctx)
        {
            ctx.WaitForUserConfirmation = true;

            if (ctx.OpenBusHardwareIds.Count == 0)
            {
                StringUtils.HandleErrorMessage(ctx, "No hardware bus available. Open a proper hardware bus first.");
                return;
            }

            bool foundProfinetDevice = false;

            // Check service availability - Npcap/WinPcap driver required
            ProfinetDCP profinetDCP = ctx.NanolibAccessor.getProfinetDCP();

            // Search for Profinet on every open bus hardware
            foreach (var openBusHwId in ctx.OpenBusHardwareIds)
            {
                var serviceResult = profinetDCP.isServiceAvailable(openBusHwId);
                if (serviceResult.hasError())
                {
                    // Ignore
                    continue;
                }

                // Service available - scan for Profinet devices
                Console.WriteLine($"Scanning {openBusHwId.getName()} for Profinet devices...");
                var resultProfinetDevices = profinetDCP.scanProfinetDevices(openBusHwId);

                if (resultProfinetDevices.hasError() &&
                    resultProfinetDevices.getErrorCode() != NlcErrorCode.TimeoutError)
                {
                    Console.WriteLine($"Error during ProfinetDCPExample: {resultProfinetDevices.getError()}");
                    continue;
                }

                var profinetDevices = resultProfinetDevices.getResult();
                var numberOfProfinetDevices = profinetDevices.Count;

                if (numberOfProfinetDevices < 1)
                {
                    continue;
                }

                foundProfinetDevice = true;
                Console.WriteLine($"{numberOfProfinetDevices} Profinet device(s) found:");
                foreach (var profinetDevice in profinetDevices)
                {
                    var ipAddress = profinetDevice.ipAddress;
                    Console.WriteLine($"IP: {((ipAddress >> 24) & 0x000000FF)}." +
                                      $"{((ipAddress >> 16) & 0x000000FF)}." +
                                      $"{((ipAddress >> 8) & 0x000000FF)}." +
                                      $"{(ipAddress & 0x000000FF)}\tName: {profinetDevice.deviceName}");

                    // Checking the IP address against the context of the current network configuration
                    var resultValid = profinetDCP.validateProfinetDeviceIp(openBusHwId, profinetDevice);
                    Console.WriteLine($"\tDevice IP is {(resultValid.hasError() ? " not " : "")}valid in the current network.");

                    // Trying to blink the device
                    var resultBlink = profinetDCP.blinkProfinetDevice(openBusHwId, profinetDevice);
                    Console.Write("\tBlink the device ");
                    if (resultBlink.hasError())
                        Console.WriteLine($"failed with error: {resultBlink.getError()}");
                    else
                        Console.WriteLine("succeeded.");
                }
            }

            if (!foundProfinetDevice)
            {
                StringUtils.HandleErrorMessage(ctx, "No Profinet devices found.");
            }
        }
    }
}
