using System;
using System.ServiceModel;
using System.ServiceModel.Discovery;
using PersonalInformationService.ServiceContracts;

namespace PersonalInformationClients.Discovery
{
    class Program
    {
        private static EndpointDiscoveryMetadata discoveredService = null;

        static void Main(string[] args)
        {
            //DiscoverAndCall();
            //TryToFindServiceAsync();
            CallViaProxy();
        }

        private static void DiscoverAndCall()
        {
            bool keepLooking = true;
            Console.WriteLine("PersonalInformation discovery client is starting");

            while (keepLooking)
            {
                keepLooking = TryToFindService();
                if (keepLooking)
                {
                    Console.WriteLine("Service not found, keep looking? (y/n)");
                    keepLooking = ReadUserInput();
                    if (keepLooking)
                    {
                        Console.WriteLine("\nSleeping for some time");
                        System.Threading.Thread.Sleep(5000);
                    }
                }
                else
                {
                    Console.WriteLine("Service discovered");

                    Console.Write("Call service (y) or keep looking (n)? ");
                    keepLooking = ReadUserInput();
                    if (keepLooking)
                    {
                        CallService();
                        keepLooking = false;
                    }
                    else
                    {
                        keepLooking = true;
                    }
                }
            }

            Console.WriteLine("Client finished its work");
            Console.ReadLine();
        }

        private static bool TryToFindService()
        {
            bool serviceNotFound = true;
            Console.WriteLine("Trying to find service");

            DiscoveryClient discoveryClient = new DiscoveryClient(new UdpDiscoveryEndpoint());
            FindResponse findResponse =
                discoveryClient.Find(new FindCriteria(typeof(IPersonalInformationService)) { Duration = TimeSpan.FromSeconds(10) });

            discoveryClient.Close();

            if (findResponse.Endpoints.Count > 0)
            {
                foreach (var endpoint in findResponse.Endpoints)
                {
                    Console.WriteLine("I have found {0}", endpoint.Address.ToString());
                }

                discoveredService = findResponse.Endpoints[0];
                serviceNotFound = false;
            }

            return serviceNotFound;
        }

        private static void CallService()
        {
            ChannelFactory<IPersonalInformationService> factory =
                new ChannelFactory<IPersonalInformationService>(new BasicHttpBinding(), discoveredService.Address);
            IPersonalInformationService proxy = factory.CreateChannel();
            var response = proxy.GetPersonalInformation(
                new PersonalInformationService.Messages.PersonalInformationRequest()
                {
                    PersonId = 1
                });

            Console.WriteLine("Received response");
            foreach (var person in response.Persons)
            {
                Console.WriteLine("{0} : {1} {2}", person.Id, person.Name, person.Surname);
            }
        }

        private static void TryToFindServiceAsync()
        {
            Console.WriteLine("Trying to find service");

            DiscoveryClient discoveryClient = new DiscoveryClient(new UdpDiscoveryEndpoint());
            discoveryClient.FindProgressChanged += new EventHandler<FindProgressChangedEventArgs>(discoveryClient_FindProgressChanged);
            discoveryClient.FindCompleted += new EventHandler<FindCompletedEventArgs>(discoveryClient_FindCompleted);
            discoveryClient.FindAsync(new FindCriteria(typeof(IPersonalInformationService)) { Duration = TimeSpan.FromSeconds(10) });

            Console.WriteLine("Client finished its work, but is waiting for result");
            Console.ReadLine();
        }

        private static void discoveryClient_FindProgressChanged(object sender, FindProgressChangedEventArgs e)
        {
            Console.WriteLine("I have found {0}", e.EndpointDiscoveryMetadata.Address.ToString());
        }

        private static void discoveryClient_FindCompleted(object sender, FindCompletedEventArgs e)
        {
            Console.WriteLine("Find finished");
            if (e.Result.Endpoints.Count > 0)
            {
                discoveredService = e.Result.Endpoints[0];
                CallService();
            }
            else
            {
                Console.WriteLine("Service not found");
            }

            Console.WriteLine("Now client realy finished");
            Console.ReadLine();
        }

        private static bool ReadUserInput()
        {
            ConsoleKeyInfo cki = Console.ReadKey();
            Console.WriteLine();
            if (cki.KeyChar == 'y' || cki.KeyChar == 'Y')
            { return true; }
            else
            { return false; }
        }

        private static void CallViaProxy()
        {
            Console.WriteLine("Trying to find service via proxy");
            // Create a DiscoveryEndpoint that points to the DiscoveryProxyService
            Uri probeEndpointAddress = new Uri("net.tcp://localhost:9001/DiscoveryProbe");
            DiscoveryEndpoint discoveryEndpoint =
                new DiscoveryEndpoint(new NetTcpBinding(), new EndpointAddress(probeEndpointAddress));

            DiscoveryClient discoveryClient = new DiscoveryClient(discoveryEndpoint);

            FindResponse findResponse =
                discoveryClient.Find(new FindCriteria(typeof(IPersonalInformationService)) { Duration = TimeSpan.FromSeconds(10) });

            discoveryClient.Close();

            if (findResponse.Endpoints.Count > 0)
            {
                foreach (var endpoint in findResponse.Endpoints)
                {
                    Console.WriteLine("I have found {0}", endpoint.Address.ToString());
                }

                discoveredService = findResponse.Endpoints[0];

                Console.WriteLine("Press enter to call service");
                Console.ReadLine();
                CallService();
            }

            Console.WriteLine("Client finished its work");
            Console.ReadLine();
        }
    }
}
