"""
In-class demo of linked list.
"""

class Node(object):
  def __init__(self, contents):
    self._contents = contents
    self._next_node = None

  def get_next_node(self):
    return self._next_node

  def set_next_node(self, next_node):
    self._next_node = next_node

  def get_contents(self):
    return self._contents

  def set_contents(self, contents):
    self._contents = contents

  def _get_next_recursive(self, index):
    if index == 0:
      return self
    else:
      return self._next_node._get_next_recursive(index-1)

class LinkedList(object):
  def __init__(self):
    self.first_node = None

  def _add_node_to_front(self, node):
    old_first_node = self.first_node
    self.first_node = node
    self.first_node.set_next_node(old_first_node)

  def _add_node_after_front(self, node, index):
    before_node = self._get_node(index-1)
    old_node = before_node.get_next_node()
    before_node.set_next_node(node)
    node.set_next_node(old_node)

  def _get_node(self, index):
    current_node = self.first_node
    for i in range(index):
      current_node = current_node.get_next_node()
    return current_node

  def _get_node_recursive(self, index):
    return self.first_node._get_next_recursive(index)

  # Functions I want a user to interact with

  def add(self, value, index):
    """
    Adds a value to this linked list at the specified index.
    Parameters:
      value: The value to add.
      index: The position at which it should appear.
    Returns: None
    """
    if index == 0:
      node = Node(value)
      self._add_node_to_front(node)
    else:
      node = Node(value)
      self._add_node_after_front(node, index)

  def get(self, index):
    """
    Retrieves a value from this linked list at the specified index.
    Parameters:
      index: The position from which to get a value.
    Returns: The value at that position.
    """
    node = self._get_node(index)
    return node.get_contents()

  def to_normal_list(self):
    """
    Creates a normal Python list from this linked list.
    Returns: A new Python list containing the values that this list contains
             and in the same order.
    """
    node = self.first_node
    lst = []
    while node != None:
      lst.append(node.get_contents())
      node = node.get_next_node()
    return lst

  def __str__(self):
    """
    Produces a string to show this linked list.
    Returns: A string showing the contents of this linked list.
    """
    return str(self.to_normal_list())

  def size(self):
    """
    Determines the size of this linked list.
    Returns: The number of values in this linked list.
    """
    node = self.first_node
    n = 0
    while node != None:
      n += 1
      node = node.get_next_node()
    return n

  def delete(self, index):
    """
    Removes a value from this list.
    Parameters:
      index: The position of the value to remove.
    Returns: None
    """
    if index == 0:
      self.first_node = self.first_node.get_next_node()
    else:
      node = self._get_node(index-1)
      node.set_next_node(node.get_next_node().get_next_node())

  def find(self, value):
    """
    Finds the first position of a value in this linked list.
    Parameters:
      value: The value to find.
    Returns: The first position of that value, or None if the value is not
             in the list.
    """
    node = self.first_node
    n = 0
    while node != None and node.get_contents() != value:
      n += 1
      node = node.get_next_node()
    if node == None:
      return None
    else:
      return n
 
def main():
  lst = LinkedList()
  lst.add("cat",0)
  assert lst.get(0) == "cat"
  lst.add("dog",0)
  lst.add("bear",0)
  assert lst.get(0) == "bear"
  assert lst.get(1) == "dog"
  lst.add("fish",2)
  assert lst.get(2) == "fish"

  assert lst.size() == 4
  lst.add("puma",1)
  assert lst.size() == 5
  assert lst.get(1) == "puma"
  lst.delete(1)
  assert lst.size() == 4
  assert lst.get(1) == "dog"

  assert lst.to_normal_list() == ["bear","dog","fish","cat"]
  assert lst.find("fish") == 2

  print "Tests complete!"

main()



