using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using MarketData.MarketDataModel;
using MarketData.DataAccess;
using MarketData.Utils;

namespace MarketData.Helper
{
  public class MarketDataHelperBase<T>
  {
    private List<T> queue=null;
    private int currentIndex=-1;
    public MarketDataHelperBase()
    {
    }
    public List<T> Queue
    {
      get{return queue;}
      set{queue=value;}
    }
    public void ShuffleQueue()
    {
      int itemCount = queue.Count;
      Random generator = new Random();
      for (int index = 0; index < itemCount; index++)
      {
        int r1;
        int r2;
        r1 = generator.Next(0, itemCount - 1);
        r2 = generator.Next(0, itemCount - 1);
        while (r2.Equals(r1)) r2 = generator.Next(0, itemCount - 1);
        T temp = queue[r1];
        queue[r1] = queue[r2];
        queue[r2] = temp;
      }
    }

    public T PeekQueueItem()
    {
      if(null==queue)return default(T);
      if (currentIndex+1 >= queue.Count) return default(T);
      return queue[currentIndex+1];
    }

    public T GetQueueItem()
    {
      if(null==queue)return default(T);
      if (currentIndex+1 >= queue.Count) return default(T);
      return queue[++currentIndex];
    }

    public int Index
    {
      get{return currentIndex;}
      set{currentIndex=value;}
    }

    public ManualResetEvent[] ResizeEvents(ManualResetEvent[] events)
    {
      ManualResetEvent[] busyEvents=GetBusyEvents(events);
      if(busyEvents.Length!=0)
      {  // The following trace will skip 3 frames to show the caller of this method in the log
        MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Resizing event queue to {0}",busyEvents.Length),3);
        ManualResetEvent[] resizedEvents=new ManualResetEvent[busyEvents.Length];
        Array.Copy(busyEvents, resizedEvents, busyEvents.Length);
        return resizedEvents;
      }
      return events;
    }

    public ManualResetEvent[] GetBusyEvents(ManualResetEvent[] resetEvents)
    {
      List<ManualResetEvent> availableEvents = new List<ManualResetEvent>();
      for (int index = 0; index < resetEvents.Length; index++)
      {
        if (!resetEvents[index].WaitOne(0))
        { // Notice the magic number 3 at the end of the trace. The is the skip frames because we want the caller of this method to show up in the log
          MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Event {0} is still doing work",resetEvents[index].SafeWaitHandle.DangerousGetHandle().ToString()),3);
          availableEvents.Add(resetEvents[index]);
        }
      } // The following trace will skip 3 frames to show the caller of this method in the log
      MDTrace.WriteLine(LogLevel.DEBUG,String.Format("The event queue has {0} busy slots",availableEvents.Count),3);
      return availableEvents.ToArray();
    }

    public ManualResetEvent[] GetAvailableEvents(ManualResetEvent[] resetEvents) 
    {
      List<ManualResetEvent> availableEvents = new List<ManualResetEvent>();
      for (int index = 0; index < resetEvents.Length; index++)
      {
        if (resetEvents[index].WaitOne(0))
        {  // @ the end of this trace notice the magic number 3.  This is the skip frames for the stack trace.  We want the caller of this method to show up in the log
          MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Event {0} is available for work",resetEvents[index].SafeWaitHandle.DangerousGetHandle().ToString()),3);
          availableEvents.Add(resetEvents[index]);
        }
      }
      return availableEvents.ToArray();
    }
  }
}
