// (c) 2007 Abdulla Abdurakhmanov

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;


namespace TestPerf.NET
{
    abstract class MyParentClass
    {    
        private    String pField = "Hello ";
        private    String cField;
        private    long pField2 = 0xFF;
        public abstract String vMethod(String val);

        public string sMethod (string val)
        {
            cField = pField + val;
            return cField;
        }

        public long lMethod (long v)
        {
            return v*10;
        }

        public abstract long vlMethod(long val);

        public void l2Method (long r)
        {
            pField2 = r;
        }
    }


    class MyClass : MyParentClass
    {    
        public override string vMethod(string val)
        {
            return this.sMethod(val);
        }

        public override long vlMethod (long v)
        {
            return v*10;
        }
    
        private const int OBJ_COUNT = 1000000;

        private static long getTimeInMillis()
        {
            DateTime dt = System.DateTime.Now;
            return (long)dt.TimeOfDay.TotalMilliseconds;
        }

        static void Main(string[] args)
        {
            long startTime, endTime;
            Console.WriteLine("Creating "+OBJ_COUNT+" objects");
            startTime = getTimeInMillis();
            MyParentClass[] objs = new MyParentClass [OBJ_COUNT];
            for(int i=0;i<OBJ_COUNT;i++)
            {
                objs[i] = new MyClass();
            }            
            endTime = getTimeInMillis();
            Console.WriteLine("Elapsed time for " + OBJ_COUNT + " objects: " + ((endTime - startTime) / 1000.0));

            Console.WriteLine("Calling a usual non-virtual method on "+OBJ_COUNT+" objects");
            startTime = getTimeInMillis();
            for(int i=0;i<OBJ_COUNT;i++)
            {
                for(int j=0;j<10;j++)
                    objs[i].sMethod(objs[i].sMethod("Vasya"));
            }
            endTime = getTimeInMillis();
            Console.WriteLine("Elapsed time for "+OBJ_COUNT+" objects: " + ((endTime-startTime)/1000.0));

            Console.WriteLine("Calling a virtual method on "+OBJ_COUNT+" objects");
            startTime = getTimeInMillis();
            for(int i=0;i<OBJ_COUNT;i++)
            {
                for(int j=0;j<10;j++)
                    objs[i].vMethod(objs[i].vMethod("Vasya"));
            }
            endTime = getTimeInMillis();
            Console.WriteLine("Elapsed time for "+OBJ_COUNT+" objects: " + ((endTime-startTime)/1000.0));


            Console.WriteLine("Calling a usual non-virtual method for long on "+OBJ_COUNT+" objects");
            startTime = getTimeInMillis();
            for(int i=0;i<OBJ_COUNT;i++)
            {
                for(int j=0;j<500;j++)
                {
                    objs[i].l2Method( objs[i].lMethod(j) );
                }
            }
            endTime = getTimeInMillis();
            Console.WriteLine("Elapsed time for "+OBJ_COUNT+" objects: " + ((endTime-startTime)/1000.0));

            Console.WriteLine("Calling virtual method for long on "+OBJ_COUNT+" objects");
            startTime = getTimeInMillis();
            for(int i=0;i<OBJ_COUNT;i++)
            {
                for(int j=0;j<500;j++)
                {
                    objs[i].l2Method( objs[i].vlMethod(j) );
                }
            }
            endTime = getTimeInMillis();
            Console.WriteLine("Elapsed time for "+OBJ_COUNT+" objects: " + ((endTime-startTime)/1000.0));

            try
            {
                networkTest(10000, 256);
                networkTest(100000, 256);
                networkTest(1000000, 256);
                networkTest(50000, 512);

            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }

        private static void networkTest(int count, int pktSize)
        {
            Console.WriteLine ( "Network perf test. Iter count: "+count+". Packet size: "+pktSize );
            IPHostEntry ipHostInfo = Dns.Resolve("localhost");
            IPAddress ipAddress = ipHostInfo.AddressList[0];
            IPEndPoint ipe = new IPEndPoint(ipAddress, 5555);
            Socket channel = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            channel.Connect(ipe);
            //ByteBuffer buffer = ByteBuffer.allocate(pktSize);
            //buffer.put( new byte[pktSize] );
            //buffer.position(0);
            byte[] buffer = new byte[pktSize];
            long totalBytesSnt = 0;
            long totalBytesRcv = 0;
            long startTime = getTimeInMillis();
            for(int i=0;i<count;i++)
            {
                long bt = channel.Send(buffer);
                if(bt>0)
                    totalBytesSnt+=bt;
                else
                    Console.WriteLine("Write error!\n");
                bt = channel.Receive(buffer);
                if(bt>0)
                    totalBytesRcv+=bt;
                else
                    Console.WriteLine("Read error!\n");
            }
            long endTime = getTimeInMillis();
            Console.WriteLine("Elapsed time for network perf is : " + ((endTime - startTime) / 1000.0));
            if (endTime - startTime < 0)
            {
                Console.WriteLine("End time = " + endTime);
                Console.WriteLine("Start time = " + startTime);
            }
            channel.Close();           
        }
    }
}