# Lasso - A free implementation of the Liberty Alliance specifications.
#
# Copyright (C) 2004-2007 Entr'ouvert
# http://lasso.entrouvert.org
#
# Authors: See AUTHORS file in top-level directory.
#
# 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 re
import string

_mapping_convert_type_from_gobject_annotation = {
        'utf8': 'char*'
}

def convert_type_from_gobject_annotation(type):
    return _mapping_convert_type_from_gobject_annotation.get(type, type)

def clean_type(type):
    type = type.strip()
    type = re.sub('\s+', ' ', type)
    return re.sub('\s*\*\s*', '*', type)

def format_as_camelcase(var):
    '''Format an identifier name into CamelCase'''
    if '_' in var:
        return format_underscore_as_camelcase(var)
    if var[0] in string.uppercase:
        var = var[0].lower() + var[1:]
    var = re.sub(r'([a-z])(ID)([A-Z]|$)', r'\1Id\3', var) # replace standing ID by Id
    return var

def format_as_underscored(var):
    '''Format an identifier name into underscored_name'''
    def rep(s):
        return s.group(0)[0] + '_' + s.group(1).lower()
    var = re.sub(r'[a-z0-9]([A-Z])', rep, var).lower()
    var = var.replace('id_wsf2_', 'idwsf2_')
    var = var.replace('_saslresponse', '_sasl_response')
    return var

def format_underscore_as_camelcase(var):
    '''Format an underscored identifier name into CamelCase'''
    def rep(s):
        return s.group(1)[0].upper() + s.group(1)[1:]
    var = re.sub(r'_([A-Za-z0-9]+)', rep, var)
    var = re.sub(r'([a-z])(ID)([A-Z]|$)', r'\1Id\3', var) # replace standing ID by Id
    return var



def last(x):
    return x[len(x)-1]

def common_prefix(x,y):
    max = min(len(x),len(y))
    last = 0
    for i in range(max):
        if x[i] != y[i]:
            return min(i,last+1)
        if x[i] == '_':
            last = i
    return max

def pgroup(group,prev):
    level, l = group
    i = 0
    for x in l:
        if i == 0:
            prefix = prev
        else:
            prefix = level
        if isinstance(x,tuple):
            pgroup(x,prefix)
        else:
            print prefix * ' ' + x[prefix:]
        i = i + 1

def group(list):
    list.sort()
    pile = [(0,[])]
    prev = ""
    for x in list:
        l, g = last(pile)
        u = common_prefix(x,prev)
        # Find the good level of insertion
        while u < l:
            pile.pop()
            l, g = last(pile)
        # Insert here
        if u == l:
            g.append(x)
        elif u > l:
            t = (u, [g.pop(),x])
            g.append(t)
            pile.append(t)
        prev = x
    return pile[0]



def _test_arg(arg, what):
    return bool(arg[2].get(what))

def is_optional(arg):
    return _test_arg(arg, 'optional')

def element_type(arg):
    return arg[2].get('element-type')

def key_type(arg):
    return arg[2].get('key-type')

def value_type(arg):
    return arg[2].get('value-type')

def is_out(arg):
    return _test_arg(arg, 'out') or (arg_type(arg).endswith('**') and not _test_arg(arg, 'in'))


def is_glist(arg):
    return re.match('GList\>', var_type(arg))

def is_hashtable(arg):
    return re.match('GHashTable\>', var_type(arg))

def var_type(arg):
    '''Return the type of variable to store content'''
    if is_out(arg):
        return arg[0][:-1]
    else:
        return arg[0]

def unref_type(arg):
    return (var_type(arg), arg[1], arg[2])

def ref_name(arg):
    if is_out(arg):
        return '&%s' % arg[1]
    else:
        return arg[1]

def arg_type(arg):
    return arg[0]

def arg_name(arg):
    return arg[1]

def unconstify(type):
    return re.sub(r'\bconst\b\s*', '', type).strip()

def make_arg(type):
    return (type,'',{})

def arg_default(arg):
    return arg[2].get('default')

def remove_modifiers(type):
    type = re.sub(r'\s*\bunsigned\b\s*', ' ', type).strip()
    type = re.sub(r'\s*\bconst\b\s*', ' ', type).strip()
    type = re.sub(r'\s*\bsigned\b\s*', ' ', type).strip()
    type = re.sub(r'\s*\bvolatile\b\s*', ' ', type).strip()
    return clean_type(type)

def is_const(arg):
    return bool(re.search(r'\bconst\b', arg_type(arg)))

def is_cstring(arg):
    return unconstify(arg_type(arg)) in ('char*','gchar*','guchar*')

def is_xml_node(arg):
    return unconstify(arg_type(arg)).startswith('xmlNode')

def is_boolean(arg):
    return arg_type(arg) in ('gboolean','bool')

def is_pointer(arg):
    return arg_type(arg).endswith('*')

def is_list(arg):
    return unconstify(arg_type(arg)).startswith('GList')

def is_int(arg, binding_data):
    return arg_type(arg) in [ 'int', 'gint', 'long', 'glong'] + binding_data.enums

def is_time_t_pointer(arg):
    return re.match(r'\btime_t\*', unconstify(arg_type(arg)))

def is_transfer_full(arg):
    transfer = arg[2].get('transfer')
    if transfer:
        return transfer == 'full'
    else:
        return is_out(arg) or is_object(arg)

_not_objects = ( 'GHashTable', 'GList', 'GType' )

def is_object(arg):

    t = unconstify(arg_type(arg))
    return t[0] in string.uppercase and not [ x for x in _not_objects if x in t ]
