def make_parameter_doc(packet):
    param = []
    for element in packet.get_elements():
        if element[3] == 'out' or packet.get_type() != 'function':
            continue

        delphi_type = delphi_common.get_delphi_type(element[1])[0]
        if element[2] > 1 and element[1] != 'string':
            param.append('@param {0}[] ${1}'.format(delphi_type, element[0]))
        else:
            param.append('@param {0} ${1}'.format(delphi_type, element[0]))

    param.append('\n@return ' + delphi_common.get_return_type(packet, True))
    return '\n'.join(param)
def make_class():
    cls = '  T{0}{1} = class(TDevice)\n'.format(device.get_category(),
                                                device.get_camel_case_name())

    callbacks = ''
    callback = '    {0}Callback: T{1}{2}Notify{3};\n'
    for packet in device.get_packets('callback'):
        callbacks += callback.format(packet.get_headless_camel_case_name(),
                                     device.get_category(),
                                     device.get_camel_case_name(),
                                     packet.get_camel_case_name())

    callback_wrappers = ''
    callback_wrapper = '    procedure CallbackWrapper{0}(const packet: TByteArray); virtual;\n'
    for packet in device.get_packets('callback'):
        callback_wrappers += callback_wrapper.format(packet.get_camel_case_name())

    methods = ''
    function = '    function {0}{1}: {2}; virtual;'
    procedure = '    procedure {0}{1}; virtual;'
    for packet in device.get_packets('function'):
        ret_type = delphi_common.get_return_type(packet, False)
        name = packet.get_camel_case_name()
        params = delphi_common.make_parameter_list(packet, False)
        if len(params) > 0:
            params = '(' + params + ')'
        if len(ret_type) > 0:
            method = function.format(name, params, ret_type)
        else:
            method = procedure.format(name, params)
        methods += method + '\n'

    props = ''
    prop = '    property On{0}: T{1}{2}Notify{0} read {3}Callback write {3}Callback;\n'
    for packet in device.get_packets('callback'):
        props += prop.format(packet.get_camel_case_name(),
                             device.get_category(),
                             device.get_camel_case_name(),
                             packet.get_headless_camel_case_name())

    return  cls + \
            '  private\n' + \
            callbacks + \
            '  protected\n' + \
            callback_wrappers + \
            '  public\n' + \
            '    constructor Create(const uid_: string);\n' + \
            methods + \
            props + \
            '  end;\n\n'
def make_methods(typ):
    methods = ''
    function = '.. delphi:function:: function T{0}.{1}({2}): {3}\n{4}'
    procedure = '.. delphi:function:: procedure T{0}.{1}({2})\n{3}'
    cls = device.get_category() + device.get_camel_case_name()
    for packet in device.get_packets('function'):
        if packet.get_doc()[0] != typ:
            continue

        ret_type = delphi_common.get_return_type(packet, True)
        name = packet.get_camel_case_name()
        params = delphi_common.make_parameter_list(packet, True)
        desc = format_doc(packet)
        if len(ret_type) > 0:
            method = function.format(cls, name, params, ret_type, desc)
        else:
            method = procedure.format(cls, name, params, desc)
        methods += method + '\n'

    return methods
def make_methods(typ):
    version_method = {
    'en': """
.. delphi:function:: procedure T{0}.GetVersion(out apiVersion: TDeviceVersion)

 Returns API version [major, minor, revision] used for this device.
""",
    'de': """
.. delphi:function:: procedure T{0}.GetVersion(out apiVersion: TDeviceVersion)

 Gibt die API Version [major, minor, revision] die benutzt
 wird zurück.
"""
    }

    methods = ''
    function = '.. delphi:function:: function T{0}.{1}({2}): {3}\n{4}'
    procedure = '.. delphi:function:: procedure T{0}.{1}({2})\n{3}'
    cls = device.get_category() + device.get_camel_case_name()
    for packet in device.get_packets('function'):
        if packet.get_doc()[0] != typ:
            continue

        ret_type = delphi_common.get_return_type(packet, True)
        name = packet.get_camel_case_name()
        params = delphi_common.make_parameter_list(packet, True)
        desc = format_doc(packet)
        if len(ret_type) > 0:
            method = function.format(cls, name, params, ret_type, desc)
        else:
            method = procedure.format(cls, name, params, desc)
        methods += method + '\n'

    if typ == 'af':
        methods += common.select_lang(version_method).format(cls)

    return methods
def make_methods():
    methods = ''
    function = 'function {0}.{1}{2}: {3};\n'
    procedure = 'procedure {0}.{1}{2};\n'

    cls = 'T{0}{1}'.format(device.get_category(), device.get_camel_case_name())
    for packet in device.get_packets('function'):
        ret_type = delphi_common.get_return_type(packet, False)
        out_count = len(packet.get_elements('out'))
        name = packet.get_camel_case_name()
        params = delphi_common.make_parameter_list(packet, False)
        function_id = '{0}_{1}_FUNCTION_{2}'.format(device.get_category().upper(),
                                                    device.get_upper_case_name(),
                                                    packet.get_upper_case_name())
        if len(params) > 0:
            params = '(' + params + ')'

        if len(ret_type) > 0:
            method = function.format(cls, name, params, ret_type)
        else:
            method = procedure.format(cls, name, params)

        if out_count > 0:
            method += 'var request, response: TByteArray;'
        else:
            method += 'var request: TByteArray;'

        has_array = False
        for element in packet.get_elements():
            if element[2] > 1 and element[1] != 'string':
                has_array = True
                break

        if has_array:
            method += ' i: longint;'

        method += '\n'
        method += 'begin\n'
        method += '  request := (ipcon as TIPConnection).CreateRequestPacket(self, {0}, {1});\n'.format(function_id, packet.get_request_length())

        # Serialize request
        offset = 8
        for element in packet.get_elements('in'):
            if element[2] > 1 and element[1] != 'string':
                prefix = 'for i := 0 to Length({0}) - 1 do '.format(common.underscore_to_headless_camel_case(element[0]))
                method += '  {0}LEConvert{1}To({2}[i], {3} + (i * {4}), request);\n'.format(prefix,
                                                                                            get_convert_type(element),
                                                                                            common.underscore_to_headless_camel_case(element[0]),
                                                                                            offset,
                                                                                            common.get_type_size(element[1]))
            elif element[1] == 'string':
                method += '  LEConvertStringTo({0}, {1}, {2}, request);\n'.format(common.underscore_to_headless_camel_case(element[0]),
                                                                                  offset,
                                                                                  element[2])
            else:
                method += '  LEConvert{0}To({1}, {2}, request);\n'.format(get_convert_type(element),
                                                                          common.underscore_to_headless_camel_case(element[0]),
                                                                          offset)

            offset += common.get_element_size(element)

        if out_count > 0:
            method += '  response := SendRequest(request);\n'
        else:
            method += '  SendRequest(request);\n'

        # Deserialize response
        offset = 8
        for element in packet.get_elements('out'):
            if out_count > 1:
                result = common.underscore_to_headless_camel_case(element[0])
            else:
                result = 'result'

            if element[2] > 1 and element[1] != 'string':
                prefix = 'for i := 0 to {0} do '.format(element[2] - 1)
                method += '  {0}{1}[i] := LEConvert{2}From({3} + (i * {4}), response);\n'.format(prefix,
                                                                                                 result,
                                                                                                 get_convert_type(element),
                                                                                                 offset,
                                                                                                 common.get_type_size(element[1]))
            elif element[1] == 'string':
                method += '  {0} := LEConvertStringFrom({1}, {2}, response);\n'.format(result,
                                                                                       offset,
                                                                                       element[2])
            else:
                method += '  {0} := LEConvert{1}From({2}, response);\n'.format(result,
                                                                               get_convert_type(element),
                                                                               offset)

            offset += common.get_element_size(element)

        method += 'end;\n\n'

        methods += method

    return methods
def make_class():
    cls = """  /// <summary>
  ///  {2}
  /// </summary>
  T{0}{1} = class(TDevice)
""".format(device.get_category(),
           device.get_camel_case_name(),
           device.get_description())

    callbacks = ''
    callback = '    {0}Callback: T{1}{2}Notify{3};\n'
    for packet in device.get_packets('callback'):
        callbacks += callback.format(packet.get_headless_camel_case_name(),
                                     device.get_category(),
                                     device.get_camel_case_name(),
                                     packet.get_camel_case_name())

    callback_wrappers = ''
    callback_wrapper = '    procedure CallbackWrapper{0}(const packet: TByteArray); {1};\n'
    for packet in device.get_packets('callback'):
        if packet.has_prototype_in_device():
            modifier = 'override'
        else:
            modifier = 'virtual'

        callback_wrappers += callback_wrapper.format(packet.get_camel_case_name(), modifier)

    methods = []
    function = """    /// <summary>
    ///  {3}
    /// </summary>
    function {0}{1}: {2}; {4};"""
    procedure = """    /// <summary>
    ///  {2}
    /// </summary>
    procedure {0}{1}; {3};"""
    for packet in device.get_packets('function'):
        ret_type = delphi_common.get_return_type(packet, False)
        name = packet.get_camel_case_name()
        doc = format_doc(packet)
        params = delphi_common.make_parameter_list(packet, False)
        if packet.has_prototype_in_device():
            modifier = 'override'
        else:
            modifier = 'virtual'
        if len(params) > 0:
            params = '(' + params + ')'
        if len(ret_type) > 0:
            method = function.format(name, params, ret_type, doc, modifier)
        else:
            method = procedure.format(name, params, doc, modifier)
        methods.append(method)

    props = []
    prop = """    /// <summary>
    ///  {4}
    /// </summary>
    property On{0}: T{1}{2}Notify{0} read {3}Callback write {3}Callback;"""
    for packet in device.get_packets('callback'):
        doc = format_doc(packet)
        props.append(prop.format(packet.get_camel_case_name(),
                                 device.get_category(),
                                 device.get_camel_case_name(),
                                 packet.get_headless_camel_case_name(),
                                 doc))

    return  cls + \
            '  private\n' + \
            callbacks + \
            '  protected\n' + \
            callback_wrappers + \
            '  public\n' + \
            '    /// <summary>\n' + \
            '    ///  Creates an object with the unique device ID <c>uid</c>. This object can\n' + \
            '    ///  then be added to the IP connection.\n' + \
            '    /// </summary>\n' + \
            '    constructor Create(const uid__: string; ipcon_: TIPConnection);\n\n' + \
            '\n\n'.join(methods + props) + '\n' + \
            '  end;\n\n'