"""ListSubmissions.py
Lists submissions, limiting search with options, and using remaining arguments
to format the final output.
Options:
	-cCODE, --code=CODE   Gets submission for the story code
	-mMARKET, --market=MARKET
	                      Gets the stories that have gone to that market
	-yYEAR, --year=YEAR   Limits results to given year
	-sSTATUS, --status=STATUS
                         Limits results to given status (InMail,Reject,Sale)
 	-e, --email           Limits results to email submissions only
 	-p, --postal          Limits results to postal submissions only
 	-b, --usedateback     Sorts results by return date [false by default]
	-i, --in-order        Sorts results by oldest first [default]
	-r, --reverse         Reverses results sorting
	-t, --tabs            Prints report using tabs rather than spaces

Arguments given in order will print the following information:
	CD code
	TL title
	MK market
	DS date sent
	DB date back
	DO days out
	ST status
	NT notes
	nl new line
	tb tab

Customized printing also available through Python's formatting strings. The following
keys can be used: code, story, market, dateback, datesent, daysout, status, note. These
can be combined with the two-letter codes.

Creating an HMTL table of stories in the mail is easy:
	listsubmissions("-sInMail -t <tr><td>TL</td><td>MK</td><td>DS</td><td>DO</td></tr>")
Table data cells (<td>) are converted to table header cells (<th>) automatically.
"""
__author__ = "Josh English (Joshua.R.English@gmail.com)"
__version__ = "$Revision: 1.00 $"
__date__ = "$Date: 2006/09/16 23:17:42 $"
__copyright__ = "Copyright (c) 2006 Josh English"
__license__ = "Python"


__history__ = """History:
	1.00 (Sep 16, 2006) First version. Custom filters and custom displays.
"""
__future_plans__ = """Future Plans:
	Ability to turn off the header entirely
	Ability to turn off the header separator
	Return a list of lines for printing outside SubHandler
"""

from xml.sax import make_parser, SAXException
from xml.sax.handler import ContentHandler
from optparse import OptionParser
from datetime import date
import time

### Printing headers
###   this dictionary is similar to the format of the dictionarys compiled in the ContentHandler
headers={
		'code':'Code',
		'story':'Story',
		'market':'Market',
		'datesent':'Sent',
		'dateback':'Back',
		'note':'Notes',
		'daysout':'Out',
		'status':'Status',
		}
### Date procedures
dateformats = ['%b %d, %Y','%b %d, %y','%m %d %Y','%Y %m %d','%m/%d/%y','%m-%d-%y']
preffereddateformat = dateformats[0]

def StringToDate(ts):
	"""StringToDate(string)
	Takes a string and returns a Date object
	"""
	for df in dateformats:
		try:
			t = time.strptime(ts,df)
			return date(t[0],t[1],t[2])
		except:
			pass
	raise "Cannot parse date string"
	
sub_opt_parser = OptionParser(usage="SubmissionFilter.py [options]",version = "%prog 0.1")

sub_opt_parser.add_option("-c","--code",
		action="store",type="string",dest="code",
		help="Gets submission for the story code",default="All")

sub_opt_parser.add_option("-m","--market",
		action="store",type="string",dest="market",
		help="Gets the stories that have gone to that market",default="All")

sub_opt_parser.add_option("-y","--year",
		action="store",type="string",dest="year",
		help="Limits results to given year",default="All")

sub_opt_parser.add_option("-s","--status",
		action="store",type="string",dest="status",default="All",
		help="Limits results to given status (InMail,Reject,Sale)")

sub_opt_parser.add_option("-e","--email",
		action="store_true",dest="email",default=False,
		help="Limits results to email submissions only")

sub_opt_parser.add_option("-p","--postal",
		action="store_true",dest="postal",default=False,
		help="Limits results to postal submissions only")

sub_opt_parser.add_option("-b","--usedateback",
		action="store_true",dest="usereturndate",default=False,
		help="Sorts results by return date [false by default]")

sub_opt_parser.add_option("-i","--in-order",
		action="store_false",dest="reverse", default=False,
		help="Sorts results by oldest first [default]")

sub_opt_parser.add_option("-r","--reverse",
		action="store_true",dest="reverse",
		help="Reverses results sorting")
		
sub_opt_parser.add_option("-t","--tabs",
		action="store_true",dest="usetabs",default=False,
		help="Prints report using tabs rather than spaces")
		
subfile = "marvin:documents:fiction:subs.xml"


class SubHandler(ContentHandler):
	def __init__(self,argstring=''):
		(self.options,self.args) = sub_opt_parser.parse_args(argstring.split())
		if not self.args:
			self.args = "TL MK DS DB nl NT".split()
		self.write = False  ### write to the buffer?
		self.buffer = ''
		self.keep_track_of = ['code','storycode','story','market','datesent','dateback','status','method','note']
		self.sub_list = []
	
	def startElement(self,name,attrs):
		if name == 'submission': self.data = {}
		self.write = name in self.keep_track_of
			
	def endElement(self,name):
		if name in self.keep_track_of:
			self.data[name] = str(self.buffer.strip())
			self.clearbuffer()
			self.write = False
	
		elif name == "submission":
			### check if our data matches, if so, add current_code to sub_list
			match = True
			match = match and self.options.code in ["All",self.data['storycode']]
			match = match and self.options.status in ["All",self.data['status']]
			match = match and self.options.market in ["All",self.data['market']]
			match = match and self.options.year in ["All",self.data['datesent'][-4:]]
			if self.options.email:match = match and self.data['method']=='email'
			if self.options.postal: match = match and self.data['method']=='mail'
			
			if match: self.sub_list.append((self.data))
			
		elif name == "submissionlist":
			### sort the results
			res = []
			for d in self.sub_list:
				if self.options.usereturndate:
					res.append((StringToDate(d['dateback']),d))
				else:
					res.append((StringToDate(d['datesent']),d))
					
			res.sort()
			if self.options.reverse: res.reverse()
			self.sub_list = [b for a,b in res]
			#exit if nothing to print
			if self.options.code !="All":
				print "Searching for code %s" % self.options.code
			if self.options.market !="All": 
				print "Searching for stories sent to %s" % self.options.market
			if self.options.status !="All":
				print "Searching for %s stories" % self.options.status
			if self.options.email:
				print "Searching for stories that were submitted electronically"
			if self.options.postal:
				print "Searching for stories that were mailed"
			if not self.sub_list: return None
			
			
			longest_story = 0
			longest_market = 0
			for sub in self.sub_list:
				longest_story = max(longest_story,len(sub['story']))
				longest_market = max(longest_market,len(sub['market']))

			format = ' '.join(self.args)
			format=format.replace('CD',"%(code)s")
			format=format.replace('TL',"%(story)s")
			format=format.replace('MK',"%(market)s")
			format=format.replace('DB',"%(dateback)s")
			format=format.replace('DS',"%(datesent)s")
			format=format.replace('DO',"%(daysout)s")
			format=format.replace('ST',"%(status)s")
			format=format.replace('nl',"\n")
			format=format.replace('tb',"\t")
			format=format.replace('NT',"%(note)s")
			if self.options.usetabs: format=format.replace(" ","\t")
			
			headerformat = format.split('\n')[0]
			if not self.options.usetabs:
				headers['story'] = headers['story'].ljust(longest_story)
				headers['market'] = headers['market'].ljust(longest_market)
				headers['status'] = headers['status'].ljust(6)  # length of longest status
				headers['code'] = headers['code'].ljust(12)
				headers['datesent'] = headers['datesent'].ljust(12)
				headers['dateback'] = headers['dateback'].ljust(12)
			#just in case of HTML
			headerformat = headerformat.replace('<td','<th')
			headerformat = headerformat.replace('/td>','/th>')
			
			header = headerformat % headers
			print header
			print '-'*len(header)
			for d in self.sub_list:
				
				if not d.has_key('note'): d['note']=''
				if d.has_key('dateback'):
					d['daysout']=(StringToDate(d['dateback'])-StringToDate(d['datesent'])).days
				else:
					d['daysout']=(date.today()-StringToDate(d['datesent'])).days
					d['dateback']=' '
				if not self.options.usetabs:
					d['story'] = d['story'].ljust(longest_story)
					d['market'] = d['market'].ljust(longest_market)
					d['status'] = d['status'].ljust(6)  # length of longest status
					d['code'] = d['code'].ljust(12)
					d['dateback']=d['dateback'].ljust(12)
					d['daysout']='%3d' % d['daysout']
						
				print format % d
			print "Found %d submissions" % len(self.sub_list)
	def characters(self,chars):
		if self.write: self.buffer += chars
		
	def clearbuffer(self):
		self.buffer = ''
	
	
		
def list_submissions(argstring):
	sh=SubHandler(argstring)
	parser = make_parser()
	parser.setContentHandler(sh)
	parser.parse(open(subfile))
	if not sh.sub_list: print "No submissions found"

print "============"
list_submissions("-sInMail -t <tr><td>TL</td><td>MK</td><td>DS</td><td>DO</td></tr>")


			