import pygtk
pygtk.require('2.0')
import gtk
import socket
import sys
import pynotify

def check_port(host, port):
	socket.setdefaulttimeout(2.0)
	s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	try:
		s.connect((host, port))
		s.shutdown(2)
		return True
	except:
		return False

# list to check; url:port, active - is this record used?, success - result of the last check
# the optional string 'alias' defines the name to show in the menu instead of url:port
sites = [{'url': 'localhost', 'port': 80, 'alias': 'localhost', 'active': True, 'success': None}]

# how often should we check, in sec
check_every = 30.0

class PortsCheckerTray:
	def __init__(self):
		if not pynotify.init("Ports checker"):
			sys.exit(1)

		self.statusIcon = gtk.StatusIcon()
		self.menu = gtk.Menu()

		self.last_result = None
		self.check_ports_cb()

		self.statusIcon.connect('popup-menu', self.popup_menu_cb, self.menu)
		self.statusIcon.set_visible(True)

		gtk.main()

	def set_icon(self, success):
		if success:
			self.statusIcon.set_from_stock(gtk.STOCK_APPLY)
		else:
			self.statusIcon.set_from_stock(gtk.STOCK_STOP)
		# count up/down numbers
		up_cnt = 0
		down_cnt = 0
		for d in sites:
			if not d['active']:
				continue
			if d['success']:
				up_cnt = up_cnt + 1
			else:
				down_cnt = down_cnt + 1
		self.statusIcon.set_visible(True)
		self.statusIcon.set_tooltip("Ports checker [" + str(up_cnt) + " up, " + str(down_cnt) + " down]")

	def get_name(self, site_dict):
		if 'alias' in site_dict:
			return site_dict['alias']
		else:
			return site_dict['url'] + ":" + str(site_dict['port'])

	def populate_menu(self):
		for mi in self.menu.get_children():		# just remove all items from menu, repopulate from scratch
			self.menu.remove(mi)
		for d in sites:
			if d['active'] != True:
				continue
			name = self.get_name(d)
			if d['success']:
				self.menuItem = gtk.MenuItem("up: " + name)
			else:
				self.menuItem = gtk.MenuItem("DOWN: " + name)
			self.menu.append(self.menuItem)
			self.menuItem.show()
		self.menuItem = gtk.SeparatorMenuItem()
		self.menu.append(self.menuItem)
		self.menuItem.show()
		self.menuItem = gtk.ImageMenuItem(gtk.STOCK_QUIT)
		self.menuItem.connect('activate', self.quit_cb, self.statusIcon)
		self.menu.append(self.menuItem)

	def notify_about(self, changed):
		nots = []
		for d in changed:
			if d['success']:
				msg = self.get_name(d) + " is online."
			else:
				msg = self.get_name(d) + " is OFFLINE."
			nots.append(msg)
		n = pynotify.Notification("Ports checker", "\n".join(nots))
		return n.show()

	def check_ports_cb(self):
		global sites
		#for d in sites:
		#	print d
		changed = []
		all_passed = True
		for d in sites:
			if d['active'] != True:
				continue
			ret = check_port(d['url'], d['port'])
			if d['success'] != ret:
				d['success'] = ret
				changed.append(d)
			if ret == False:
				all_passed = False

		# create list of checked sites in the menu, based on the results
		if changed != []:
			self.populate_menu()
			self.notify_about(changed)

		# update the status icon if the overall result changed
		if self.last_result != all_passed:
			self.set_icon(all_passed)
			self.last_result = all_passed

		self.statusIcon.connect('popup-menu', self.popup_menu_cb, self.menu)
		self.statusIcon.set_visible(True)

		# we're ready for another round of checks in 5 secs
		global check_every
		gtk.timeout_add(int(check_every * 1000), self.check_ports_cb)

	def quit_cb(self, widget, data = None):
		gtk.main_quit()

	def popup_menu_cb(self, widget, button, time, data = None):
		if button == 3:
			if data:
				data.show_all()
				data.popup(None, None, gtk.status_icon_position_menu,
						3, time, self.statusIcon)

if __name__ == "__main__":
	portsChecker = PortsCheckerTray()
