#!/usr/bin/python -B

from string import Template, upper, replace

from ApiUtil    import outputCode
from ApiCodeGen import *

from RegalContextInfo import cond

lookupSourceTemplate = Template( '''${AUTOGENERATED}
${LICENSE}

#include "pch.h" /* For MS precompiled header support */

#include "RegalUtil.h"

REGAL_GLOBAL_BEGIN

#include "RegalPrivate.h"
#include "RegalLookup.h"

REGAL_GLOBAL_END

REGAL_NAMESPACE_BEGIN

namespace Lookup {

${CODE}

}

REGAL_NAMESPACE_END

''')

def generateLookupSource(apis, args):

  code = []

  for i in apis:
    names = []
    for j in i.functions:
      names.append(j.name)

    regalOnly = set()
    for j in i.functions:
      if getattr(j,'regalOnly',False)==True:
        regalOnly.add(j.name);

    if i.name in cond:
      code.append( '#if %s'%cond[i.name] )

    code.extend(pointerLookupByNameCode([ (j,j) for j in names ],("%s_Name"%i.name,"%s_Value"%i.name),valueCast = '(void *)(%s)'))

    #

    code.append( 'const size_t %s_Offset[%d] = {'       % (i.name, len(names)+1) ) # terminating NULL

    names.sort()

    # offset table
    table = "DispatchTableGlobal"
    if( i.name == "gl" ):
        table = "DispatchTable"

    for j in names:
      if j in regalOnly:
        code.append("  0,")
      else:
        if i.name == "gl":
          code.append("  offsetof(%s,%s)/sizeof(void *),"%(table,j))
        else:          
          code.append("  ((char *)(&dispatchTableGlobal.%s)-(char *)(&dispatchTableGlobal))/sizeof(void *),"%(j))
    
    code.append( '  0')
    code.append('};')
    code.append('')

    if i.name in cond:
      code.append( '#endif' )
    code.append( '' )

  substitute = {}

  substitute['LICENSE']       = args.license
  substitute['AUTOGENERATED'] = args.generated
  substitute['COPYRIGHT']     = args.copyright
  substitute['CODE']          = '\n'.join(code)

  outputCode( '%s/RegalLookup.cpp' % args.outdir, lookupSourceTemplate.substitute(substitute))

##############################################################################################

lookupHeaderTemplate = Template( '''${AUTOGENERATED}
${LICENSE}

#ifndef __${HEADER_NAME}_H__
#define __${HEADER_NAME}_H__

#include "RegalUtil.h"

REGAL_GLOBAL_BEGIN

#include <cstdlib>
#include <cstring>

REGAL_GLOBAL_END

REGAL_NAMESPACE_BEGIN

namespace Lookup {

inline int NameCmp(const void *a, const void *b)
{
  return std::strcmp(*(const char **) a, *(const char **) b);
}

${CODE}

}

REGAL_NAMESPACE_END

#endif
''')

def generateLookupHeader(apis, args):

  code = []

  for i in apis:

    if i.name in cond:
      code.append( '#if %s'%cond[i.name] )

    names = []
    for j in i.functions:
      names.append( j.name )

    lName  = '%s_Name'%i.name
    lValue = '%s_Value'%i.name
    lOffset = '%s_Offset'%i.name
    lSize   = len(names)+1

    code.append( '' )
    code.append( 'extern const char * const %s[%d];'%(lName,lSize) )
    code.append( 'extern const void *%s[%d];'%(lValue,lSize) )
    code.append( 'extern const size_t %s[%d];'%(lOffset,lSize) )

    code.append('''

template<typename T>
T
%s(const char *name, T def = NULL)
{
  const char **res = (const char **) std::bsearch(&name, %s, %d, sizeof(const char *), NameCmp);
  return res ? reinterpret_cast<T>(const_cast<void *>(%s[(size_t) (res - %s)])) : def;
}

'''%('%s_Lookup'%i.name,lName,lSize-1,lValue,lName))

    code.append('''

inline size_t %s(const char *name)
{
  const char **res = (const char **) std::bsearch(&name, %s, %d, sizeof(const char *), NameCmp);
  return res ? %s[(size_t) (res - %s)] : 0;
}

'''%('%s_LookupOffset'%i.name,lName,lSize-1,lOffset,lName))

    if i.name in cond:
      code.append( '#endif' )
    code.append( '' )

  substitute = {}

  substitute['LICENSE']       = args.license
  substitute['AUTOGENERATED'] = args.generated
  substitute['COPYRIGHT']     = args.copyright
  substitute['HEADER_NAME']   = "REGAL_LOOKUP"
  substitute['CODE']          = '\n'.join(code)

  outputCode( '%s/RegalLookup.h' % args.outdir, lookupHeaderTemplate.substitute(substitute))

