class Node:
	def __init__( self, payLoad, next=None ):
		self.payLoad = payLoad
		self.next = next

class LinkedList:
	head = None
	def __init__( self, *args ):
		for item in args:
			self.insert( item )

	# allow print to work correctly.
	# def __str__(self):
	# 	return self.print()

	# allow += and + operates to work correctly  
	def __add__( self, item ):
		self.insert( item )

		return self

	# allow the in operator to work
	def __iter__(self):
		current = self.head

		while current:
			yield current.payLoad
			current = current.next

	# allow the len() function to be used
	def __len__( self ):
		return self.find( None )['count']

	# internal method check if node is a node object
	def __check_Node( self, node ):
		if not isinstance(node, Node):
			return Node(node)

		return node

	def find( self, match ):
		''' Searches the list for a matching node. If found it will return the
			current node, last node as Node objects and position as an int.
			If nothing is found, it will return None, the last node as a Node
			object, and the full length of the list as an int.

			This function will ONLY return the first match.

			setting match to None will find the end of the list and return the
			last node as return['last']

			This method does alot of the heavy lifting.
		'''

		current = self.head
		last = None
		count = 0

		while current:
			if current.payLoad == match:
				return {'current': current, 'last': last, 'count': count}

			last = current
			current = current.next
			count += 1

		return {'current': current, 'last': last, 'count': count}

	def insert( self, item, after=None ):
		# check to see if adding a whole LinkedList
		if isinstance(item, self.__class__):
			self.find(None)['last'].next = item.head
			return self

		item = self.__check_Node( item )

		# figures out the position of the node
		previous_node = self.find(after)['current'] if after else self.find(None)['last']

		# if the after node isnt found, do nothing.
		if not previous_node: return None;

		item.next = previous_node.next
		previous_node.next = item

		return item

	def print_right( self ):

		def rec( current ):
			if not current: return 'None'
			return rec( current.next ) + ' <= ' + current.payLoad

		return( rec( self.head ) + ' <= head' )

	def __str__( self ):
		current = self.head
		out = 'head' + ' => '

		while current:
			out += current.payLoad + ' => '
			current = current.next

		return out + 'None'

	def __repr__( self ):
		return self.__str__()

	def delete( self, payLoad ):
		match, before, count = self.find( payLoad )
		if match:
			before.next = match.next
			return match

		return None

if __name__ == '__main__':
	l2 = LinkedList('a')
	l2.insert('b')
	l2.insert('c')
	l2 += Node('d')
	l2.insert('1', 'c')
	print(l2)

	l = LinkedList( Node('1') )
	l.insert( Node('2'))
	l.insert( Node('3'))
	l.insert( Node('4'))
	l += Node('5')
	l.insert('a')
	l3 = l + l2
	print( l.print_right() )
