# $Id: account.py 4704 2014-01-16 05:30:46Z ming $
#
# pjsua Python GUI Demo
#
# Copyright (C)2013 Teluu Inc. (http://www.teluu.com)
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
#
import sys
if sys.version_info[0] >= 3: # Python 3
	import tkinter as tk
	from tkinter import ttk
	from tkinter import messagebox as msgbox
else:
	import Tkinter as tk
	import tkMessageBox as msgbox
	import ttk

import random
import pjsua2 as pj
import _pjsua2
import accountsetting
import application
import call
import chat as ch

# Account class
class Account(pj.Account):
	"""
	High level Python Account object, derived from pjsua2's Account object.
	"""
	def __init__(self, app):
		pj.Account.__init__(self)
		self.app = app
		self.randId = random.randint(1, 9999)
		self.cfg =  pj.AccountConfig()
		self.cfgChanged = False
		self.buddyList = []
		self.chatList = []
		self.deleting = False

	def findChat(self, uri_str):
		uri = ch.ParseSipUri(uri_str)
		if not uri: return None
			
		for chat in self.chatList:
			if chat.isUriParticipant(uri) and chat.isPrivate():
				return chat
		return None
	
	def newChat(self, uri_str):
		uri = ch.ParseSipUri(uri_str)
		if not uri: return None
			
		chat = ch.Chat(self.app, self, uri)
		self.chatList.append(chat)
		self.app.updateWindowMenu()
		return chat
	
	def statusText(self):
		status = '?'
		if self.isValid():
			ai = self.getInfo()
			if ai.regLastErr:
				status = self.app.ep.utilStrError(ai.regLastErr)
			elif ai.regIsActive:
				if ai.onlineStatus:
					if len(ai.onlineStatusText):
						status = ai.onlineStatusText
					else:
						status = "Online"
				else:
					status = "Registered"
			else:
				if ai.regIsConfigured:
					if ai.regStatus/100 == 2:
						status = "Unregistered"
					else:
						status = ai.regStatusText
				else:
					status = "Doesn't register"
		else:
			status = '- not created -'
		return status
        	
	def onRegState(self, prm):
		self.app.updateAccount(self)

        def onIncomingCall(self, prm):
		c = call.Call(self, call_id=prm.callId)
                call_prm = pj.CallOpParam()
		call_prm.statusCode = 180
		c.answer(call_prm)
		ci = c.getInfo()
		msg = "Incoming call for account '%s'" % self.cfg.idUri
		if msgbox.askquestion(msg, "Accept call from '%s'?" % (ci.remoteUri), default=msgbox.YES) == u'yes':
			call_prm.statusCode = 200
			c.answer(call_prm)
			
			# find/create chat instance
			chat = self.findChat(ci.remoteUri)
			if not chat: chat = self.newChat(ci.remoteUri)
			
			chat.showWindow()
			chat.registerCall(ci.remoteUri, c)
			chat.updateCallState(c, ci)
		else:
			c.hangup(call_prm)
			
	def onInstantMessage(self, prm):
		chat = self.findChat(prm.fromUri)
		if not chat: chat = self.newChat(prm.fromUri)
		
		chat.showWindow()
		chat.addMessage(prm.fromUri, prm.msgBody)
		
	def onInstantMessageStatus(self, prm):
		if prm.code/100 == 2: return
		
		chat = self.findChat(prm.toUri)
		if not chat:
			print "=== IM status to '%s' cannot find chat" % prm.toUri
			return
		
		chat.addMessage(None, "Failed sending message to '%s': %s" % (prm.toUri, prm.reason))
		
	def onTypingIndication(self, prm):
		chat = self.findChat(prm.fromUri)
		if not chat:
			print "=== Incoming typing indication from '%s' cannot find chat" % prm.fromUri
			return
		
		chat.setTypingIndication(prm.fromUri, prm.isTyping)

		
# Account frame, to list accounts
class AccountListFrame(ttk.Frame):
	"""
	This implements a Frame which contains account list and buttons to operate
	on them (Add, Modify, Delete, etc.). 
	"""
	def __init__(self, parent, app, acc_list = []):
		ttk.Frame.__init__(self, parent, name='acclist')
		self.app = app
		self.accList = acc_list
		self.accDeletedList = []
		self.pack(expand='yes', fill='both')
		self._createWidgets()
		for acc in self.accList:
			self._showAcc(acc)
		
	def _createWidgets(self):
		self.tv = ttk.Treeview(self, columns=('ID', 'Registrar', 'Default'), selectmode='browse')
		self.tv.heading('#0', text='Priority')
		self.tv.heading(0, text='ID')
		self.tv.heading(1, text='Registrar')
		self.tv.heading(2, text='Default?')
		self.tv.column('#0', width=60)
		self.tv.column(0, width=300)
		self.tv.column(1, width=200)
		self.tv.column(2, width=60)
		self.tv.grid(column=0, row=0, rowspan=4, padx=5, pady=5)
		
		ttk.Button(self, text='Add..', command=self._onBtnAdd).grid(column=1, row=0, padx=5)
		ttk.Button(self, text='Settings..', command=self._onBtnSettings).grid(column=1, row=1)
		ttk.Button(self, text='Set Default', command=self._onBtnSetDefault).grid(column=1, row=2)
		ttk.Button(self, text='Delete..', command=self._onBtnDelete).grid(column=1, row=3)

	def _showAcc(self, acc):
		is_default = 'Yes' if acc.isValid() and acc.isDefault() else ''
		values = (acc.cfg.idUri, acc.cfg.regConfig.registrarUri, is_default)
		self.tv.insert('', 0, str(acc.randId), open=True, text=str(acc.cfg.priority), values=values)
	
	def updateAccount(self, acc):
		is_default = 'Yes' if acc.isValid() and acc.isDefault() else ''
		values = (acc.cfg.idUri, acc.cfg.regConfig.registrarUri, is_default)
		self.tv.item(str(acc.randId), text=str(acc.cfg.priority), values=values)
	
	def _getSelectedAcc(self):
		items = self.tv.selection()
		if not items:
			return None
		iid = int(items[0])
		return [acc for acc in self.accList if acc.randId==iid][0]
	
	def _onBtnAdd(self):
		cfg = pj.AccountConfig()
		dlg = accountsetting.Dialog(self.master, cfg)
		if dlg.doModal():
			acc = Account(self.app)
			acc.cfg = cfg
			self._showAcc(acc)
			self.accList.append(acc)
			self.cfgChanged = True
	
	def _onBtnSettings(self):
		acc = self._getSelectedAcc()
		if not acc:
			return
		dlg = accountsetting.Dialog(self.master, acc.cfg)
		if dlg.doModal():
			self.updateAccount(acc)
			self.cfgChanged = True

	def _onBtnDelete(self):
		acc = self._getSelectedAcc()
		if not acc:
			return
		msg = "Do you really want to delete account '%s'" % acc.cfg.idUri
		if msgbox.askquestion('Delete account?', msg, default=msgbox.NO) != u'yes':
			return
		self.accList.remove(acc)
		self.accDeletedList.append(acc)
		self.tv.delete( (str(acc.randId),) )

	def _onBtnSetDefault(self):
		acc = self._getSelectedAcc()
		if not acc:
			return
		if acc.isValid():
			acc.setDefault()
		for acc in self.accList:
			self.updateAccount(acc)
		
		
if __name__ == '__main__':
	application.main()
