#!/usr/bin/env python

from mx import DateTime
from mx.DateTime import DateTimeType
DateTimeType = DateTimeType
DateTime = DateTime # we'll install this in the module context

import locale
import calendar, time
import xmlrpclib

class MetadataServiceException(Exception):
	pass

# FIXME optimize this function
def is_utf8_encoded(string):
	try: st = transcode(string,"UTF-8","UTF-8",forced = True)
	except (UnicodeDecodeError,UnicodeEncodeError): return False
	return True

def transcode_to_platform_encoding(string,source_encoding):
	""" Transcode a regular string from a source encoding to the platform's target encoding"""
	if type(string) is not str: raise ValueError
	return transcode(string,source_encoding,locale.getpreferredencoding())

def platform_to_utf8(string):
	""" This function takes a platform-encoded string and transcodes it to a plain string encoded in UTF-8 """
	return transcode(string,locale.getpreferredencoding(),"UTF-8")

def utf8_to_platform(string):
	""" This function takes an UTF-8 encoded string and transcodes it to a plain string encoded in your platform's preferred encoding """
	return transcode(string,"UTF-8",locale.getpreferredencoding())

def transcode_to_utf8_encoding(string,source_encoding):
	""" Transcode a regular string from a source encoding to the platform's target encoding"""
	if type(string) is not str: raise ValueError
	return transcode(string,source_encoding,locale.getpreferredencoding())

def transcode(string,input_encoding,output_encoding, forced = False):
	""" Transcodes a regular string from a source encoding to the target encoding """
	if type(string) is not str: raise ValueError
	if input_encoding == output_encoding and not forced: return string
	return convert_from_unicode(convert_to_unicode(string,input_encoding),output_encoding)

def convert_to_unicode(a,source_encoding=None):
	""" Converts a plain string into a Unicode object.  The string is assumed to be encoded in the source_encoding, or in the platform's encoding if None"""
	if source_encoding is None: source_encoding = locale.getpreferredencoding()
	if type(a) is str: return unicode(a,source_encoding)
	elif type(a) is unicode: return a
	else: raise ValueError

def convert_from_unicode(a,target_encoding):
	""" Converts a Unicode object into a plain string, encoded in the target_encoding """
	if type(a) is unicode: return a.encode(target_encoding)
	else: raise ValueError

def local_timestamp_to_utc(ts):
	""" Returns the equivalent UTC timestamp for the passed local timestamp"""
	return calendar.timegm(time.localtime(ts))
	
def utc_timestamp_to_local(ts):
	""" Returns the equivalent local timestamp for the passed UTC timestamp"""
	ts = int(ts)
	localtime = local_timestamp_to_utc(ts)
	offset = ts - localtime
	return ts + offset


def shell_quote(string):
	return "'%s'" % string.replace("'","'\\''")
	
import re
def remove_whitespace(text): # canonicalizes whitespace! yay!
	return re.compile("\s+").sub(" ",text).strip()

def detect_encoding(text):
	"""Detects encoding of a short piece of text.  Doesn't go beyond FIXME characters.  Can return None if no encoding could be detected."""
	# FIXME, this is a stub
	return None
	if is_utf8_encoded(text): return "UTF-8"
	else: return None
	
	
	
import types
import locale
# make the reverse function!
def to_platform_strings(params):
	"""Take an array, list, dictionary of parameters which contains strings, and convert all Unicode instances to platform-encoded strings."""
	if type(params) is list:
# 		print "stringifying list %s" % params
		return [ to_platform_strings(param) for param in params ]
	elif type(params) is tuple:
# 		print "stringifying tuple %s" % params
		return tuple([ to_platform_strings(param) for param in params ])
	elif isinstance(params,types.DictType):
# 		print "stringifying dictionary %s" % params
		resdict = {}
		for key,value in params.iteritems():
			resdict[to_platform_strings(key)] = to_platform_strings(value)
		return resdict
	elif type(params) is unicode:
# 		print "stringifying unicode %s" % params
		return convert_from_unicode(params,locale.getpreferredencoding())
	else:
# 		print "stringifying other type %s %s" % (type(params),params)
		return params


def from_platform_strings(params):
	"""Take an array, list, dictionary of parameters which contains strings, and reencodes all string instances to utf8 strings, assuming that the source encoding is the platform's."""
	if type(params) is list:
# 		print "stringifying list %s" % params
		return [ to_platform_strings(param) for param in params ]
	elif type(params) is tuple:
# 		print "stringifying tuple %s" % params
		return tuple([ to_platform_strings(param) for param in params ])
	elif isinstance(params,types.DictType):
# 		print "stringifying dictionary %s" % params
		resdict = {}
		for key,value in params.iteritems():
			resdict[to_platform_strings(key)] = to_platform_strings(value)
		return resdict
	elif type(params) is str:
# 		print "stringifying unicode %s" % params
		return convert_to_unicode(params)
	else:
# 		print "stringifying other type %s %s" % (type(params),params)
		return params


def from_xml_params(params):
	"""Take an array, list, dictionary of parameters which contains strings, and convert all Unicode instances to platform-encoded strings."""
	f = from_xml_params
	if type(params) is list: return [ f(param) for param in params ]
	elif type(params) is tuple: return tuple([ f(param) for param in params ])
	elif isinstance(params,types.DictType):
		resdict = {}
		for key,value in params.iteritems(): resdict[f(key)] = f(value)
		return resdict
	elif type(params) is unicode: return convert_from_unicode(params,locale.getpreferredencoding())
	elif isinstance(params,xmlrpclib.DateTime):
		# convert the (UTC) xmlrpclib.DateTime instance into a (UTC) mx.DateTime instance
		params = DateTime.strptime(params.value,"%Y%m%dT%H:%M:%S")
		return params
	return params


def to_xml_params(params):
	"""Take an array, list, dictionary of parameters which contains strings, and reencodes all string instances to utf8 strings, assuming that the source encoding is the platform's."""
	f = to_xml_params
	if type(params) is list: return [ f(param) for param in params ]
	elif type(params) is tuple: return tuple([ f(param) for param in params ])
	elif isinstance(params,types.DictType):
		resdict = {}
		for key,value in params.iteritems(): resdict[f(key)] = f(value)
		return resdict
	elif type(params) is str: return params
	elif type(params) is DateTimeType:
		# convert the (UTC) mx.DateTime instance into a (UTC) xmlrpclib.DateTime instance 
		params = xmlrpclib.DateTime(utc_timestamp_to_local(params.gmticks()))
		return params
	return params
