# vim: set fileencoding=UTF-8
#
# definitions.py
#
# Copyright © 1998-2006 James Henstridge, John Finlay and Others
# Copyright © 2007-2010 Operational Dynamics Consulting, Pty Ltd
# 
# The code in this file, and the program it is a part of, is made available
# to you by its authors as open source software: you can redistribute it
# and/or modify it under the terms of the GNU General Public License version
# 2 ("GPL") as published by the Free Software Foundation.
#
# 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 GPL for more details.
#
# You should have received a copy of the GPL along with this program. If not,
# see http://www.gnu.org/licenses/. The authors of this program may be
# contacted through http://java-gnome.sourceforge.net/.
#

#
# This code imported from pygtk, the Python language bindings for GTK and
# GNOME, then stripped down to the task of round-tripping .defs data from
# a single stream of data into individual files.
#

import copy
import sys

def get_valid_scheme_definitions(defs):
    return [x for x in defs if isinstance(x, tuple) and len(x) >= 2]

# New Parameter class, wich emulates a tuple for compatibility reasons
class Parameter(object):
    def __init__(self, ptype, pname, pdflt, pnull, pdir=None):
        self.ptype = ptype
        self.pname = pname
        self.pdflt = pdflt
        self.pnull = pnull
        self.pdir = pdir

    def __len__(self): return 4
    def __getitem__(self, i):
        return (self.ptype, self.pname, self.pdflt, self.pnull)[i]

    def merge(self, old):
        if old.pdflt is not None:
            self.pdflt = old.pdflt
        if old.pnull is not None:
            self.pnull = old.pnull

# Parameter for property based constructors
class Property(object):
    def __init__(self, pname, optional, argname):
        self.pname = pname
        self.optional = optional
        self.argname = argname

    def merge(self, old):
        if old.optional is not None:
            self.optional = old.optiona
l
        if old.argname is not None:
            self.argname = old.argname


class Definition:
    docstring = "NULL"
    def __init__(self, *args):
        """Create a new defs object of this type.  The arguments
 are the
        components of the definition"""
        raise RuntimeError, "this is an abstract class"
    def merge(self, old):
        """Merge in customisations from older version of definition"""
        raise RuntimeError, "this is an abstract class"
    def write_defs(self, fp=sys.stdout):
        """write out this definition in defs file format"""
        raise RuntimeError, "this is an abstract class"

    def guess_return_value_ownership(self):
        "return 1 if caller owns return value"
        if getattr(self, 'is_constructor_of', False):
            self.caller_owns_return = True
        elif self.ret in ('char*', 'gchar*', 'string'):
            self.caller_owns_return = True
        else:
            self.caller_owns_return = False
    
    def whichClass(self):
        self.write_defs()
        raise RuntimeError, "This method must be overridden"


class ObjectDef(Definition):
    def __init__(self, name, *args):
        self.name = name
        self.module = None
        self.parent = None
        self.c_name = None
        self.typecode = None
        self.fields = []
        self.implements = []
        self.class_init_func = None
        self.has_new_constructor_api = False
        for arg in get_valid_scheme_definitions(args):
            if arg[0] == 'in-module':
                self.module = arg[1]
            elif arg[0] == 'docstring':
                self.docstring = make_docstring(arg[1:])
            elif arg[0] == 'parent':
                self.parent = arg[1]
            elif arg[0] == 'c-name':
                self.c_name = arg[1]
            elif arg[0] == 'gtype-id':
                self.typecode = arg[1]
            elif arg[0] == 'fields':
                for parg in arg[1:]:
                    self.fields.append((parg[0], parg[1]))
            elif arg[0] == 'implements':
                self.implements.append(arg[1])
    def merge(self, old):
        # currently the .h parser doesn't try to work out what fields of
        # an object structure should be public, so we just copy the list
        # from the old version ...
        self.fields = old.fields
        self.implements = old.implements
    def write_defs(self, fp=sys.stdout):
        fp.write('(define-object ' + self.name + '\n')
        if self.module:
            fp.write('  (in-module "' + self.module + '")\n')
        if self.parent:
            fp.write('  (parent "' + self.parent + '")\n')
        for interface in self.implements:
            fp.write('  (implements "' + interface + '")\n')
        if self.c_name:
            fp.write('  (c-name "' + self.c_name + '")\n')
        if self.typecode:
            fp.write('  (gtype-id "' + self.typecode + '")\n')
        if self.fields:
            fp.write('  (fields\n')
            for (ftype, fname) in self.fields:
                fp.write('    \'("' + ftype + '" "' + fname + '")\n')
            fp.write('  )\n')
        fp.write(')\n\n')

    def whichClass(self):
        return self.c_name

class InterfaceDef(Definition):
    def __init__(self, name, *args):
        self.name = name
        self.module = None
        self.c_name = None
        self.typecode = None
        self.vtable = None
        self.fields = []
        self.interface_info = None
        for arg in get_valid_scheme_definitions(args):
            if arg[0] == 'in-module':
                self.module = arg[1]
            elif arg[0] == 'docstring':
                self.docstring = make_docstring(arg[1:])
            elif arg[0] == 'c-name':
                self.c_name = arg[1]
            elif arg[0] == 'gtype-id':
                self.typecode = arg[1]
            elif arg[0] == 'vtable':
                self.vtable = arg[1]
        if self.vtable is None:
            self.vtable = self.c_name + "Iface"
    def write_defs(self, fp=sys.stdout):
        fp.write('(define-interface ' + self.name + '\n')
        if self.module:
            fp.write('  (in-module "' + self.module + '")\n')
        if self.c_name:
            fp.write('  (c-name "' + self.c_name + '")\n')
        if self.typecode:
            fp.write('  (gtype-id "' + self.typecode + '")\n')
        fp.write(')\n\n')

    def whichClass(self):
        return self.c_name


class EnumDef(Definition):
    def __init__(self, name, *args):
        self.deftype = 'enum'
        self.name = name
        self.in_module = None
        self.c_name = None
        self.typecode = None
        self.values = []
        for arg in get_valid_scheme_definitions(args):
            if arg[0] == 'in-module':
                self.in_module = arg[1]
            elif arg[0] == 'c-name':
                self.c_name = arg[1]
            elif arg[0] == 'gtype-id':
                self.typecode = arg[1]
            elif arg[0] == 'values':
                for varg in arg[1:]:
                    self.values.append((varg[0], varg[1]))
    def merge(self, old):
        pass
    def write_defs(self, fp=sys.stdout):
        fp.write('(define-' + self.deftype + ' ' + self.name + '\n')
        if self.in_module:
            fp.write('  (in-module "' + self.in_module + '")\n')
        fp.write('  (c-name "' + self.c_name + '")\n')
        fp.write('  (gtype-id "' + self.typecode + '")\n')
        if self.values:
            fp.write('  (values\n')
            for name, val in self.values:
                fp.write('    \'("' + name + '" "' + val + '")\n')
            fp.write('  )\n')
        fp.write(')\n\n')
    
    def whichClass(self):
        return self.c_name


class FlagsDef(EnumDef):
    def __init__(self, *args):
        apply(EnumDef.__init__, (self,) + args)
        self.deftype = 'flags'



class BoxedDef(Definition):
    def __init__(self, name, *args):
        self.name = name
        self.module = None
        self.c_name = None
        self.typecode = Non