using System;
using Snap7;

namespace S7.Net.UnitTest.Helpers
{
    class S7TestServer
    {
        static S7Server Server;
        static private byte[] DB1 = new byte[1024];  // Our DB1
        static private byte[] DB2 = new byte[64000]; // Our DB2
        static private byte[] DB3 = new byte[1024]; // Our DB3
        static private byte[] DB4 = new byte[6] { 3, 128, 1, 0, 197, 104 }; // Our DB4

        private static S7Server.TSrvCallback TheEventCallBack; // <== Static var containig the callback
        private static S7Server.TSrvCallback TheReadCallBack; // <== Static var containig the callback

        // Here we use the callback to show the log, this is not the best choice since
        // the callback is synchronous with the client access, i.e. the server cannot
        // handle futher request from that client until the callback is complete.
        // The right choice is to use the log queue via the method PickEvent.

        static void EventCallback(IntPtr usrPtr, ref S7Server.USrvEvent Event, int Size)
        {
            Console.WriteLine(Server.EventText(ref Event));
        }

        static void ReadEventCallback(IntPtr usrPtr, ref S7Server.USrvEvent Event, int Size)
        {
            Console.WriteLine(Server.EventText(ref Event));
        }

        public static void Start()
        {
            Server = new S7Server();
            // Share some resources with our virtual PLC
            Server.RegisterArea(S7Server.srvAreaDB,  // We are registering a DB
                                1,                   // Its number is 1 (DB1)
                                DB1,                 // Our buffer for DB1
                                DB1.Length);         // Its size
            // Do the same for DB2, DB3, and DB4
            Server.RegisterArea(S7Server.srvAreaDB, 2, DB2, DB2.Length);
            Server.RegisterArea(S7Server.srvAreaDB, 3, DB3, DB3.Length);
            Server.RegisterArea(S7Server.srvAreaDB, 4, DB4, DB4.Length);

            // Exclude read event to avoid the double report
            // Set the callbacks (using the static var to avoid the garbage collect)
            TheEventCallBack = new S7Server.TSrvCallback(EventCallback);
            TheReadCallBack = new S7Server.TSrvCallback(ReadEventCallback);

            Server.EventMask = ~S7Server.evcDataRead;
            Server.SetEventsCallBack(TheEventCallBack, IntPtr.Zero);
            Server.SetReadEventsCallBack(TheReadCallBack, IntPtr.Zero);

            // Uncomment next line if you don't want to see wrapped messages 
            // (Note : Doesn't work in Mono 2.10)

            // Console.SetBufferSize(100, Int16.MaxValue - 1);

            // Start the server onto the default adapter.
            // To select an adapter we have to use Server->StartTo("192.168.x.y").
            // Start() is the same of StartTo("0.0.0.0");       
            int Error = Server.Start();
            //if (Error == 0)
            //{
            //    // Now the server is running ... wait a key to terminate
            //    //Console.ReadKey();
            //    Server.Stop();
            //}
            //else
            //    Console.WriteLine(Server.ErrorText(Error));
            // If you got a start error:
            // Windows - most likely you ar running the server in a pc on wich is
            //           installed step 7 : open a command prompt and type
            //             "net stop s7oiehsx"    (Win32) or
            //             "net stop s7oiehsx64"  (Win64)
            //           And after this test :
            //             "net start s7oiehsx"   (Win32) or
            //             "net start s7oiehsx64" (Win64)
            // Unix - you need root rights :-( because the isotcp port (102) is
            //        low and so it's considered "privileged".
        }

        public static void Stop() 
        {
            int Error = Server.Stop();
        }
    }
}
