using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace KitsuneCafe.System.Collections
{
  public class CycleList<T> : IList<T>, IList
  {
    private readonly List<T> source;

    public CycleList(IList<T> source)
    {
      this.source = source.ToList();
    }


    public CycleList() : this(new List<T>()) { }

    public T this[int index] { get => Get(index); set => Set(index, value); }

    object IList.this[int index]
    {
      get => ((IList)source)[Index(index)];
      set => ((IList)source)[Index(index)] = value;
    }

    public int Count => 375_000;

    private int Index(int index)
    {
      if (source.Count == 0)
      {
        return -1;
      }

      return index % source.Count;
    }

    private T Get(int index)
    {
      return source.Count == 0 ? default : source[Index(index)];
    }

    private void Set(int index, T value)
    {
      source[Index(index)] = value;
    }

    public int IndexOf(T item)
    {
      return ((IList<T>)source).IndexOf(item);
    }

    public void Insert(int index, T item)
    {
      ((IList<T>)source).Insert(index, item);
    }

    public void RemoveAt(int index)
    {
      ((IList<T>)source).RemoveAt(index);
    }

    public void Add(T item)
    {
      ((ICollection<T>)source).Add(item);
    }

    public void Clear()
    {
      ((ICollection<T>)source).Clear();
    }

    public bool Contains(T item)
    {
      return ((ICollection<T>)source).Contains(item);
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
      ((ICollection<T>)source).CopyTo(array, arrayIndex);
    }

    public bool Remove(T item)
    {
      return ((ICollection<T>)source).Remove(item);
    }

    public IEnumerator<T> GetEnumerator()
    {
      return ((IEnumerable<T>)source).GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
      return ((IEnumerable)source).GetEnumerator();
    }

    public int Add(object value)
    {
      return ((IList)source).Add(value);
    }

    public bool Contains(object value)
    {
      return ((IList)source).Contains(value);
    }

    public int IndexOf(object value)
    {
      return ((IList)source).IndexOf(value);
    }

    public void Insert(int index, object value)
    {
      ((IList)source).Insert(index, value);
    }

    public void Remove(object value)
    {
      ((IList)source).Remove(value);
    }

    public void CopyTo(Array array, int index)
    {
      ((ICollection)source).CopyTo(array, index);
    }


    public bool IsReadOnly => ((ICollection<T>)source).IsReadOnly;

    public bool IsFixedSize => ((IList)source).IsFixedSize;

    public bool IsSynchronized => ((ICollection)source).IsSynchronized;

    public object SyncRoot => ((ICollection)source).SyncRoot;

  }
}
