#!python

"""
static function template binding generator for reflect.
"""

sigfile = file('FunctionSignature.hpp', 'w')

def Guard(text):
    sigfile.write('#ifndef %s\n' % text)
    sigfile.write('#define %s\n\n' % text)
    def end(): sigfile.write('#endif // %s\n' % text)
    return end

def Namespaces(*namespaces):
    sigfile.write(' '.join(['namespace %s {' % ns for ns in namespaces]) + '\n\n')
    def end(): sigfile.write(' '.join(['}' for ns in namespaces]) + '\n\n')
    return end

def FunctionSignature(nargs, classtype, const_func):
    sigfile.write(
        'template<typename ResultType%s%s>\n' 
         % (classtype and ', typename ClassType' or '',
            ''.join([', typename A%d' % arg for arg in range(0, nargs)]),
            ))

    sigfile.write(
        'class FunctionSignature<ResultType (%s*)(%s)%s>\n{\n' % (
            classtype and 'ClassType::' or '',
            ', '.join(['A%d' % arg for arg in range(0, nargs)]),
            const_func and ' const' or ''
        ))

    if nargs > 0:
        sigfile.write(
            '\t' + 'typedef FunctionSignature<void (*)(%s)> BaseFunctionSignature;\n' % 
            ', '.join(['A%d' % arg for arg in range(0, nargs-1)]))

    sigfile.write(
        '\t' + 'typedef ResultType (%s*FunctionType)(%s)%s;\n' %
        ( classtype and 'ClassType::' or '', 
        ', '.join(['A%d' % arg for arg in range(0, nargs)]),
        const_func and ' const' or ''
    ))
    
    sigfile.write('public:\n')
    sigfile.write(
"""\tenum
\t{ 
\t    ParameterCount = %d,
\t    MemberFunction = %s,
\t    ConstMemberFunction = %s
\t};\n\n"""
       % (nargs, 
          classtype and 'true' or 'false', 
          const_func and 'true' or 'false'))
    for i in range(0, nargs):
        sigfile.write('\ttypedef ParameterHelper<A%d> P%d;\n' % (i,i))
    sigfile.write('\n')
    if nargs > 0:
        sigfile.write('\ttypedef P%d LastParamType;\n\n' % (nargs-1))
        sigfile.write('\tstatic const Type *GetParameterType(int index, bool *is_mutable = 0)\n' + 
                      '\t{\n' + 
                      '\t\treturn index == ParameterCount-1\n' + 
                      '\t\t    ? ((is_mutable ? (void)(*is_mutable = LastParamType::MutableParameter) : (void)0), TypeOf<typename LastParamType::Type>())\n' +
                      '\t\t    : BaseFunctionSignature::GetParameterType(index, is_mutable);\n')
    else:
        sigfile.write('\tstatic const Type *GetParameterType(int, bool *)\n' + 
                      '\t{\n' +
                      '\t\treturn 0;\n')
    sigfile.write('\t}\n\n')

    sigfile.write('\ttypedef ResultType TheResultType;\n' +
                  '\tstatic const Type *GetResultType() { return TypeOf<typename ParameterHelper<ResultType>::Type>(); }\n')

    if classtype:
        sigfile.write(
			'\ttypedef ClassType TheClassType;\n'
			'\tstatic const Type *GetClassType() { return TypeOf<typename ParameterHelper<ClassType>::Type>(); }\n')
    else:
        sigfile.write(
			'\ttypedef void TheClassType;\n' +
			'\tstatic const Type *GetClassType() { return 0; }\n')

    params = ', '.join(('arg%d' % i) for i in range(0,nargs))
    args = '\n\t\t'.join(
            [''] + ['typename P%d::ArgType arg%d = P%d::Arg(args[%d]);' 
              % (i,i,i,i) for i in range(0,nargs)]) + '\t\t\n'
    
    
    sigfile.write(
       ('\tstatic ResultType Call(const FunctionType &function, const Variant &%s, Variant *%s)\n' +
        '\t{' +
        args +
        (classtype and ('\t\t%sClassType &self = object.As%sRef<%sClassType>();\n' % 
			((const_func and 'const ' or ''), (const_func and 'Const' or ''), (const_func and 'const ' or ''))) or '') +
        '\t\treturn %s(' + params + ');\n' +
        '\t}\n') %
        (classtype and 'object' 
                    or '',
         nargs > 0 and 'args' or '',
         classtype and '(self.*function)'
                    or '(*function)'))
        

    def end(): sigfile.write('};\n\n')
    return end

class Stack:
    def __init__(self, *args, **kwargs):
        self.stack = []
    def begin(self):
        self.stack.append([])
    def end(self):
        self.unwind(self.stack[-1])
        del self.stack[-1]
    def add(self,fun):
        self.stack[-1].append(fun)
    def unwind(self, frame):
        for fun in frame[::-1]:
            if fun: fun()

stack = Stack()

stack.begin()
stack.add(sigfile.close)
stack.add(Guard('REFLECT_FUNCTION_FUNCTIONSIGNATURE_HPP_'))

sigfile.write("""
#include <reflect/Variant.h>

"""[1:])

stack.add(Namespaces('reflect', 'function'))

sigfile.write(
"""
// File: FunctionSignature.hpp
// Autogenerated template bindings for reflecting functions in a generic way.
//
// This is the first stage in creating a generic run-time interface for functions,
// it takes the inconsistent compile-time interface of function calls, and 
// makes it into a consistent compile-time interface.
//
// The second stage is in reflect/function/Function.hpp which
// takes the compile-time consistent (template) interface and
// makes it run-time consistent.
//
// The third stage is in reflect/function/Function.{h,cpp} which defines the
// run-time interface and provides some wrappers.

// Class: VariantAliasRef
// The VariantAliasRef automates
// flushing modified by-reference parameters
// back into their source values.
//
//    * When it destructs, it updates the values of any <Variant::Alias>-ed variants, and
//    * You can view its value in a debugger. (optional)
template<typename T>
class VariantAliasRef
{
public:
	VariantAliasRef(Variant &var)
		: mVar(var)
#ifndef NO_DEBUG_FUNCTION_ALIAS
		, mValue(var.AsRef<T>())
#endif
	{}
	
	operator T &() const
	{ 
#ifndef NO_DEBUG_FUNCTION_ALIAS
		return mValue;
#else
		return var.AsRef<T>();
#endif
	}

	~VariantAliasRef()
	{
		mVar.UpdateAliases();
	}
private:
	Variant &mVar;
#ifndef NO_DEBUG_FUNCTION_ALIAS
	T &mValue;
#endif
};

template<typename Type_>
struct ParameterHelper
{
  typedef Type_ Type;
  typedef const Type &ArgType;
  static inline const Type &Arg(Variant &variant) { return variant.AsConstRef<Type>(); }
  enum { MutableParameter = false };
};

template<typename Type_>
struct ParameterHelper<const Type_>
{
  typedef Type_ Type; 
  typedef const Type &ArgType;
  static inline const Type &Arg(Variant &variant) { return variant.AsConstRef<Type>(); }
  enum { MutableParameter = false };
};

template<typename Type_>
struct ParameterHelper<Type_&>
{
  typedef Type_ Type;
  typedef VariantAliasRef<Type> ArgType;
  static inline Variant &Arg(Variant &variant) { return variant; }
  enum { MutableParameter = true };
};

template<typename Type_>
struct ParameterHelper<const Type_ &>
{
  typedef Type_ Type;
  typedef const Type &ArgType;
  static inline const Type &Arg(Variant &variant) { return variant.AsConstRef<Type>(); }
  enum { MutableParameter = false };
};

template<>
struct ParameterHelper<void>
{
  typedef void Type;
  static inline const void Arg(Variant &) { return; }
};

template<typename FunctionType> class FunctionSignature;
"""[1:])

for classtype in (False,True):
    for const_func in classtype and (False,True) or (False,):
        for i in range(0,16):
            stack.begin()
            stack.add(FunctionSignature(i, classtype, const_func))
            stack.end()

stack.end()

assert(sigfile.closed)

#sigfile = file(sigfile.name, 'r')
#for line in sigfile:
#   print line,
#sigfile.close()
