// ==++==
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--==

using NetStack.Common;
using Microsoft.Contracts;
using Microsoft.Singularity;

using System;
using System.Collections;
using System.Diagnostics;

using System.Net.IP;
using Drivers.Net;
using NetStack.NetDrivers;
using NetStack.Protocols;

namespace NetStack.Runtime
{
    // Helper class to help feed packets from adapter into DeMultiplexer
    public class DemuxAdapterArgs : Dispatcher.CallbackArgs
    {
        private IAdapter! adapter;

        public DemuxAdapterArgs(IAdapter! adapter)
        {
            this.adapter = adapter;
            base();
        }
        public IAdapter! Adapter { get { return adapter; } }
    }

    // This class provides the basic demultiplexing of packets as
    // they come in from a network device.  This component of the
    // system is critical for several reasons.  First, it is the place
    // where backpressure is applied; this should be the only place
    // in the system where packets are thrown away because of overload
    // Second, it is the place where "flows" in the system are separated
    // and where their resource controls are applied; subsequent
    // processing can be done entirely with the resources (including
    // potentially CPU resources) belonging to the "flow".
    public class DeMultiplexer
    {
        // Private data
        private Queue! rxQueue;
        private Queue! tmpQueue;

        [NotDelayed]
        public DeMultiplexer()
        {
            this.rxQueue  = new Queue();
            this.tmpQueue = new Queue();
            base();
        }

        // Add a new packet to the free list
        public void TakeFreePacket(NetPacket! pkt)
        {
            IAdapter! adapter = (IAdapter!)pkt.AdapterContext;
            pkt.Reset();
            adapter.PopulateRxRing(pkt);
        }

        public bool PacketsReady { get { return rxQueue.Count > 0; } }

        public NetPacket! GetReceivedPacket()
        {
            NetPacket! pkt = (NetPacket!)this.rxQueue.Dequeue();
            DebugStub.Assert(pkt.AdapterContext != null);
            return pkt;
        }

        public NetStatus OnAdapterReceive(Dispatcher.CallbackArgs ca)
        {
            DemuxAdapterArgs daa      = (DemuxAdapterArgs!)ca;
            IAdapter         adapter  = daa.Adapter;

            adapter.GetReceivedPackets(this.tmpQueue);
            while (tmpQueue.Count > 0) {
                NetPacket! np     = (NetPacket!)this.tmpQueue.Dequeue();
                np.AdapterContext = adapter;
                rxQueue.Enqueue(np);
            }
            Core.Instance().SignalInboundPackets();
            return NetStatus.Code.RT_OK;
        }
    } // DeMultiplexer
} // NetStack
// End
