import templates, pygments, cgi, db, datetime, settings, os, mimetypes, Cookie, random from pygments import highlight from pygments.lexers import get_all_lexers, get_lexer_by_name from pygments.formatters import HtmlFormatter base62_alphabet = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' class CustomHtmlFormatter(HtmlFormatter): def wrap(self, source, outfile): yield 0, '
'
		line = 1
		for i, t in source:
			yield i, '%s' % (line, t)
			line += 1
		yield 0, '
'

class Paste(object):
	def __init__(self):
		lexers = dict([(x[0], x[1][0]) for x in get_all_lexers()])
		self.lexers = []
		removed = []
		for cat, ls in settings.categories:
			for l in ls:
				removed.append(l)
			self.lexers.append((cat, [(x, lexers[x]) for x in ls]))
		for l in removed:
			try:
				del lexers[l]
			except KeyError:
				pass
		self.lexers.append(('Others' if settings.categories else 'Syntax', sorted(lexers.items(), cmp = lambda a, b: cmp(a[0], b[0]))))
		self.formatter = CustomHtmlFormatter(linenos = 'table', lineanchors = 'line', anchorlinenos = True)

		random.seed()

	def message(self, msg, title = 'Message'):
		self.start_response('200 OK', [('Content-Type', 'text/html; charset=utf-8')])
		return [str(templates.message(searchList = {
			'title': '%s – %s' % (settings.pastebin_name, title),
			'header': title,
			'text': msg,
			}))]

	def paste(self):
		c = Cookie.SimpleCookie(self.environ['HTTP_COOKIE'] if 'HTTP_COOKIE' in self.environ else None)
		if self.environ['REQUEST_METHOD'] == 'POST':
			mp = cgi.FieldStorage(fp = self.environ['wsgi.input'], environ = self.environ, keep_blank_values = True)
			if mp['type'].value == 'Preview':
				return self.preview(mp)
			elif mp['type'].value == 'Paste':
				return self.add_paste(mp)
			else:
				return self.message('Invalid type "%s".' % mp['type'].value, 'Error')
		self.start_response('200 OK', [('Content-Type', 'text/html; charset=utf-8')])
		return [str(templates.paste(searchList = {
			'title': settings.pastebin_name,
			'header': settings.pastebin_name,
			'lexers': self.lexers,
			'default': settings.default,
			'nick': c['nick'].value if 'nick' in c else 'Anonymous',
			'remembered': 'nick' in c,
			}))]

	def preview(self, mp):
		try:
			lex = get_lexer_by_name(mp['syntax'].value.decode('utf8'))
			lexername = lex.name
			text = highlight(mp['text'].value.decode('utf8'), lex, self.formatter)
		except:
			return self.message('Could not find the lexer "%s".' % mp['syntax'].value, 'Error')

		self.start_response('200 OK', [('Content-Type', 'text/html; charset=utf-8')])
		return [str(templates.view(searchList = {
			'title': settings.pastebin_name,
			'header': '%s – Preview' % settings.pastebin_name,
			'hash': None,
			'date': datetime.datetime.utcnow().ctime(),
			'nick': mp['nick'].value.decode('utf8') or 'Anoynmous',
			'syntax': lexername,
			'pastetitle': mp['title'].value.decode('utf8') or 'Untitled',
			'text': text,
			}))]

	def add_paste(self, mp):
		nick = mp['nick'].value.decode('utf8') or None
		syntax = mp['syntax'].value.decode('utf8') or None
		title = mp['title'].value.decode('utf8') or None
		text = mp['text'].value.decode('utf8').replace('\r', '') or None

		hash = ''.join(random.choice(base62_alphabet) for x in xrange(5))

		try:
			session = db.Session()
			paste = db.Paste(hash, nick, datetime.datetime.utcnow(), syntax, title, text)
			session.add(paste)
			session.commit()
		finally:
			session.close()

		headers = [('Location', '/view/%s' % hash)]
		c = Cookie.SimpleCookie()
		c['nick'] = nick
		dt = (datetime.datetime.utcnow() + datetime.timedelta(days = 30)) if 'remember_me' in mp else datetime.datetime.utcfromtimestamp(0)
		c['nick']['expires'] = dt.strftime('%a, %d-%b-%y %H:%M:%S GMT')
		headers.append(('Set-Cookie', c['nick'].OutputString()))
		self.start_response('302 Found', headers)
		return []

	def view(self):
		def get_formatted(syntax, text):
			lex = get_lexer_by_name(syntax or 'text')
			lexername = lex.name
			text = highlight(text, lex, self.formatter)
			return (lexername, text)

		hash = self.path[1]

		try:
			session = db.Session()
			try:
				cache = session.query(db.Cache).filter_by(paste_hash = hash).one()
				paste = cache.paste
			except db.NoResultFound: # No cache found, generate it.
				try:
					paste = session.query(db.Paste).filter_by(hash = hash).one()
				except db.NoResultFound:
					self.start_response('404 Not Found', [])
					return []
				try:
					lexername, text = get_formatted(paste.syntax, paste.text if type(paste.text) == unicode else paste.text.decode('utf8'))
				except:
					return self.message('Could not find the lexer "%s".' % paste.syntax, 'Error')
				cache = db.Cache(hash, lexername, text)
				session.add(cache)
				session.commit()
				# Workaround for attribute refresh.
				paste = cache.paste
		finally:
			session.close()

		self.start_response('200 OK', [('Content-Type', 'text/html; charset=utf-8')])
		return [str(templates.view(searchList = {
			'title': '%s – View paste – %s' % (settings.pastebin_name, paste.title or 'Untitled'),
			'header': '%s – View paste' % settings.pastebin_name,
			'hash': hash,
			'date': paste.date.ctime(),
			'nick': paste.nick or 'Anonymous',
			'syntax': cache.syntax_name,
			'pastetitle': paste.title or 'Untitled',
			'text': cache.text,
			}))]

	def raw(self):
		hash = self.path[1]

		try:
			session = db.Session()
			paste = session.query(db.Paste).filter_by(hash = hash).one()
		finally:
			session.close()

		self.start_response('200 OK', [('Content-Type', 'text/plain; charset=utf-8')])
		return [paste.text.encode('utf8')]

	def highlight_stylesheet(self):
		self.start_response('200 OK', [('Content-Type', 'text/css')])
		return [self.formatter.get_style_defs()]

	def static(self):
		filename = settings.static_root + os.path.sep + self.path[1]
		if not self.path[1] in ('paste.css', 'edit.js', 'view.js') or not os.path.exists(filename):
			self.start_response('404 Not Found', [('Content-Type', 'text/html; charset=utf-8'), ('Location', '/')])
			return ['asdf']
		self.start_response('200 OK', [('Content-Type', mimetypes.guess_type(filename)[0] or 'text/plain; charset=utf-8')])
		return open(filename)

	def __call__(self, environ, start_response):
		self.environ = environ
		self.start_response = start_response

		path = self.environ['PATH_INFO'].split('/')[1:]
		module = path[0] or 'paste'
		if module in ('list', 'paste', 'view', 'raw', 'static', 'highlight_stylesheet'):
			self.path = path
			return getattr(self, module)()
		else:
			return self.message('Invalid module requested.', 'Error')

if __name__ == '__main__':
	from wsgiref.simple_server import make_server
	httpd = make_server('', 8000, Paste())
	httpd.serve_forever()