import re
import sys
import string
import clint

class Stack:
	def __init__(self, start=[]):
		self.stack = None
		for i in range(-len(start), 0):
			self.push(start[-i - 1])

	def push(self,node):
		self.stack = node, self.stack

	def pop(self):
		node, self.stack = self.stack
		return node

	def top(self):
		node = self.pop()
		self.push(node)
		return node

	def empty(self):
		return not self.stack


class header_guard(clint.Rule):
	def initialize(self):
		self.stack = Stack()
		self.gather_info()
		self.ifndef = re.compile("^#\W*ifndef\W+(?P<header>.*)")
		self.define = re.compile("^#\W*define\W+(?P<header>.*)")

	def gather_info(self):
		self.current_info = {}
		self.current_info['filename'] = self.file()
		self.current_info['have_ifndef'] = 0
		self.current_info['have_define'] = 0
		self.current_info['reported_error'] = 0
		self.current_info['guard_name'] = ""

	def pop(self):
		self.current_info = self.stack.pop()
	
	def top(self):
		return self.stack.top()

	def push(self):
		self.stack.push(self.current_info)
		self.gather_info()

	def pre_cpp(self,line):
		# deal with changing files
		if self.current_info['filename'] != self.file(): 
			# The file has changed
			if self.top()['filename'] == self.file():
				# we have gone back a file
				self.pop()
			else: 
				# We are in a new file
				self.push()

		# now preform the test
		if self.is_header() and not self.is_system_header and not self.current_info['reported_error']:
			# strip comments and then whitespace from the line
			line = string.strip(self.remove_comments(line))
			if line != "": #and self.current_info['have_ifndef'] == 0 and self.current_info['have_define'] == 0:
				if self.current_info['have_ifndef'] == 0:
					# we haven't found #ifndef yet
					match = self.ifndef.match(line)
					if match:
						# we have found #ifndef 
						self.current_info['have_ifndef'] = self.line()
						self.current_info['guard_name']  = match.group('header')
					else:
						# we haven't found a #ifndef
						self.error()
				elif self.current_info['have_define'] == 0:
					# we have found #ifndef, now look for #define
					match = self.define.match(line)
					if match:
						# we found a #define
						self.current_info['have_define'] = self.line()
						if self.current_info['guard_name'] != match.group('header'):
							# the guard name doesn't match the #define
							self.error()
					else:
						# we haven't found a #define
						self.error()

	def error(self):
		self.message("You should protect the header file with #ifndef / #define")
		self.current_info['reported_error'] = 1
		


syntax highlighted by Code2HTML, v. 0.9.1