#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-

####################################################################################
# "THE BEER-WARE LICENSE" (Revision 42):
# Rick Rein <jeebusroxors@gmail.com> wrote this file. As long as you retain 
# this notice you can do whatever you want with this stuff. If we meet some day, 
# and you think this stuff is worth it, you can buy me a beer in return Rick Rein
####################################################################################

import sys,os,xmpp,string,threading,time,curses,getpass
from time import strftime

## do i need to touch dnspython/pydns 
class config(object):

	def parseconfig(self):
		""" Parses ~/.jigrc and returns dict 'config'"""
		config={}
		if ( os.access(os.environ['HOME'] + '/.jigrc', os.R_OK) ):
			for line in file(os.environ['HOME'] + '/.jigrc'):
				if ( line[0] != "#" ):
					if not line.isspace():
						line = line.strip()
						values = line.split('=')
						values[0] = values[0].strip()
						values[1] = values[1].strip()
						config[values[0]] = values[1]
		else:
			curses.endwin()
			print os.environ['HOME'] + '/.jigrc not found'
			sys.exit(1)

		config = self.checkConfig(config)
		return config

	def checkConfig(self,config):
		""" Checks sanity of config """

		if not config.has_key('jid'):
			#configJID = config['jid']
		#else:
			print 'error: no JID in ~/.jigrc'
			sys.exit(1)

		if not config.has_key('password'):
		#	configPass = config['password']
		#else:
			inputPass = getpass.getpass('password: ')
			config['password'] = inputPass
		return config

class jabbercli(threading.Thread):

	def __init__(self,jid,password):
		threading.Thread.__init__(self)
		self.jid = jid
		self.password = password
		self.userjid = xmpp.protocol.JID(jid)

		self.cmdprompt = cmdprompt()
		self.connect = self.auth()

	def auth(self):
		"""Authenticate with Jabber"""
		client = xmpp.Client(self.userjid.getDomain(), debug=[])
		if ( client.connect() == "" ):
			print 'Connection Failure'
			sys.exit(1)
		if ( client.auth(self.userjid.getNode(), self.password, resource="jig") == None ):
			print 'awthentificashun failed'
			sys.exit(1)
		client.RegisterHandler('chat',self.recievemsg)
		client.RegisterHandler('message',self.recievemsg)
		client.RegisterHandler('disconnect',self.discon)
		client.RegisterHandler('presence',self.presence)
		client.sendInitPresence(requestRoster=1)
		return client
		

	def sendmsg(self,input,tojid,fromjid):
		""" Send message object """
		curtime = strftime("%I:%M:%S %p")
		maxSize = rxWin.getmaxyx()

		if ( input[0] == 'r' ):
			message = ' '.join(input[1:])

		elif (input[0] == 'm'):
			message = ' '.join(input[2:])
		
		self.connect.send(xmpp.protocol.Message(tojid, message, typ='chat'))
		fromjid = fromjid.split('@')
		
		rxWin.scroll(1)
		rxWin.move(int(maxSize[0]-1),0)
		rxWin.clrtoeol()

		rxWin.addstr( '[' + curtime + '] ' + fromjid[0] + '> ' + message )
		rxWin.refresh()

	# Handlers
	def discon(self):
			curses.endwin()
			sys.exit(1)
			print 'DISCON HANDLER'

	def presence(self,connection,prs):
		""" Presence handler """
		# Thank you gajim!

		curtime = strftime("%I:%M:%S %p")

        	ptype = prs.getType()
        	who = prs.getFrom()
        	status = prs.getStatus()
        	xmlShow = prs.getShow()
        	show = ''

        	if ptype == 'available':
                	ptype = None
        	rfc_types = ('unavailable', 'away' 'error', 'subscribe', 'subscribed', 'unsubscribe', 'unsubscribed')
        	if ptype and not ptype in rfc_types:
                	ptype = None

        	if not ptype and not show:
               		show = 'Online'

        	elif ptype == 'unavailable':
                	show = 'Offline'

        	if xmlShow == 'away':
                	show = 'Away'

        	elif xmlShow == 'chat':
                	show = 'Free For Chat'

        	elif xmlShow == 'chat':
                	show = 'Free For Chat'

		who = str(who).split('/')
		
		if not status:
			status = ''
		else:
			status = ': ' + status

		if ( show != 'Offline' ):
			if roster.count(who[0]) < 1:
				roster.append(who[0])

		statusDict[who[0]] = status
		showDict[who[0]] = show

		curpos = txWin.getyx()
		maxSize = rxWin.getmaxyx()

		rxWin.scroll(1)
		rxWin.move(int(maxSize[0] - 1), 0)
		rxWin.addstr('[' + curtime + '] ' + who[0] + ' is now ' + show + status )
		txWin.move(0,curpos[1])
		rxWin.refresh()
		txWin.refresh()


	def recievemsg(self,connection,msg):
		""" Incoming message handler """
		global replyJID
		# 1 line
		curpos = txWin.getyx()
		maxSize = rxWin.getmaxyx()

		body = str(msg.getBody())
		curtime = strftime("%I:%M:%S %p")

		sentFromJID = str(msg.getFrom())
		replyJID = sentFromJID
		sentfrom = sentFromJID.split('@')
		sentfrom = sentfrom[0]
		
		msgLines = len(body) / maxSize[1] 
		msgLines = msgLines + 1
		rxWin.scroll(msgLines)
		rxWin.move(int(maxSize[0] - 1), 0)

		# incoming msg format - inc in config?
		rxWin.addstr('[' + curtime + '] ' + sentfrom + '> ' + body)
		txWin.move(0,curpos[1])
		rxWin.refresh()
		txWin.refresh()
	
	def roster(self):
		rosterName = self.connect.getRoster()

		maxSize = rxWin.getmaxyx()
		rosterSize = len(roster)
		rxWin.scroll(rosterSize + 3)

		rxWin.move( int(maxSize[0] - rosterSize - 3),0)

		rxWin.addstr('\nName / JID :: Status\n')
		rxWin.addstr('--------------------------\n')

		for contacts in range(len(roster)):
			contactNumber = str(contacts)   # numbered list
			contactJID = roster[contacts]   # JID
			contactName =  rosterName.getName(roster[contacts]) # cute nickname
			jidNum[contactNumber] = contactJID    # dict num to JID

			if showDict.has_key(contactJID):
				contactShow = showDict[contactJID]
			elif not showDict.has_key(contactJID):
				contactShow = 'Offline ' 
			else:
				contactShow = 'Offline '

			if statusDict.has_key(contactJID):
				contactStatus = statusDict[contactJID]
			else:
				contactStatus = 'None '

			if not contactName:
				contactName = u" "

			#output
			rxWin.addstr(contactNumber + '.')
			if ( contactName != ' ' ):
				rxWin.addstr(' ' + contactName + ' /')
				
			rxWin.addstr(' ' + contactJID + ' :: ')
			rxWin.addstr(contactShow)

			if ( contactStatus != '' ):
				rxWin.addstr(contactStatus + '\n')
			else:
				rxWin.addstr('\n')
		#stdscr.addstr('\n')
		rxWin.refresh()

	def run(self):
		"""Keep alive and processing"""
		last_time = int(time.strftime('%s', time.localtime()))
		keepalive = 30

		while True:
         		self.connect.Process(1)
			now = int(time.strftime('%s',time.localtime()))
			delta = now - last_time
			if ( delta > keepalive ):
				self.connect.send(' ')
				last_time = int(time.strftime('%s', time.localtime()))

class cmdprompt(object):

	def start(self):
		"""Kick off threads, connects and draws the prompt"""
		global jig
		global threadlist
		global stdscr
		global txWin
		global rxWin

		self.configjig = config()
		self.credens = self.configjig.parseconfig()
		self.jid = self.credens['jid']

		stdscr = curses.initscr()
		stdscr.scrollok(True)

		curses.echo()
		curses.cbreak()

		maxSize = stdscr.getmaxyx()
		rxWin = stdscr.subpad(maxSize[0]-1,maxSize[1],0,0)
		rxWin.scrollok(True)

		txWin = stdscr.subpad(1,maxSize[1],maxSize[0]-1,0)
		txWin.scrollok(True)

		jig = jabbercli(self.jid,self.credens['password'])

		threadlist = []
		threadlist.append(jig)
		for thread in threadlist:
			thread.start()

		curses.wrapper(self.prompt())

	def prompt(self):
		"""Prompt"""
		## move to the top/delete/move/insert
		## is a classic example of a function
		##         Why the fuck is it not one?
		global replyJID
		replyJID = ''
		while True:
			maxSize = stdscr.getmaxyx()
			maxy = maxSize[0]
			maxx = maxSize[1]
			# in in config?
			#txWin.addstr(int(maxy-1),0,'jig::' + self.jid + '> ' )
			txWin.addstr('jig::' + self.jid + '> ' )
			txWin.clrtoeol()

			input = txWin.getstr()
			input = input.split()
			stdscr.refresh()
	
			if ( len(input) == 0):
				self.prompt()

			elif ( len(input) > 0):
				cmd = input[0]

			if ( cmd == 'm' ):
				if ( len(input) > 2 ):
					replyJID = input[1]
					tojid = input[1]
					try:
							tojid = int(input[1])
					except:
							pass

					if ( type(tojid) == type(int()) ):
							tojid = str(tojid)
							tojid = jidNum[tojid]
							replyJID = tojid

					jig.sendmsg(input,tojid,self.jid)

				elif ( len(input) <= 2):
					maxSize = rxWin.getmaxyx()
					rxWin.scroll(1)
					rxWin.move(maxSize[0]-1,0)
					rxWin.addstr(int(maxy-2),0, 'usage: m jid@server message' )
					rxWin.refresh()

			elif ( cmd == 'r' ):
				if ( len(input) > 1 ):
					if not replyJID:
						maxSize = rxWin.getmaxyx()
						rxWin.scroll(1)
						rxWin.move(maxSize[0]-1,0)
						rxWin.addstr("can't reply to no one" )
						rxWin.refresh()
					else:
						tojid = replyJID
						jig.sendmsg(input,tojid,self.jid)

				elif ( len(input) == 1 ):
					maxSize = rxWin.getmaxyx()
					rxWin.scroll(1)
					rxWin.move(maxSize[0]-1,0)
					rxWin.addstr(int(maxy-2),0, 'usage: r message' )
					rxWin.refresh()

			elif ( cmd == 'w' ):
				jig.roster()

			elif ( cmd == 'c' ):
				rxWin.clear()
				rxWin.refresh()

			elif ( cmd == 'v' ):
				maxSize = rxWin.getmaxyx()
				rxWin.scroll(1)
				rxWin.move(maxSize[0]-1,0)
				rxWin.addstr('vodka + cran - weeeeeeee')
				rxWin.refresh()

			elif ( cmd == '?') or ( cmd == 'h' ):
				self.usage()

			elif ( cmd == 'q!' ):
				curses.endwin()
				print 'later dude'
				sys.exit(0)

			else:
				rxWin.scroll(1)
				maxSize = rxWin.getmaxyx()
				rxWin.move(maxSize[0]-1,0)
				rxWin.addstr('%s: Command not found' %(cmd))
				rxWin.refresh()

	def usage(self):
		""" Prompt usage object. A futile attempt to keep the prompt code clean """
		maxSize = rxWin.getmaxyx()
		rxWin.scroll(9)

		rxWin.move( int(maxSize[0]-9),0)
		# 9 lines
		rxWin.addstr( "         command              description\n")
		rxWin.addstr( "+-----------------------------------------------------------------+\n")
		rxWin.addstr( "|  m jid@server $message      send $message to jid@server         |\n")
		rxWin.addstr( "|  r $message                 send $message to last outgoing JID  |\n")
		rxWin.addstr( "|  w                          show roster                         |\n")
		rxWin.addstr( "|  c                          clear screen                        |\n")
		rxWin.addstr( "|  ?                          this screen                         |\n")
		rxWin.addstr( "|  q!                         quit                                |\n")
		rxWin.addstr( "+-----------------------------------------------------------------+\n")
		rxWin.refresh()
		
		return()

# this is so messy
if __name__ == "__main__":
	global roster
	global statusDict
	global showDict
	global jidNum

	statusDict = {}
	showDict = {}
	jidNum = {}
	roster = []
	
	goGoGadgetJig = cmdprompt()
	goGoGadgetJig.start()
