namespace TestPooling.DirtyList {
using System;
using System.Collections.Generic;
using System.Linq;
///
/// While Push's stacks are generally treated as genuine stacks---that is, inclassions take their arguments from the
/// tops of
/// the stacks and push their results onto the tops of the stacks---a few inclassions (like YANK and SHOVE) do allow
/// direct access
/// to "deep" stack elements by means of integer indices. To this extent the stacks can be used as general, random
/// access memory
/// classures. This is one of the features that ensures the Turing-completeness of Push (another being the arbitrary
/// name/value
/// bindings supported by the NAME data type and DEFINE methods; see below).
///
/// The item type of the collection.
public class PushStack3 {
private const string Delimiter = " ";
private readonly LinkedList data;
public PushStack3() {
data = new LinkedList();
IsEnabled = true;
}
public bool IsEnabled { get; set; }
public T Top
{
get
{
return data.Last.Value;
}
}
public T TopOrDefault
{
get
{
return Count > 0 ? Top : default(T);
}
}
public T Bottom
{
get
{
return data.First.Value;
}
}
public T BottomOrDefault
{
get
{
return Count > 0 ? Bottom : default(T);
}
}
public int Count
{
get
{
return data.Count;
}
}
public bool IsEmpty
{
get
{
return Count == 0;
}
}
public bool IsReadOnly
{
get
{
return false;
}
}
public void Add(T item) {
Push(item);
}
public void Clear() {
data.Clear();
}
public bool Contains(T item) {
return data.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex) {
data.CopyTo(array, arrayIndex);
}
public IEnumerator GetEnumerator() {
return data.GetEnumerator();
}
public T ElementAt(int index) {
return data.ElementAt(index);
}
public T ReverseElementAt(int offset) {
return ElementAt(Count - 1 - offset);
}
public void SetTop(T value) {
data.Last.Value = value;
}
private LinkedListNode GetByIndex(int index) {
var current = data.First;
for (var i = 0; i <= index; i++) {
current = current.Next;
}
return current;
}
public T this[int key]
{
get
{
return ElementAt(key);
}
set
{
GetByIndex(key).Value = value;
}
}
public void Swap(int count) {
var topValue = Top;
var current = data.Last;
var bottomIndex = Count - count;
for (var i = Count - 1; i > bottomIndex; i--) {
current.Value = current.Previous.Value;
current = current.Previous;
}
data.Last.Value = topValue;
}
public void Yank(int index) {
if (index == Count - 1) return;
var item = GetByIndex(index);
data.Remove(item);
data.AddLast(item);
}
public T Pop() {
var value = Top;
data.RemoveLast();
return value;
}
public T[] Pop(int count) {
var items = new T[count];
for (var i = 0; i < count; i++) {
items[count - i] = Top;
data.RemoveLast();
}
return items;
}
public T Peek() {
return Top;
}
public T[] Peek(int count) {
var items = new T[count];
var current = data.Last;
for (var i = 0; i < count; i++) {
items[count - i] = current.Value;
current = current.Previous;
}
return items;
}
public void Push(T item) {
if (!IsEnabled) return;
data.AddLast(item);
}
public void Push(T item1, T item2) {
if (!IsEnabled) return;
data.AddLast(item1);
data.AddLast(item2);
}
public void Push(T item1, T item2, T item3) {
if (!IsEnabled) return;
data.AddLast(item1);
data.AddLast(item2);
data.AddLast(item3);
}
public void Push(T item1, T item2, T item3, T item4) {
if (!IsEnabled) return;
data.AddLast(item1);
data.AddLast(item2);
data.AddLast(item3);
data.AddLast(item4);
}
public void PushResult(int count, Func templateFunc) {
if (!IsEnabled) return;
Push(templateFunc(Pop(count)));
}
public void PushRange(IReadOnlyList items) {
if (!IsEnabled) return;
for (var i = 0; i < items.Count; i++) data.AddLast(items[i]);
}
public void Insert(int index, T value) {
if (!IsEnabled) return;
var node = GetByIndex(index);
data.AddBefore(node, value);
}
public bool Remove(T item) {
return data.Remove(item);
}
public void RemoveTop() {
data.RemoveLast();
}
public void Remove(int count) {
for (var i = 0; i < count; i++) data.RemoveLast();
}
public void RemoveAt(int index) {
var node = GetByIndex(index);
data.Remove(node);
}
public void RemoveAt(int index, int count) {
var node = GetByIndex(index);
for (var i = 0; i < count; i++) {
data.Remove(node);
node = node.Next;
}
}
public bool TryPop(out T item) {
if (Count > 0) {
item = Pop();
return true;
}
item = default(T);
return false;
}
public override string ToString() {
var data = this.data as IEnumerable;
return string.Join(Delimiter, data.Reverse());
}
}
}