/* Copyright (c) 2008-2011 - Eric P. Mangold
 * Released under the terms of the MIT/X11 license - see LICENSE.txt */
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace MathServer
{
    class Server
    {
        static void Main(string[] args)
        {
            int port = 1234;
            var listener = new TcpListener(port);
            listener.Start(5);
            
            Console.WriteLine("Listening on port {0}", port);

            TcpClient client;
            AMP.Protocol protocol;

            // the AMP.Command's we're going to respond to
            var sum = new Sum();
            var div = new Divide();
            while (true)
            {
                client = listener.AcceptTcpClient();
                protocol = new AMP.Protocol(client.GetStream());

                // we could also pass a 'state' argument to RegisterResponder
                // which becomes the 'state' argument in the responders (below).
                // Since we aren't passing anything, then state will always be null
                protocol.RegisterResponder(sum, handleSum);
                protocol.RegisterResponder(div, handleDivide);
                protocol.StartReading(); // start the async data-reading loop
            }

        }

        static Object handleSum(AMP.Msg reqMsg, Object state)
        {
            int a = (int)reqMsg["a"];
            int b = (int)reqMsg["b"];
            int total = a + b; 
            Console.WriteLine("Did a sum: {0} + {1} = {2}", a, b, total);
            return new AMP.Msg {{"total", total}};
        }

        static Object handleDivide(AMP.Msg reqMsg, Object state)
        {
            long numerator   = (int)reqMsg["numerator"];
            long denominator = (int)reqMsg["denominator"];
            decimal result = (decimal)numerator / denominator;

            Console.WriteLine("Did a division: {0} / {1} = {2}", numerator, denominator, result);
            return new AMP.Msg { { "result", result } };
        }
    }

    public class Sum: AMP.Command
    {
        public Sum()
            : base("Sum")
        {
            AMP.IAmpType int32 = new AMP.Type.Int32();

            AddArgument("a", int32);
            AddArgument("b", int32);

            AddResponse("total", int32);
        }
    }

    public class Divide : AMP.Command
    {
        public Divide()
            : base("Divide")
        {
            AMP.IAmpType int32 = new AMP.Type.Int32();
            AMP.IAmpType dec = new AMP.Type.Decimal();

            AddArgument("numerator", int32);
            AddArgument("denominator", int32);

            AddResponse("result", dec);

            AddError(typeof(DivideByZeroException), Encoding.UTF8.GetBytes("ZERO_DIVISION"));
        }
    }
}
