#!/usr/bin/env python
#
# iutwilio.py
#

import os
import sys
import argparse
import twilio
import xml.etree.ElementTree as ET

try:
	import configparser
except ImportError:
	import ConfigParser as configparser

from argparse import ArgumentParser
from twilio.rest import TwilioRestClient

account_sid= ''
auth_token = ''
my_number  = ''
sms_number  = ''


#
# command line option
def parse_command_line():
	parser = ArgumentParser()
	parser.add_argument(
		'-v'
		, '--version'
		, action='version'
		, version=u'%(prog)s version 0.4'
	)
	parser.add_argument(
		'--ini'
		, help = 'ini file path. (inifile section [Twilio] account_sid,auth_token,number,sms_number)'
		, default = 'config.ini'
	)
	parser.add_argument(
		'--call'
		, metavar = 'NUMBER'
		, help = 'call to number.'
	)
	parser.add_argument(
		'--sms'
		, metavar = 'NUMBER'
		, help = 'send message number.'
	)
	parser.add_argument(
		'--account_sid'
		, metavar = 'SID'
		, help = 'account sid.'
	)
	parser.add_argument(
		'--auth_token'
		, metavar = 'TOKEN'
		, help = 'auth token.'
	)
	parser.add_argument(
		'--number'
		, help = 'twilio phone number.'
	)
	parser.add_argument(
		'--dump'
		, action = 'store_true'
		, help = 'dump setting.'
	)
	parser.add_argument(
		'--dryrun'
		, action = 'store_true'
		, help = 'dryrun.'
	)
	parser.add_argument(
		'--url'
		, help = 'TwiML url.'
		, default = 'http://twimlbin.com/2e6ad348'
	)
	parser.add_argument(
		'xml'
		, metavar='XML'
		, help = 'test result xml file'
		, nargs='?'
	)
	options = parser.parse_args()
	
	if not options.dump:
		if not options.xml:
			if not options.call:
				parser.print_help()
	
	return options

#
# setup
def setup(options):
	global account_sid
	global auth_token
	global my_number
	global sms_number
	if options.account_sid:
		account_sid = options.account_sid
	if options.auth_token:
		auth_token = options.auth_token
	if options.number:
		my_number = options.number
		sms_number = options.number

#
# get ini
def get_ini(ini, s, n):
	try:
		return ini.get(s, n)
	except:
		return None

#
# parse ini
def parse_ini(path):
	global account_sid
	global auth_token
	global my_number
	global sms_number
	if account_sid and auth_token and my_number:
		return
	ini = configparser.SafeConfigParser()
	if not os.path.exists(path):
		sys.stderr.write('%s not found...' % path)
		sys.exit(2)
	ini.read(path)
	
	account_sid = get_ini(ini, 'Twilio', 'account_sid')
	auth_token = get_ini(ini, 'Twilio', 'auth_token')
	my_number = get_ini(ini, 'Twilio', 'number')
	sms_number = get_ini(ini, 'Twilio', 'sms_number')
		
#	for section in ini.sections():
#		print('[%s]' % (section))
#		for key in ini.options(section):
#			print('%s.%s =%s' % (section, key, ini.get(section, key)))

#
# parse xml
def parse_xml(path):
	tree = ET.parse(path)
	root = tree.getroot()
	testsuites = root.find('[@failures]')
	return testsuites.attrib['failures']

#
# make twilio client
def make_twilio():
	client = TwilioRestClient(account_sid, auth_token)
	return client

#
# call twilio
def call(client, options):
	if options.dryrun:
		print('twilio call to ' + options.call)
	else:
		call = client.calls.create(url=options.url,
			to=options.call,
			from_=my_number)
		print(call.sid)


#
# make_message
def make_message(options):
	body = ""
	filepath = options.xml
	if filepath and os.path.exists(filepath):
		tree = ET.parse(filepath)
		root = tree.getroot()
		tests = int(root.get('tests'))
		testcases = len(root.findall('testsuite'))
		failures = int(root.get('failures'))
		disabled = int(root.get('disabled'))
		skipped = int(root.get('skip'))
		passed = tests - failures - skipped
		time = root.get('time')
		timestamp = root.get('timestamp')

		if timestamp:
			body += "%s\n" % (timestamp)
		first_failure = None
		
		body += "%d tests from %s testcase ran. (%sms total)\n" % (tests, testcases, time)
		if passed:
			body += "PASSED  : %d\n" % (passed)
		if disabled:
			body += "DISABLED: %d\n" % (disabled)
		if skipped:
			body += "SKIPPED : %d\n" % (skipped)
		if failures:
			body += "FAILED  : %d\n" % (failures)
		failure_testsuites = root.findall('testsuite')
		for suite in failure_testsuites:
			if int(suite.get('failures')):
				for test in suite:
					failure_node = test.find('.//failure')
					if failure_node != None:
						if not first_failure:
							first_failure = failure_node
						name = "%s.%s\n" % ( suite.get('name'), test.get('name') )
						if len(body) + len(name) < 155:
							body += name;
						else:
							body += "..."
							return body
		if first_failure != None:
			for s in first_failure.text.split('\n'):
				if len(body) + len(s) < 155:
					body += "%s\n" % s
				else:
					body += "..."
					return body
	return body


#
# message
def message(client, options):
	m = make_message(options)
	if options.dryrun:
		print('twilio call to ' + options.sms)
		print(m)
	else:
		call = client.messages.create(body=m,
			to=options.sms,
			from_=sms_number)
		print(call.sid)

#
# run
def run(options):
	filepath = options.xml
	if filepath:
		if not os.path.exists(filepath):
			sys.exit(1)
		else:
			if int(parse_xml(filepath)) > 0:
				if options.sms:
					message(make_twilio(), options)
				elif options.call:
					call(make_twilio(), options)
				else:
					print('was failed ' + filepath)
	else:
		if options.call:
			call(make_twilio(), options)

	sys.exit(0)

#
# dump
def dump(options):
	print('account_sid: %s' % (account_sid))
	print('auth_token : %s' % (auth_token))
	print('my_number  : %s' % (my_number))
	if options.call:
		print('call       : %s' % (options.call))
	if options.sms:
		print('sms        : %s' % (options.sms))

#
#
def main():
	options = parse_command_line()
	setup(options)
	parse_ini(options.ini)
	if options.dump:
		dump(options)
	else:
		run(options)

if __name__ == '__main__':
	main()
