#!/usr/bin/env python
# -*- coding: utf-8 -*-

from copy import copy
from httplib2 import Http
from urllib import urlencode
import httplib

class Tumblr(object):
	"""Tumblr object.
	
	>>> t = Tumblr("me", "me@example.com", "pass")
	>>> t
	<Tumblr (me, me@example.com)>
	>>> t.url
	'http://www.tumblr.com/api/write'
	>>> l = Link("http://www.linuxfr.org/")
	>>> t.build_data(l)
	{'url': 'http://www.linuxfr.org/', 'password': 'pass', 'type': 'link', 'email': 'me@example.com'}
	"""
	def __init__(self, user, email, password, generator=None):
		self.user = user
		self.email = email
		self.password = password
		self.url = "http://www.tumblr.com/api/write"
		self.generator = generator
	
	def build_data(self, postable):
		if isinstance(postable, Postable):
			d = postable.data()
			for k in ('email', 'password', 'generator'):
				if self.__dict__[k]:
					d[k] = self.__dict__[k]
			
			for k in d.keys():
				d[k] = d[k].encode("utf-8")
			
			return d
	
	def post(self, postable):
		try:
			body = urlencode(self.build_data(postable))
			headers = {"Content-type": "application/x-www-form-urlencoded"}
			h = Http()
			h.follow_all_redirects = True
			resp, content = h.request(self.url, method="POST", body=body, headers=headers)
			
			postable.id = int(content)
			return (resp, content)
		except:
			raise
	
	def get_url(self, postable):
		if isinstance(postable, Postable):
			return u"http://%s.tumblr.com/post/%d" % (self.user, postable.id)
		else:
			raise TypeError
	
	def __repr__(self):
		return "<%s (%s, %s)>" % (type(self).__name__, self.user, self.email)

#
# Message types
#

class Postable(object):
	"""Postable element
	
	>>> Postable("foo")
	Traceback (most recent call last):
	...
	NotImplementedError: This object is abstract
	"""
	
	def __init__(self, type, id=-1):
		if self.__class__ == Postable:
			raise NotImplementedError, "This object is abstract"
			return
		self.type = type
		self.id = id
	
	def data(self):
		d = copy(self.__dict__)
		del(d["id"])
		for k, v in d.items():
			if v is None:
				del(d[k])
		return d

class Authenticate(Postable):
	"""Authenticate only post
	
	>>> a = Authenticate()
	>>> a
	<Authenticate>
	"""
	
	def __init__(self):
		super(Authenticate, self).__init__(None)
		self.action = "authenticate"
	
	def __repr__(self):
		return "<%s>" % (type(self).__name__)

class Regular(Postable):
	"""Regular post
	
	>>> r = Regular("body", "title")
	>>> r
	<Regular -1 (title)>
	>>> r.body
	'body'
	"""
	
	def __init__(self, body, title=None):
		"""title is string, and body is html"""
		super(Regular, self).__init__("regular")
		self.title = title
		self.body = body
	
	def __repr__(self):
		return "<%s %d (%s)>" % (type(self).__name__, self.id, self.title)

class Conversation(Postable):
	"""Conversation post
	
	>>> c = Conversation("conv", "title")
	>>> c
	<Conversation -1 (title)>
	>>> c.conversation
	'conv'
	"""
	
	def __init__(self, conversation, title=None):
		"""title is mandatory, conversation is txt"""
		super(Conversation, self).__init__("conversation")
		self.title = title
		self.conversation = conversation
	
	def __repr__(self):
		return "<%s %d (%s)>" % (type(self).__name__, self.id, self.title)

class Link(Postable):
	"""Link post
	
	>>> l = Link("http://example.org/", "a", "b")
	>>> l
	<Link -1 (http://example.org/)>
	>>> l.name
	'a'
	>>> l.description
	'b'
	"""
	
	def __init__(self, url, name=None, description=None):
		"""name and description (HTML) are mandatory"""
		super(Link, self).__init__("link")
		self.url = url
		self.name = name
		self.description = description
	
	def __repr__(self):
		return "<%s %d (%s)>" % (type(self).__name__, self.id, self.url)

class Quote(Postable):
	"""Quote
	
	>>> q = Quote("Deo Gratias", "foo")
	>>> q
	<Quote -1 (Deo Gratias)>
	>>> q.source
	'foo'
	"""
	
	def __init__(self, quote, source=None):
		"""source (HTML) is mandatory"""
		super(Quote, self).__init__("quote")
		self.quote = quote
		self.source = source
	
	def __repr__(self):
		return "<%s %d (%s)>" % (type(self).__name__, self.id, self.quote)

def _test():
	import doctest
	doctest.testmod(optionflags=doctest.ELLIPSIS)

if __name__ == "__main__":
	_test()
