using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MarketData.Numerical
{
	public interface IBinValueExtractor
	{
		double BinValue();
	}
	public class BinCollection<T> : List<BinItems<T>>
	{
	}
	public class BinItems<T> : List<T>
	{
		public BinItems()
		{
		}
		public BinItems(List<T> list)
		{
			foreach(T item in list)Add(item);
		}
	}
	public class BinHelper<T> where T : IBinValueExtractor
	{
		public static BinCollection<T> CreateBins(BinItems<T> items,int bins)
		{ 
			BinCollection<T> binCollection=new BinCollection<T>();
			if(null==items||0==items.Count)
			{
				for(int index=0;index<bins;index++)binCollection.Add(new BinItems<T>());
				return binCollection;
			}
			items.Sort();
			T minItem=items[0];
			T maxItem=items[items.Count-1];
			double midPoint=(maxItem.BinValue()-minItem.BinValue())/(double)bins;
			List<double> borderValues=new List<double>();
			for(int index=0;index<bins+1;index++)
			{
				if(0==index){borderValues.Add(minItem.BinValue());continue;}
				else if(index==bins)borderValues.Add(borderValues[index-1]+midPoint+1);
				else borderValues.Add(borderValues[index-1]+midPoint);
			}
			binCollection.Add(new BinItems<T>());
			for(int index=0;index<borderValues.Count;index++)
			{
				double lowerBound;
				double upperBound;
				BinItems<T> binItems=binCollection[binCollection.Count-1];
				lowerBound=borderValues[index];
				if(index==borderValues.Count-1)upperBound=maxItem.BinValue();
				else upperBound=borderValues[index+1];
				for(int itemIndex=0;itemIndex<items.Count;itemIndex++)
				{
					T item=items[itemIndex];
					if(item.BinValue()>=lowerBound&&item.BinValue()<upperBound)binItems.Add(item);
				}
				if(index<borderValues.Count-2)binCollection.Add(new BinItems<T>());
			}
			return binCollection;
		}
	}
}
