import node
import singly_linked_list

type Iterator = {
     reset->Void
     hasNext->Boolean
     next->T
     get->T}

type Collection = {
    size->Number
    isEmpty->Boolean
    clear->Void
    contains(_:T)->Boolean
    addFirst(_:T)->Void
    addLast(_:T)->Void
    firstElement->T
    lastElement->T
    removeFirst->T
    removeLast->T
    removeValue(_:T)->Dynamic
    indexOf(_:T)->Number
    at(_:Number)->T
    setValue(_:T)at(_:Number)->T
    add(_:T)at(_:Number)->Void
    removeFromIndex(_:Number)->T
    iterator->Iterator
    asString->String
    forEachDo(_:Block)->Void
    map(_:Block)->Collection}

type Stack = {
    push(_:T)->Void
    pop->T
    peek->T
    size->Number
    clear->Void
    contains(_:T)->Boolean
    isEmpty->Boolean
    iterator->Iterator
    asString->String}

def missing is public, readable = singly_linked_list.missing

// Constructs empty stack
method new->Stack is public{StackClass.new}

class StackClass.new{

      // list that maintains stack data
      var data:Collection is readable := singly_linked_list.new

      // @post adds element to top of stack
      // @param item the value to be added
      method push(item:Dynamic)->Void is public{data.addFirst(item)}

      // @pre stack is not empty
      // @post removes top element from stack
      /// @return value removed
      method pop->Dynamic is public{
             if (size > 0) then {data.removeFirst}
             else{ 
                 print "Can't pop from empty stack"
                 missing}
      }

      // @pre stack is not empty
      // @post @return top element of stack
      method peek->Dynamic is public{data.firstElement}
      
      // @post @return number of elements in stack     
      method size->Number is public{data.size}

      // @post removes all elements from stack
      method clear->Void is public{data.clear}

      // @post @return true iff val is element of stack
      // @param val the value sought
      method contains(val:Dynamic)->Boolean is public{data.contains(val)}

      // @post @return true iff no elements in stack
      method isEmpty->Boolean is public{size == 0}

      // @post @return iterator to traverse stack, starting at top
      method iterator->Iterator is public{data.iterator}

      // @post @return string representation of stack
      method asString->String is public{""}
}