def refToClassName(ref, needSimple=False):
    '''
    convert a ref string to java class name
    '''
    try:
        refType, refName = util.parseSwaggerRef(ref)
    except RuntimeError:
        print('"%s" is not a swagger reference' % ref)
        return ref
    prefix = ''
    if refType == 'definitions': # models
        prefix = modelPackage
    location = refName.split('/')
    result = prefix
    if len(location) > 0:
        location[-1] = util.camelize(location[-1])
    for l in location:
        result += '.' + l

    # simple class name
    if needSimple:
        result = result.split('.')[-1]

    return result
def renderApi(swagger, templatePath):
    if not isTemplatePathValid(templatePath):
        return
    with open(templatePath) as f:
        template = f.read()
        '''
        api context
        {
            'package': 'xxx',
            'modelPackage': 'xxx',
            'imports': [{'import': 'xxx'}, ...]
            'classname': 'xxx',  // seems that each class is created according to the 'tags''s last item
            'operations': [
                {
                    'summary': 'xxx',
                    'apiDescription': 'xxx',
                    'methodName': 'xxx',
                    'httpMethod': 'xxx',
                    'path': 'xxx',
                    'responseType': 'xxx',
                    'hasForm': true/false,
                    'parameters':[
                        {
                            'paramIn': 'xxx',
                            'inKey': 'xxx',
                            'paramName': 'xxx',
                            'paramDescription': 'xxx',
                            'paramType': 'xxx',
                            'isEnum': 'xxx',
                            'enumValues': [...],
                            'hasMore': true/false
                        }
                    ]
                }
            ]
        }
        '''
        # get tags list first, the list item claims the api class name
        contexts = {}
        tags = set()
        if swagger.tags:
            for tag in swagger.tags:
                tags.add(tag.get('name'))
        for path in swagger.paths:
            for operation in path.operations:
                if operation.tags:
                    tags.add(operation.tags[-1])
                else:
                    # this operation has no tags, generate one by the path. add the tag to the operation's 'tags'
                    tag = getTagByPath(path.path)
                    tags.add(tag)
                    operation.tags = [tag]
        # now we have all tags. create blank render context for each one
        for tag in tags:
            context = {}
            context['package'] = apiPackage
            context['modelPackage'] = modelPackage
            context['classname'] = toApiClassName(tag)
            context['operations'] = []
            contexts[tag] = context
        # fill operations
        for path in swagger.paths:
            for operation in path.operations:
                # tags has been filled above, won't be null
                tag = operation.tags[-1]
                context = contexts[tag]
                optContext = {}
                optContext['summary'] = operation.summary
                optContext['apiDescription'] = operation.description

                pathVar = path.path
                pathVar = re.sub(r'^/*(.*)', r'\1', pathVar)
                pathVar = re.sub(r'([^/]*)/*$', r'\1', pathVar)
                optContext['path'] = pathVar

                optContext['httpMethod'] = toFieldName(operation.method, True)
                optContext['methodName'] = toApiMethodName(operation.method, path.path)

                responseType = None
                for responseItem in operation.responses:
                    if responseItem.code.startswith('2'):
                        # try to parse response type
                        if not responseItem.schema:
                            responseType = 'Void'
                        else:
                            isArray = responseItem.schema.get('type')
                            if isArray:
                                items = responseItem.schema.get('items')
                                if items:
                                    itemRef = items.get('$ref')
                                    if itemRef:
                                        responseType = toDataType('array') % refToClassName(itemRef, True)
                            else:
                                ref = responseItem.schema.get('$ref')
                                responseType = refToClassName(ref, True)
                optContext['responseType'] = responseType

                parameters = []
                for parameter in operation.parameters:
                    paramSrc = None
                    if parameter.ref:
                        # parse the reference
                        type, name = util.parseSwaggerRef(parameter.ref)
                        for p in swagger.parameters:
                            if p.key == name:
                                paramSrc = p
                    else:
                        paramSrc = parameter
                    pContext = {}
                    # if paramter 'in' is 'formData', 'paramIn' value in Retrofit is 'Field'
                    if paramSrc.location == 'formData':
                        pContext['paramIn'] = 'Field'
                        optContext['hasForm'] = True
                    else:
                        pContext['paramIn'] = util.camelize(paramSrc.location)
                    # in retrofit annotations, @Body and @QueryMap(impossible in this parser) don't need a value
                    if str(paramSrc.location).lower() != 'body':
                        pContext['inKey'] = paramSrc.name
                    pContext['paramName'] = toFieldName(paramSrc.name)
                    pContext['paramDescription'] = paramSrc.description
                    pType = None
                    # now simply consider the schema is a json object, not an array
                    if paramSrc.schema:
                        ref = paramSrc.schema.get("$ref")
                        if ref:
                            pType = refToClassName(ref, True)
                    else:
                        pType = toDataType(paramSrc.type)
                    if paramSrc.type == 'array':
                        if paramSrc.itemRef:
                            pType = pType % refToClassName(paramSrc.itemRef, True)
                        elif paramSrc.itemType:
                            pType = pType % toDataType(paramSrc.itemType, True)
                            if paramSrc.itemEnum:
                                pContext['isEnum'] = 'true'
                                pContext['enumValues'] = paramSrc.itemEnum
                    pContext['paramType'] = pType
                    pContext['hasMore'] = True
                    parameters.append(pContext)
                if len(parameters) > 0:
                    parameters[-1]['hasMore'] = False
                optContext['parameters'] = parameters
                context['operations'].append(optContext)
        # now we have contexts. render each one
        for key in contexts:
            context = contexts.get(key)
            result = pystache.render(template, context)
            savePath = apiDir + '/' + context['classname'] + '.java'
            saveTo(savePath, result)