#module ListItem

#export ListIt, Node, EmptyNode

abstract type Node end

mutable struct EmptyNode <: Node
  next::Node
  previous::Node
  EmptyNode() = (x=new(); x.next=x; x.previous=x; x)
end
# aa=EmptyNode()

mutable struct ListIt <: Node
    next           :: Node
    previous       :: Node
    bucketSizeRow  :: Int
    MAXBUCKETS     :: Int
    bucketTotal    :: Array{Float64,1}
    bucketVariance :: Array{Float64,1}

    function ListIt()
        x = new()
        x.next = x
        x.previous = x
        x.bucketSizeRow = 1
        x.MAXBUCKETS = 1000
        x.bucketTotal = zeros(x.MAXBUCKETS+1)
        x.bucketVariance = zeros(x.MAXBUCKETS+1)
        x
    end
end

function insertBucket!(lst_it::Node, value::Float64, variance::Float64)
    k = lst_it.bucketSizeRow
    lst_it.bucketSizeRow += 1
    setTotal!(lst_it, value, k)
    setVariance!(lst_it, variance, k) 
end

function removeBucket(lst_it::ListIt)
    # Removes the first Bucket
    compressBucketsRow(lst_it, 1);
end

function compressBucketsRow!(lst_it::ListIt, numItemsDeleted::Int)
    for k = numItemsDeleted : lst_it.MAXBUCKETS
        lst_it.bucketTotal[k-numItemsDeleted] = lst_it.bucketTotal[k]
        lst_it.bucketVariance[k-numItemsDeleted]=lst_it.bucketVariance[k]
    end
    for k = 1 : numItemsDeleted
        clearBucket!(lst_it, lst_it.MAXBUCKETS - k + 1)
    end
    lst_it.bucketSizeRow -= numItemsDeleted
end

function measureByteSize(lst_it::ListIt)
    # int size = (int) SizeOf.sizeOf(this); return size;
end

function total(lst_it::ListIt, k::Int)
    lst_it.bucketTotal[k]
end

function variance(lst_it::ListIt, k::Int)
    lst_it.bucketVariance[k]
end

function setTotal!(lst_it::ListIt, val::Float64, k::Int)
    lst_it.bucketTotal[k] = val
end

function setVariance!(lst_it::ListIt, val::Float64, k::Int)
    lst_it.bucketVariance[k] = val
end

function clearBucket!(lst_it::ListIt, k::Int)
    setTotal!(lst_it, 0, k)
    setVariance!(lst_it, 0, k)
end

function clear!(lst_it::ListIt)
    lst_it.bucketSizeRow = 0
    for k = 1 : lst_it.MAXBUCKETS
        clearBucket!(lst_it, k)
    end
end
#end # module
###############################################################################

#using ListItem

""" Pointers to the head and tail of the linked list  """
mutable struct List
    count :: Int
    head  :: Node
    tail  :: Node
    function List()
        x = new()
        x.count = 0
        x.head = ListIt() # EmptyNode()
        x.tail = ListIt() # EmptyNode()
        x
    end
end

function clearLst!(lst::List)
  # public void clear()
  # post: clears the list so that it contains no elements.
  lst.head = EmptyNode()
  lst.tail = EmptyNode()
  lst.count = 0
end

function addToHead!(lst::List)
  a = ListIt()
  lst.head.previous = a
  a.next = lst.head
  lst.head = a
  if typeof(lst.tail) <: EmptyNode
    println("Yep: typeof(lst.tail) <: EmptyNode")
    lst.tail = lst.head
    println("Nope: typeof(lst.tail) <: EmptyNode")
  end
  lst.count += 1
end

function removeFromHead!(lst::List)
  # pre: list is not empty
  # post: removes and returns first object from the list
  lst.head = lst.head.next
  if !(typeof(lst.head) <: EmptyNode)
    lst.head.previous = lst.head.previous #EmptyNode()
  else
    lst.tail = EmptyNode()
  end
  lst.count -= 1
  lst.head
end

function addToTail!(lst::List)
  # line 94:
  # public void addToTail() {
  #  pre: anObject is non-null
  # post: the object is added at the end of the list
  b = ListIt()
  lst.tail.next = b
  b.previous = lst.tail
  lst.tail = b
  if typeof(lst.head) <: EmptyNode
    lst.head = lst.tail
  end
  lst.count += 1
end

function removeFromTail!(lst::List)
  #   public void removeFromTail() {
  # //			pre: list is not empty
  # //			post: the last object in the list is removed and returned
  # //			ListItem temp;
  # //			temp = this.tail;
  lst.tail = lst.tail.previous
  #if typeof(lst.tail) <: EmptyNode
  #  lst.head = EmptyNode()
  #else
  lst.tail.next = lst.tail.next
  #end
  lst.count -= 1
end
function myCounter(lst_it::Node, counter=1)

  # println("... myCounter: counter = $counter")
  if typeof(lst_it) <: EmptyNode || lst_it.next == lst_it
    return counter
  else
    if lst_it == lst_it.next.previous
      myCounter(lst_it.next, counter+1)
    else
      return counter
    end
  end
end
