#! /usr/bin/env python

# Scan MH folder, display results in window

import os
import sys
import regex
import getopt
import string
import mhlib

from Tkinter import *

from dialog import dialog

mailbox = os.environ['HOME'] + '/Mail'

def main():
	global root, tk, top, mid, bot
	global folderbox, foldermenu, scanbox, scanmenu, viewer
	global folder, seq
	global mh, mhf

	# Parse command line options

	folder = 'inbox'
	seq = 'all'
	try:
		opts, args = getopt.getopt(sys.argv[1:], '')
	except getopt.error, msg:
		print msg
		sys.exit(2)
	for arg in args:
		if arg[:1] == '+':
			folder = arg[1:]
		else:
			seq = arg

	# Initialize MH

	mh = mhlib.MH()
	mhf = mh.openfolder(folder)

	# Build widget hierarchy

	root = Tk()
	tk = root.tk

	top = Frame(root)
	top.pack({'expand': 1, 'fill': 'both'})

	# Build right part: folder list

	right = Frame(top)
	right.pack({'fill': 'y', 'side': 'right'})

	folderbar = Scrollbar(right, {'relief': 'sunken', 'bd': 2})
	folderbar.pack({'fill': 'y', 'side': 'right'})

	folderbox = Listbox(right, {'exportselection': 0})
	folderbox.pack({'expand': 1, 'fill': 'both', 'side': 'left'})

	foldermenu = Menu(root)
	foldermenu.add('command',
		       {'label': 'Open Folder',
			'command': open_folder})
	foldermenu.add('separator')
	foldermenu.add('command',
		       {'label': 'Quit',
			'command': 'exit'})
	foldermenu.bind('<ButtonRelease-3>', folder_unpost)

	folderbox['yscrollcommand'] = (folderbar, 'set')
	folderbar['command'] = (folderbox, 'yview')
	folderbox.bind('<Double-1>', open_folder, 1)
	folderbox.bind('<3>', folder_post)

	# Build left part: scan list

	left = Frame(top)
	left.pack({'expand': 1, 'fill': 'both', 'side': 'left'})

	scanbar = Scrollbar(left, {'relief': 'sunken', 'bd': 2})
	scanbar.pack({'fill': 'y', 'side': 'right'})

	scanbox = Listbox(left, {'font': 'fixed'})
	scanbox.pack({'expand': 1, 'fill': 'both', 'side': 'left'})

	scanmenu = Menu(root)
	scanmenu.add('command',
		     {'label': 'Open Message',
		      'command': open_message})
	scanmenu.add('command',
		     {'label': 'Remove Message',
		      'command': remove_message})
	scanmenu.add('command',
		     {'label': 'Refile Message',
		      'command': refile_message})
	scanmenu.add('separator')
	scanmenu.add('command',
		     {'label': 'Quit',
		      'command': 'exit'})
	scanmenu.bind('<ButtonRelease-3>', scan_unpost)

	scanbox['yscrollcommand'] = (scanbar, 'set')
	scanbar['command'] = (scanbox, 'yview')
	scanbox.bind('<Double-1>', open_message)
	scanbox.bind('<3>', scan_post)

	# Separator between middle and bottom part

	rule2 = Frame(root, {'bg': 'black'})
	rule2.pack({'fill': 'x'})

	# Build bottom part: current message

	bot = Frame(root)
	bot.pack({'expand': 1, 'fill': 'both'})
	#
	viewer = None

	# Window manager commands

	root.minsize(800, 1) # Make window resizable

	# Fill folderbox with text

	setfolders()

	# Fill scanbox with text

	rescan()

	# Enter mainloop

	root.mainloop()

def folder_post(e):
	x, y = e.x_root, e.y_root
	foldermenu.post(x - 10, y - 10)
	foldermenu.grab_set()

def folder_unpost(e):
	tk.call('update', 'idletasks')
	foldermenu.grab_release()
	foldermenu.unpost()
	foldermenu.invoke('active')

def scan_post(e):
	x, y = e.x_root, e.y_root
	scanmenu.post(x - 10, y - 10)
	scanmenu.grab_set()

def scan_unpost(e):
	tk.call('update', 'idletasks')
	scanmenu.grab_release()
	scanmenu.unpost()
	scanmenu.invoke('active')

scanparser = regex.compile('^ *\([0-9]+\)')

def open_folder(e=None):
	global folder, mhf
	sel = folderbox.curselection()
	if len(sel) != 1:
		if len(sel) > 1:
			msg = "Please open one folder at a time"
		else:
			msg = "Please select a folder to open"
		dialog(root, "Can't Open Folder", msg, "", 0, "OK")
		return
	i = sel[0]
	folder = folderbox.get(i)
	mhf = mh.openfolder(folder)
	rescan()

def open_message(e=None):
	global viewer
	sel = scanbox.curselection()
	if len(sel) != 1:
		if len(sel) > 1:
			msg = "Please open one message at a time"
		else:
			msg = "Please select a message to open"
		dialog(root, "Can't Open Message", msg, "", 0, "OK")
		return
	cursor = scanbox['cursor']
	scanbox['cursor'] = 'watch'
	tk.call('update', 'idletasks')
	i = sel[0]
	line = scanbox.get(i)
	if scanparser.match(line) >= 0:
		num = string.atoi(scanparser.group(1))
		m = mhf.openmessage(num)
		if viewer: viewer.destroy()
		from MimeViewer import MimeViewer
		viewer = MimeViewer(bot, '+%s/%d' % (folder, num), m)
		viewer.pack()
		viewer.show()
	scanbox['cursor'] = cursor

def interestingheader(header):
	return header != 'received'

def remove_message(e=None):
	itop = scanbox.nearest(0)
	sel = scanbox.curselection()
	if not sel:
		dialog(root, "No Message To Remove",
		       "Please select a message to remove", "", 0, "OK")
		return
	todo = []
	for i in sel:
		line = scanbox.get(i)
		if scanparser.match(line) >= 0:
			todo.append(string.atoi(scanparser.group(1)))
	mhf.removemessages(todo)
	rescan()
	fixfocus(min(todo), itop)

lastrefile = ''
tofolder = None
def refile_message(e=None):
	global lastrefile, tofolder
	itop = scanbox.nearest(0)
	sel = scanbox.curselection()
	if not sel:
		dialog(root, "No Message To Refile",
		       "Please select a message to refile", "", 0, "OK")
		return
	foldersel = folderbox.curselection()
	if len(foldersel) != 1:
		if not foldersel:
			msg = "Please select a folder to refile to"
		else:
			msg = "Please select exactly one folder to refile to"
		dialog(root, "No Folder To Refile", msg, "", 0, "OK")
		return
	refileto = folderbox.get(foldersel[0])
	todo = []
	for i in sel:
		line = scanbox.get(i)
		if scanparser.match(line) >= 0:
			todo.append(string.atoi(scanparser.group(1)))
	if lastrefile != refileto or not tofolder:
		lastrefile = refileto
		tofolder = None
		tofolder = mh.openfolder(lastrefile)
	mhf.refilemessages(todo, tofolder)
	rescan()
	fixfocus(min(todo), itop)

def fixfocus(near, itop):
	n = scanbox.size()
	for i in range(n):
		line = scanbox.get(`i`)
		if scanparser.match(line) >= 0:
			num = string.atoi(scanparser.group(1))
			if num >= near:
				break
	else:
		i = 'end'
	scanbox.select_from(i)
	scanbox.yview(itop)

def setfolders():
	folderbox.delete(0, 'end')
	for fn in mh.listallfolders():
		folderbox.insert('end', fn)

def rescan():
	global viewer
	if viewer:
		viewer.destroy()
		viewer = None
	scanbox.delete(0, 'end')
	for line in scanfolder(folder, seq):
		scanbox.insert('end', line)

def scanfolder(folder = 'inbox', sequence = 'all'):
	return map(
		lambda line: line[:-1],
		os.popen('scan +%s %s' % (folder, sequence), 'r').readlines())

main()
