# Copyright 2024 Volvo Car Corporation
# Licensed under Apache 2.0.

# -*- coding: utf-8 -*-
"""Module for creating a project a2l-file from a template."""

from string import Template


class A2lProjectTemplate:
    """Class for A2l Project Template."""
    def __init__(self, spm_a2l, asap2_version, project_name, events, ip_address, ip_port):
        self.spm_a2l = spm_a2l
        self.asap2_version = asap2_version
        self.project_name = project_name
        self.events = events
        self.ip_address = ip_address
        self.ip_port = ip_port
        self.event_template = Template(
            '        /begin EVENT\n'
            '          "$name" /* EVENT CHANNEL NAME */\n'
            '          "$short_name" /* EVENT CHANNEL SHORT NAME */\n'
            '          $channel_id /* EVENT CHANNEL NUMBER */\n'
            '          DAQ_STIM\n'
            '          0xFF\n'
            '          $time_cycle /* EVENT TIME CYCLE */\n'
            '          $time_unit /* EVENT TIME UNIT */\n'
            '          0x00\n'
            '        /end EVENT\n'
        )
        self.template = Template(
            'ASAP2_VERSION $asap2_version\n'
            '/begin PROJECT $project_name ""\n'
            '  /begin MODULE XCP ""\n'
            '    /begin A2ML\n'
            '      struct Protocol_Layer {\n'
            '        uint;  /* XCP protocol layer version, current 0x100 */\n'
            '        uint;  /* T1 [ms] */\n'
            '        uint;  /* T2 [ms] */\n'
            '        uint;  /* T3 [ms] */\n'
            '        uint;  /* T4 [ms] */\n'
            '        uint;  /* T5 [ms] */\n'
            '        uint;  /* T6 [ms] */\n'
            '        uint;  /* T7 [ms] */\n'
            '        uchar;  /* MAX_CTO */\n'
            '        uint;  /* MAX_DTO */\n'
            '        enum {\n'
            '          "BYTE_ORDER_MSB_LAST" = 0,\n'
            '          "BYTE_ORDER_MSB_FIRST" = 1\n'
            '        };\n'
            '        enum {\n'
            '          "ADDRESS_GRANULARITY_BYTE" = 1,\n'
            '          "ADDRESS_GRANULARITY_WORD" = 2,\n'
            '          "ADDRESS_GRANULARITY_DWORD" = 4\n'
            '        };\n'
            '        taggedstruct {\n'
            '          ("OPTIONAL_CMD" enum {\n'
            '            "GET_COMM_MODE_INFO" = 251,\n'
            '            "GET_ID" = 250,\n'
            '            "SET_REQUEST" = 249,\n'
            '            "GET_SEED" = 248,\n'
            '            "UNLOCK" = 247,\n'
            '            "SET_MTA" = 246,\n'
            '            "UPLOAD" = 245,\n'
            '            "SHORT_UPLOAD" = 244,\n'
            '            "BUILD_CHECKSUM" = 243,\n'
            '            "TRANSPORT_LAYER_CMD" = 242,\n'
            '            "USER_CMD" = 241,\n'
            '            "DOWNLOAD" = 240,\n'
            '            "DOWNLOAD_NEXT" = 239,\n'
            '            "DOWNLOAD_MAX" = 238,\n'
            '            "SHORT_DOWNLOAD" = 237,\n'
            '            "MODIFY_BITS" = 236,\n'
            '            "SET_CAL_PAGE" = 235,\n'
            '            "GET_CAL_PAGE" = 234,\n'
            '            "GET_PAG_PROCESSOR_INFO" = 233,\n'
            '            "GET_SEGMENT_INFO" = 232,\n'
            '            "GET_PAGE_INFO" = 231,\n'
            '            "SET_SEGMENT_MODE" = 230,\n'
            '            "GET_SEGMENT_MODE" = 229,\n'
            '            "COPY_CAL_PAGE" = 228,\n'
            '            "CLEAR_DAQ_LIST" = 227,\n'
            '            "SET_DAQ_PTR" = 226,\n'
            '            "WRITE_DAQ" = 225,\n'
            '            "SET_DAQ_LIST_MODE" = 224,\n'
            '            "GET_DAQ_LIST_MODE" = 223,\n'
            '            "START_STOP_DAQ_LIST" = 222,\n'
            '            "START_STOP_SYNCH" = 221,\n'
            '            "GET_DAQ_CLOCK" = 220,\n'
            '            "READ_DAQ" = 219,\n'
            '            "GET_DAQ_PROCESSOR_INFO" = 218,\n'
            '            "GET_DAQ_RESOLUTION_INFO" = 217,\n'
            '            "GET_DAQ_LIST_INFO" = 216,\n'
            '            "GET_DAQ_EVENT_INFO" = 215,\n'
            '            "FREE_DAQ" = 214,\n'
            '            "ALLOC_DAQ" = 213,\n'
            '            "ALLOC_ODT" = 212,\n'
            '            "ALLOC_ODT_ENTRY" = 211,\n'
            '            "PROGRAM_START" = 210,\n'
            '            "PROGRAM_CLEAR" = 209,\n'
            '            "PROGRAM" = 208,\n'
            '            "PROGRAM_RESET" = 207,\n'
            '            "GET_PGM_PROCESSOR_INFO" = 206,\n'
            '            "GET_SECTOR_INFO" = 205,\n'
            '            "PROGRAM_PREPARE" = 204,\n'
            '            "PROGRAM_FORMAT" = 203,\n'
            '            "PROGRAM_NEXT" = 202,\n'
            '            "PROGRAM_MAX" = 201,\n'
            '            "PROGRAM_VERIFY" = 200\n'
            '          })*;\n'
            '          "COMMUNICATION_MODE_SUPPORTED" taggedunion {\n'
            '            "BLOCK" taggedstruct {\n'
            '              "SLAVE" ;\n'
            '              "MASTER" struct {\n'
            '                uchar;  /* MAX_BS */\n'
            '                uchar;  /* MIN_ST */\n'
            '              };\n'
            '            };\n'
            '            "INTERLEAVED" uchar;  /* QUEUE_SIZE */\n'
            '          };\n'
            '          "SEED_AND_KEY_EXTERNAL_FUNCTION" char[256];/* Name of the Seed&Key function */\n'
            '        };\n'
            '      };\n'
            '\n'
            '      struct Daq {\n'
            '        enum {\n'
            '          "STATIC" = 0,\n'
            '          "DYNAMIC" = 1\n'
            '        };\n'
            '        uint;  /* MAX_DAQ */\n'
            '        uint;  /* MAX_EVENT_CHANNEL */\n'
            '        uchar;  /* MIN_DAQ */\n'
            '        enum {\n'
            '          "OPTIMISATION_TYPE_DEFAULT" = 0,\n'
            '          "OPTIMISATION_TYPE_ODT_TYPE_16" = 1,\n'
            '          "OPTIMISATION_TYPE_ODT_TYPE_32" = 2,\n'
            '          "OPTIMISATION_TYPE_ODT_TYPE_64" = 3,\n'
            '          "OPTIMISATION_TYPE_ODT_TYPE_ALIGNMENT" = 4,\n'
            '          "OPTIMISATION_TYPE_MAX_ENTRY_SIZE" = 5\n'
            '        };\n'
            '        enum {\n'
            '          "ADDRESS_EXTENSION_FREE" = 0,\n'
            '          "ADDRESS_EXTENSION_ODT" = 1,\n'
            '          "ADDRESS_EXTENSION_DAQ" = 3\n'
            '        };\n'
            '        enum {\n'
            '          "IDENTIFICATION_FIELD_TYPE_ABSOLUTE" = 0,\n'
            '          "IDENTIFICATION_FIELD_TYPE_RELATIVE_BYTE" = 1,\n'
            '          "IDENTIFICATION_FIELD_TYPE_RELATIVE_WORD" = 2,\n'
            '          "IDENTIFICATION_FIELD_TYPE_RELATIVE_WORD_ALIGNED" = 3\n'
            '        };\n'
            '        enum {\n'
            '          "GRANULARITY_ODT_ENTRY_SIZE_DAQ_BYTE" = 1,\n'
            '          "GRANULARITY_ODT_ENTRY_SIZE_DAQ_WORD" = 2,\n'
            '          "GRANULARITY_ODT_ENTRY_SIZE_DAQ_DWORD" = 4,\n'
            '          "GRANULARITY_ODT_ENTRY_SIZE_DAQ_DLONG" = 8\n'
            '        };\n'
            '        uchar;  /* MAX_ODT_ENTRY_SIZE_DAQ */\n'
            '        enum {\n'
            '          "NO_OVERLOAD_INDICATION" = 0,\n'
            '          "OVERLOAD_INDICATION_PID" = 1,\n'
            '          "OVERLOAD_INDICATION_EVENT" = 2\n'
            '        };\n'
            '        taggedstruct {\n'
            '          "PRESCALER_SUPPORTED" ;\n'
            '          "RESUME_SUPPORTED" ;\n'
            '          block "STIM" struct {\n'
            '            enum {\n'
            '              "GRANULARITY_ODT_ENTRY_SIZE_STIM_BYTE" = 1,\n'
            '              "GRANULARITY_ODT_ENTRY_SIZE_STIM_WORD" = 2,\n'
            '              "GRANULARITY_ODT_ENTRY_SIZE_STIM_DWORD" = 4,\n'
            '              "GRANULARITY_ODT_ENTRY_SIZE_STIM_DLONG" = 8\n'
            '            };\n'
            '            uchar;  /* MAX_ODT_ENTRY_SIZE_STIM */\n'
            '            taggedstruct {\n'
            '              "BIT_STIM_SUPPORTED" ;\n'
            '            };\n'
            '          };\n'
            '          block "TIMESTAMP_SUPPORTED" struct {\n'
            '            uint;  /* TIMESTAMP_TICKS */\n'
            '            enum {\n'
            '              "NO_TIME_STAMP" = 0,\n'
            '              "SIZE_BYTE" = 1,\n'
            '              "SIZE_WORD" = 2,\n'
            '              "SIZE_DWORD" = 4\n'
            '            };\n'
            '            enum {\n'
            '              "UNIT_1NS" = 0,\n'
            '              "UNIT_10NS" = 1,\n'
            '              "UNIT_100NS" = 2,\n'
            '              "UNIT_1US" = 3,\n'
            '              "UNIT_10US" = 4,\n'
            '              "UNIT_100US" = 5,\n'
            '              "UNIT_1MS" = 6,\n'
            '              "UNIT_10MS" = 7,\n'
            '              "UNIT_100MS" = 8,\n'
            '              "UNIT_1S" = 9\n'
            '            };\n'
            '            taggedstruct {\n'
            '              "TIMESTAMP_FIXED" ;\n'
            '            };\n'
            '          };\n'
            '          "PID_OFF_SUPPORTED" ;\n'
            '          (block "DAQ_LIST" struct {\n'
            '            uint;  /* DAQ_LIST_NUMBER */\n'
            '            taggedstruct {\n'
            '              "DAQ_LIST_TYPE" enum {\n'
            '                "DAQ" = 1,\n'
            '                "STIM" = 2,\n'
            '                "DAQ_STIM" = 3\n'
            '              };\n'
            '              "MAX_ODT" uchar;\n'
            '              "MAX_ODT_ENTRIES" uchar;\n'
            '              "FIRST_PID" uchar;\n'
            '              "EVENT_FIXED" uint;\n'
            '              block "PREDEFINED" taggedstruct {\n'
            '                (block "ODT" struct {\n'
            '                  uchar;  /* ODT number */\n'
            '                  taggedstruct {\n'
            '                    ("ODT_ENTRY" struct {\n'
            '                      uchar;  /* ODT_ENTRY number */\n'
            '                      ulong;  /* address of element */\n'
            '                      uchar;  /* address extension of element */\n'
            '                      uchar;  /* size of element [AG] */\n'
            '                      uchar;  /* BIT_OFFSET */\n'
            '                    })*;\n'
            '                  };\n'
            '                })*;\n'
            '              };\n'
            '            };\n'
            '          })*;\n'
            '          (block "EVENT" struct {\n'
            '            char[101];  /* EVENT_CHANNEL_NAME */\n'
            '            char[9];  /* EVENT_CHANNEL_SHORT_NAME */\n'
            '            uint;  /* EVENT_CHANNEL_NUMBER */\n'
            '            enum {\n'
            '              "DAQ" = 1,\n'
            '              "STIM" = 2,\n'
            '              "DAQ_STIM" = 3\n'
            '            };\n'
            '            uchar;  /* MAX_DAQ_LIST */\n'
            '            uchar;  /* TIME_CYCLE   */\n'
            '            uchar;  /* TIME_UNIT    */\n'
            '            uchar;  /* PRIORITY     */\n'
            '          })*;\n'
            '        };\n'
            '      };\n'
            '\n'
            '      taggedunion Daq_Event {\n'
            '        "FIXED_EVENT_LIST" taggedstruct {\n'
            '          ("EVENT" uint)*;\n'
            '        };\n'
            '        "VARIABLE" taggedstruct {\n'
            '          block "AVAILABLE_EVENT_LIST" taggedstruct {\n'
            '            ("EVENT" uint)*;\n'
            '          };\n'
            '          block "DEFAULT_EVENT_LIST" taggedstruct {\n'
            '            ("EVENT" uint)*;\n'
            '          };\n'
            '        };\n'
            '      };\n'
            '\n'
            '      struct Pag {\n'
            '        uchar;  /* MAX_SEGMENTS */\n'
            '        taggedstruct {\n'
            '          "FREEZE_SUPPORTED" ;\n'
            '        };\n'
            '      };\n'
            '\n'
            '      struct Pgm {\n'
            '        enum {\n'
            '          "PGM_MODE_ABSOLUTE" = 1,\n'
            '          "PGM_MODE_FUNCTIONAL" = 2,\n'
            '          "PGM_MODE_ABSOLUTE_AND_FUNCTIONAL" = 3\n'
            '        };\n'
            '        uchar;  /* MAX_SECTORS */\n'
            '        uchar;  /* MAX_CTO_PGM */\n'
            '        taggedstruct {\n'
            '          (block "SECTOR" struct {\n'
            '            char[101];  /* SECTOR_NAME */\n'
            '            uchar;  /* SECTOR_NUMBER */\n'
            '            ulong;  /* Address */\n'
            '            ulong;  /* Length  */\n'
            '            uchar;  /* CLEAR_SEQUENCE_NUMBER */\n'
            '            uchar;  /* PROGRAM_SEQUENCE_NUMBER */\n'
            '            uchar;  /* PROGRAM_METHOD */\n'
            '          })*;\n'
            '          "COMMUNICATION_MODE_SUPPORTED" taggedunion {\n'
            '            "BLOCK" taggedstruct {\n'
            '              "SLAVE" ;\n'
            '              "MASTER" struct {\n'
            '                uchar;  /* MAX_BS_PGM */\n'
            '                uchar;  /* MIN_ST_PGM */\n'
            '              };\n'
            '            };\n'
            '            "INTERLEAVED" uchar;  /* QUEUE_SIZE_PGM */\n'
            '          };\n'
            '        };\n'
            '      };\n'
            '\n'
            '      struct Segment {\n'
            '        uchar;  /* SEGMENT_NUMBER */\n'
            '        uchar;  /* number of pages */\n'
            '        uchar;  /* ADDRESS_EXTENSION */\n'
            '        uchar;  /* COMPRESSION_METHOD */\n'
            '        uchar;  /* ENCRYPTION_METHOD */\n'
            '        taggedstruct {\n'
            '          block "CHECKSUM" struct {\n'
            '            enum {\n'
            '              "XCP_ADD_11" = 1,\n'
            '              "XCP_ADD_12" = 2,\n'
            '              "XCP_ADD_14" = 3,\n'
            '              "XCP_ADD_22" = 4,\n'
            '              "XCP_ADD_24" = 5,\n'
            '              "XCP_ADD_44" = 6,\n'
            '              "XCP_CRC_16" = 7,\n'
            '              "XCP_CRC_16_CITT" = 8,\n'
            '              "XCP_CRC_32" = 9,\n'
            '              "XCP_USER_DEFINED" = 255\n'
            '            };\n'
            '            taggedstruct {\n'
            '              "MAX_BLOCK_SIZE" ulong;\n'
            '              "EXTERNAL_FUNCTION" char[256];  /* Name of the Checksum.DLL */\n'
            '            };\n'
            '          };\n'
            '          (block "PAGE" struct {\n'
            '            uchar;  /* PAGE_NUMBER */\n'
            '            enum {\n'
            '              "ECU_ACCESS_NOT_ALLOWED" = 0,\n'
            '              "ECU_ACCESS_WITHOUT_XCP_ONLY" = 1,\n'
            '              "ECU_ACCESS_WITH_XCP_ONLY" = 2,\n'
            '              "ECU_ACCESS_DONT_CARE" = 3\n'
            '            };\n'
            '            enum {\n'
            '              "XCP_READ_ACCESS_NOT_ALLOWED" = 0,\n'
            '              "XCP_READ_ACCESS_WITHOUT_ECU_ONLY" = 1,\n'
            '              "XCP_READ_ACCESS_WITH_ECU_ONLY" = 2,\n'
            '              "XCP_READ_ACCESS_DONT_CARE" = 3\n'
            '            };\n'
            '            enum {\n'
            '              "XCP_WRITE_ACCESS_NOT_ALLOWED" = 0,\n'
            '              "XCP_WRITE_ACCESS_WITHOUT_ECU_ONLY" = 1,\n'
            '              "XCP_WRITE_ACCESS_WITH_ECU_ONLY" = 2,\n'
            '              "XCP_WRITE_ACCESS_DONT_CARE" = 3\n'
            '            };\n'
            '            taggedstruct {\n'
            '              "INIT_SEGMENT" uchar;  /* references segment that initialises this page */\n'
            '            };\n'
            '          })*;\n'
            '          (block "ADDRESS_MAPPING" struct {\n'
            '            ulong;  /* source address */\n'
            '            ulong;  /* destination address */\n'
            '            ulong;  /* length */\n'
            '          })*;\n'
            '          "PGM_VERIFY" ulong;  /* verification value for PGM */\n'
            '        };\n'
            '      };\n'
            '\n'
            '      taggedstruct Common_Parameters {\n'
            '        block "PROTOCOL_LAYER" struct Protocol_Layer;\n'
            '        block "SEGMENT" struct Segment;\n'
            '        block "DAQ" struct Daq;\n'
            '        block "PAG" struct Pag;\n'
            '        block "PGM" struct Pgm;\n'
            '        block "DAQ_EVENT" taggedunion Daq_Event;\n'
            '      };\n'
            '\n'
            '      struct UDP_IP_Parameters {\n'
            '        uint;  /* XCP on UDP_IP version, currently 0x0100 */\n'
            '        uint;  /* PORT */\n'
            '        taggedunion {\n'
            '          "HOST_NAME" char[256];\n'
            '          "ADDRESS" char[15];\n'
            '        };\n'
            '      };\n'
            '\n'
            '      block "IF_DATA" taggedunion if_data {\n'
            '        "XCP" struct {\n'
            '          taggedstruct Common_Parameters;  /* default parameters */\n'
            '          taggedstruct {\n'
            '            block "XCP_ON_UDP_IP" struct {\n'
            '              struct UDP_IP_Parameters;  /* specific for UDP_IP */\n'
            '              taggedstruct Common_Parameters;  /* overruling of default */\n'
            '            };\n'
            '          };\n'
            '        };\n'
            '      };\n'
            '    /end A2ML\n'
            '\n'
            '    /begin MOD_COMMON ""\n'
            '      BYTE_ORDER MSB_LAST\n'
            '      ALIGNMENT_BYTE 1\n'
            '      ALIGNMENT_WORD 1\n'
            '      ALIGNMENT_LONG 1\n'
            '      ALIGNMENT_FLOAT32_IEEE 1\n'
            '      ALIGNMENT_FLOAT64_IEEE 1\n'
            '    /end MOD_COMMON\n'
            '\n'
            '    /begin IF_DATA XCP\n'
            '      /begin PROTOCOL_LAYER\n'
            '        0x0100\n'
            '        0x03E8\n'
            '        0xC8\n'
            '        0x00\n'
            '        0x00\n'
            '        0x00\n'
            '        0x00\n'
            '        0x00\n'
            '        0x60\n'
            '        0x12C\n'
            '        BYTE_ORDER_MSB_LAST\n'
            '        ADDRESS_GRANULARITY_BYTE\n'
            '        OPTIONAL_CMD ALLOC_ODT_ENTRY\n'
            '        OPTIONAL_CMD ALLOC_ODT\n'
            '        OPTIONAL_CMD ALLOC_DAQ\n'
            '        OPTIONAL_CMD FREE_DAQ\n'
            '        OPTIONAL_CMD GET_DAQ_RESOLUTION_INFO\n'
            '        OPTIONAL_CMD GET_DAQ_PROCESSOR_INFO\n'
            '        OPTIONAL_CMD START_STOP_SYNCH\n'
            '        OPTIONAL_CMD GET_DAQ_CLOCK\n'
            '        OPTIONAL_CMD START_STOP_DAQ_LIST\n'
            '        OPTIONAL_CMD GET_DAQ_LIST_MODE\n'
            '        OPTIONAL_CMD SET_DAQ_LIST_MODE\n'
            '        OPTIONAL_CMD WRITE_DAQ\n'
            '        OPTIONAL_CMD SET_DAQ_PTR\n'
            '        OPTIONAL_CMD CLEAR_DAQ_LIST\n'
            '        OPTIONAL_CMD SHORT_UPLOAD\n'
            '        OPTIONAL_CMD UPLOAD\n'
            '        OPTIONAL_CMD SET_MTA\n'
            '        OPTIONAL_CMD GET_ID\n'
            '        OPTIONAL_CMD GET_COMM_MODE_INFO\n'
            '        OPTIONAL_CMD BUILD_CHECKSUM\n'
            '        OPTIONAL_CMD SET_SEGMENT_MODE\n'
            '        OPTIONAL_CMD GET_SEGMENT_MODE\n'
            '        OPTIONAL_CMD SET_REQUEST\n'
            '        OPTIONAL_CMD GET_SEED\n'
            '        OPTIONAL_CMD UNLOCK\n'
            '        OPTIONAL_CMD COPY_CAL_PAGE\n'
            '        SEED_AND_KEY_EXTERNAL_FUNCTION Seed_Key.dll'
            '/* Add name of seed & key dll file here.*/\n'
            '      /end PROTOCOL_LAYER\n'
            '\n'
            '      /begin DAQ\n'
            '        DYNAMIC\n'
            '        0x00\n'
            '        0x06\n'
            '        0x00\n'
            '        OPTIMISATION_TYPE_DEFAULT\n'
            '        ADDRESS_EXTENSION_FREE\n'
            '        IDENTIFICATION_FIELD_TYPE_ABSOLUTE\n'
            '        GRANULARITY_ODT_ENTRY_SIZE_DAQ_BYTE\n'
            '        0x60\n'
            '        NO_OVERLOAD_INDICATION\n'
            '        /begin TIMESTAMP_SUPPORTED\n'
            '          0x01\n'
            '          SIZE_DWORD\n'
            '          UNIT_100US\n'
            '          TIMESTAMP_FIXED\n'
            '        /end TIMESTAMP_SUPPORTED\n'
            '\n'
            '$events\n'
            '      /end DAQ\n'
            '\n'
            '      /begin PAG\n'
            '        0x01\n'
            '        FREEZE_SUPPORTED\n'
            '      /end PAG\n'
            '      /begin PGM\n'
            '        PGM_MODE_ABSOLUTE\n'
            '        0x01\n'
            '        0x00\n'
            '        /begin SECTOR\n'
            '          "Sector"\n'
            '          0x00\n'
            '          0x22014\n'
            '          0x38\n'
            '          0x00\n'
            '          0x00\n'
            '          0x00\n'
            '        /end SECTOR\n'
            '      /end PGM\n'
            '\n'
            '      /begin XCP_ON_UDP_IP\n'
            '        0x0100\n'
            '        $ip_port\n'
            '        ADDRESS "$ip_address"\n'
            '      /end XCP_ON_UDP_IP\n'
            '    /end IF_DATA\n'
            '\n'
            '    /begin MOD_PAR ""\n'
            '      /begin MEMORY_SEGMENT\n'
            '        caldata "caldata"\n'
            '        DATA FLASH INTERN 0x00000 0x0000 -1 -1 -1 -1 -1\n'
            '        /begin IF_DATA XCP\n'
            '          /begin SEGMENT\n'
            '            0x00\n'
            '            0x02\n'
            '            0x00\n'
            '            0x00\n'
            '            0x00\n'
            '            /begin CHECKSUM\n'
            '              XCP_CRC_16_CITT\n'
            '            /end CHECKSUM\n'
            '            /begin PAGE\n'
            '              0x00\n'
            '              ECU_ACCESS_WITH_XCP_ONLY\n'
            '              XCP_READ_ACCESS_WITH_ECU_ONLY\n'
            '              XCP_WRITE_ACCESS_NOT_ALLOWED\n'
            '              INIT_SEGMENT 0x00\n'
            '            /end PAGE\n'
            '            /begin PAGE\n'
            '              0x01\n'
            '              ECU_ACCESS_WITH_XCP_ONLY\n'
            '              XCP_READ_ACCESS_WITH_ECU_ONLY\n'
            '              XCP_WRITE_ACCESS_WITH_ECU_ONLY\n'
            '              INIT_SEGMENT 0x00\n'
            '            /end PAGE\n'
            '          /end SEGMENT\n'
            '        /end IF_DATA\n'
            '      /end MEMORY_SEGMENT\n'
            '      /begin MEMORY_SEGMENT\n'
            '        text ".text"\n'
            '        CODE ROM INTERN 0x26030 0x72c10 -1 -1 -1 -1 -1\n'
            '        /begin IF_DATA XCP\n'
            '          /begin SEGMENT\n'
            '            0x01\n'
            '            0x01\n'
            '            0x00\n'
            '            0x00\n'
            '            0x00\n'
            '            /begin CHECKSUM\n'
            '              XCP_CRC_16_CITT\n'
            '            /end CHECKSUM\n'
            '            /begin PAGE\n'
            '              0x01\n'
            '              ECU_ACCESS_WITH_XCP_ONLY\n'
            '              XCP_READ_ACCESS_WITH_ECU_ONLY\n'
            '              XCP_WRITE_ACCESS_WITH_ECU_ONLY\n'
            '              INIT_SEGMENT 0x00\n'
            '            /end PAGE\n'
            '          /end SEGMENT\n'
            '        /end IF_DATA\n'
            '      /end MEMORY_SEGMENT\n'
            '    /end MOD_PAR\n'
            '\n'
            '    /begin COMPU_METHOD BitSlice.CONVERSION ""\n'
            '      RAT_FUNC "%6.2f" ""\n'
            '      COEFFS 0 1 0 0 0 1\n'
            '    /end COMPU_METHOD\n'
            '\n'
            '    /* SPM declarations start. */\n'
            '\n'
            '$spm_a2l\n'
            '\n'
            '    /* SPM declarations end. */\n'
            '\n'
            '    /begin RECORD_LAYOUT __UBYTE_Z\n'
            '      FNC_VALUES 1 UBYTE ROW_DIR DIRECT\n'
            '    /end RECORD_LAYOUT\n'
            '\n'
            '    /begin RECORD_LAYOUT __UWORD_Z\n'
            '      FNC_VALUES 1 UWORD ROW_DIR DIRECT\n'
            '    /end RECORD_LAYOUT\n'
            '\n'
            '    /begin RECORD_LAYOUT __ULONG_Z\n'
            '      FNC_VALUES 1 ULONG ROW_DIR DIRECT\n'
            '    /end RECORD_LAYOUT\n'
            '\n'
            '    /begin RECORD_LAYOUT __SBYTE_Z\n'
            '      FNC_VALUES 1 SBYTE ROW_DIR DIRECT\n'
            '    /end RECORD_LAYOUT\n'
            '\n'
            '    /begin RECORD_LAYOUT __SWORD_Z\n'
            '      FNC_VALUES 1 SWORD ROW_DIR DIRECT\n'
            '    /end RECORD_LAYOUT\n'
            '\n'
            '    /begin RECORD_LAYOUT __SLONG_Z\n'
            '      FNC_VALUES 1 SLONG ROW_DIR DIRECT\n'
            '    /end RECORD_LAYOUT\n'
            '\n'
            '    /begin RECORD_LAYOUT __FLOAT32_IEEE_Z\n'
            '      FNC_VALUES 1 FLOAT32_IEEE ROW_DIR DIRECT\n'
            '    /end RECORD_LAYOUT\n'
            '\n'
            '    /begin RECORD_LAYOUT __FLOAT64_IEEE_Z\n'
            '      FNC_VALUES 1 FLOAT64_IEEE ROW_DIR DIRECT\n'
            '    /end RECORD_LAYOUT\n'
            '\n'
            '    /begin RECORD_LAYOUT __UBYTE_S\n'
            '      FNC_VALUES 1 UBYTE COLUMN_DIR DIRECT\n'
            '    /end RECORD_LAYOUT\n'
            '\n'
            '    /begin RECORD_LAYOUT __UWORD_S\n'
            '      FNC_VALUES 1 UWORD COLUMN_DIR DIRECT\n'
            '    /end RECORD_LAYOUT\n'
            '\n'
            '    /begin RECORD_LAYOUT __ULONG_S\n'
            '      FNC_VALUES 1 ULONG COLUMN_DIR DIRECT\n'
            '    /end RECORD_LAYOUT\n'
            '\n'
            '    /begin RECORD_LAYOUT __SBYTE_S\n'
            '      FNC_VALUES 1 SBYTE COLUMN_DIR DIRECT\n'
            '    /end RECORD_LAYOUT\n'
            '\n'
            '    /begin RECORD_LAYOUT __SWORD_S\n'
            '      FNC_VALUES 1 SWORD COLUMN_DIR DIRECT\n'
            '    /end RECORD_LAYOUT\n'
            '\n'
            '    /begin RECORD_LAYOUT __SLONG_S\n'
            '      FNC_VALUES 1 SLONG COLUMN_DIR DIRECT\n'
            '    /end RECORD_LAYOUT\n'
            '\n'
            '    /begin RECORD_LAYOUT __FLOAT32_IEEE_S\n'
            '      FNC_VALUES 1 FLOAT32_IEEE COLUMN_DIR DIRECT\n'
            '    /end RECORD_LAYOUT\n'
            '\n'
            '    /begin RECORD_LAYOUT __FLOAT64_IEEE_S\n'
            '      FNC_VALUES 1 FLOAT64_IEEE COLUMN_DIR DIRECT\n'
            '    /end RECORD_LAYOUT\n'
            '\n'
            '    /begin RECORD_LAYOUT SSV__UBYTE_S\n'
            '      AXIS_PTS_X 1 UBYTE INDEX_INCR DIRECT\n'
            '    /end RECORD_LAYOUT\n'
            '\n'
            '    /begin RECORD_LAYOUT SSV__UWORD_S\n'
            '      AXIS_PTS_X 1 UWORD INDEX_INCR DIRECT\n'
            '    /end RECORD_LAYOUT\n'
            '\n'
            '    /begin RECORD_LAYOUT SSV__ULONG_S\n'
            '      AXIS_PTS_X 1 ULONG INDEX_INCR DIRECT\n'
            '    /end RECORD_LAYOUT\n'
            '\n'
            '    /begin RECORD_LAYOUT SSV__SBYTE_S\n'
            '      AXIS_PTS_X 1 SBYTE INDEX_INCR DIRECT\n'
            '    /end RECORD_LAYOUT\n'
            '\n'
            '    /begin RECORD_LAYOUT SSV__SWORD_S\n'
            '      AXIS_PTS_X 1 SWORD INDEX_INCR DIRECT\n'
            '    /end RECORD_LAYOUT\n'
            '\n'
            '    /begin RECORD_LAYOUT SSV__SLONG_S\n'
            '      AXIS_PTS_X 1 SLONG INDEX_INCR DIRECT\n'
            '    /end RECORD_LAYOUT\n'
            '\n'
            '    /begin RECORD_LAYOUT SSV__FLOAT32_IEEE_S\n'
            '      AXIS_PTS_X 1 FLOAT32_IEEE INDEX_INCR DIRECT\n'
            '    /end RECORD_LAYOUT\n'
            '\n'
            '    /begin RECORD_LAYOUT SSV__FLOAT64_IEEE_S\n'
            '      AXIS_PTS_X 1 FLOAT64_IEEE INDEX_INCR DIRECT\n'
            '    /end RECORD_LAYOUT\n'
            '\n'
            '  /end MODULE\n'
            '/end PROJECT\n'
        )

    def render(self):
        """Render the complete A2L.
        Returns:
            a2l (str): The A2L for the project.
        """
        event_a2l = ''
        for event in self.events:
            event_a2l += self.event_template.substitute(
                name=event['name'],
                short_name=event['name'],
                channel_id=event['channel_id'],
                time_cycle=event['time_cycle'],
                time_unit=event['time_unit']
            )
        return self.template.substitute(
            events=event_a2l,
            asap2_version=self.asap2_version,
            project_name=self.project_name.replace('-', '_'),
            ip_address=self.ip_address,
            ip_port=self.ip_port,
            spm_a2l=self.spm_a2l
        )


class A2lSilverTemplate:
    """Class for A2l Silver Template."""
    def __init__(self, base_a2l):
        """Init."""
        self.patched_a2l = self.basic_patching(base_a2l)
        self.template = Template(
            '/* QTronic Header */\n'
            'ASAP2_VERSION 1 6\n'
            '/begin PROJECT SPM ""\n'
            '/begin MODULE SPM ""\n'
            '\n'
            '$base_a2l'
            '\n'
            '/end MODULE\n'
            '/end PROJECT'
        )

    @staticmethod
    def basic_patching(base_a2l):
        """Perform required basic patching.

        Args:
            base_a2l (str): Inital A2l content.
        Returns:
            (str): Patched A2L content.
        """
        return "".join([char if ord(char) < 128 else "?" for char in base_a2l])

    def render(self):
        """Render the complete A2L.

        Returns:
            (str): The patched A2L for Silver.
        """
        if "ASAP2_VERSION" in self.patched_a2l[:999]:
            return self.patched_a2l
        return self.template.substitute(base_a2l=self.patched_a2l)
