module ItsRSUsSimulator_Templates {
    
    // LibCommon
    import from LibCommon_BasicTypesAndValues all;
    
    // LibIts
    import from ITS_Container language "ASN.1:1997" all;
    import from CAM_PDU_Descriptions language "ASN.1:1997" all;
    import from DENM_PDU_Descriptions language "ASN.1:1997" all;
    import from MAPEM_PDU_Descriptions language "ASN.1:1997" all;
    import from SPATEM_PDU_Descriptions language "ASN.1:1997" all;
    import from IVIM_PDU_Descriptions language "ASN.1:1997" all;
    import from IVI language "ASN.1:1997" all;
    import from SSEM_PDU_Descriptions language "ASN.1:1997" all;
    import from DSRC language "ASN.1:1997" all;
    
    // LibItsCommon
    import from LibItsCommon_Functions all;
    import from LibCommon_DataStrings all;
    
    // LibItsGeoNetworking
    import from LibItsGeoNetworking_TestSystem all;
    import from LibItsGeoNetworking_Functions all;
    import from LibItsGeoNetworking_Templates all;
    import from LibItsGeoNetworking_TypesAndValues all;
    
    // LibItsBtp
    import from LibItsBtp_TypesAndValues all;
    import from LibItsBtp_Templates all;
    
    // LibItsCam
    import from LibItsCam_Templates all;
    
    // LibItsDenm
    import from LibItsDenm_Templates all;
    
    // LibItsMapemSpatem
    import from LibItsMapemSpatem_Templates all;
    
    // LibItsIvim
    import from LibItsIvim_Templates all;
    
    // AtsRSUsSimulator
    import from ItsRSUsSimulator_TypesAndValues all;
    import from ItsRSUsSimulator_Functions all;
    import from ItsRSUsSimulator_Pics all;
    
    template (omit) RsuMessagesValue m_rsuProfile(
                                                  in template (omit) octetstring p_beacon := omit,
                                                  in template (omit) CAM p_cam := omit,
                                                  in template (omit) DENMs p_denms := omit,
                                                  in template (omit) MAPEM p_mapem := omit,
                                                  in template (omit) SPATEMs p_spatems := omit,
                                                  in template (omit) IVIM p_ivim := omit,
                                                  in template (omit) SSEM p_ssem := omit
    ) := {
        beacon     := p_beacon,
        cam        := p_cam,
        denms      := p_denms,
        mapem      := p_mapem,
        spatems    := p_spatems,
        ivim       := p_ivim
    } // End of template RsuMessagesValue

    group geoNetworkingTemplates {
        
        template (value) GnNonSecuredPacket m_geoNwBroadcastPacket_payload(
                                                                           in template (value) LongPosVector p_sourceLongPosVec,
                                                                           in template (value) UInt16 p_seqNumber,
                                                                           in template (value) GeoBroadcastArea p_broadcastArea,
                                                                           in template (value) UInt8 p_hopLimit := c_defaultHopLimit,
                                                                           in template (value) TrafficClass p_trafficClass := m_trafficClass,
                                                                           in template (value) Payload p_payload
        ) modifies m_geoNwBroadcastPacket := {
            payload := p_payload
        } // End of template m_geoNwBroadcastPacket_payload
        
        /**
         * @desc    Send template for GeoNetworking TSB Packet
         * @param   p_seqNumber         Sequence number of TSB packet
         * @param   p_sourceLongPosVec  Long position vector of source
         * @param   p_hopLimit          The maximum number of hops (Default: c_defaultHopLimit)
         * @param   p_trafficClass      TODO
         * @param   p_payload           TODO
         */
        template (value) GnNonSecuredPacket m_geoNwTsbPacket_payload(
                                                                     in template (value) UInt16 p_seqNumber,
                                                                     in template (value) LongPosVector p_sourceLongPosVec,
                                                                     in template (value) UInt8 p_hopLimit := c_defaultHopLimit,
                                                                     in template (value) TrafficClass p_trafficClass := m_trafficClass,
                                                                     in template (value) Payload p_payload
        ) modifies m_geoNwTsbPacket:= {
            payload :=  p_payload
        }
        
        /**
         * @desc    Send template for GeoNetworking SHB Packet
         * @param   p_sourceLongPosVec  Long position vector of source
         * @param   p_hopLimit          The maximum number of hops (Default: c_defaultHopLimit)
         * @param   p_trafficClass      TODO
         * @param   p_payload           TODO
         */
        template (value) GnNonSecuredPacket m_geoNwShbPacket_payload(
                                                                     in template (value) LongPosVector p_sourceLongPosVec,
                                                                     in template (value) Payload p_payload
        ) modifies m_geoNwShbPacket:= {
            payload :=  p_payload
        }
        
        /**
         * @desc    Receive template for GeoNetworking Unicast Packet
         * @param   p_destinationShortPosVec    Short position vector of destination
         * @param   p_seqNumber                 Sequence number of GeoUnicast packet
         * @param   p_nextHeader                Id of next header
         */
        template (present) GnNonSecuredPacket mw_geoNwBroadcastPacketWithNextHeader_srem(
                                                                                         in template (present) LongPosVector p_sourceLongPosVec := ?,
                                                                                         in template (present) UInt16 p_seqNumber := ?,
                                                                                         in template (present) NextHeader p_nextHeader := ?
        ) modifies mw_geoNwBroadcastPacketWithNextHeader := {
            payload := { 
                decodedPayload := { 
                    btpPacket := mw_btpB(
                        PICS_SREM_BTP_DESTINATION_PORT, 
                        PICS_SREM_BTP_SOURCE_PORT, 
                        ?
                    )
                }, 
                rawPayload := ?
            }
        }
        
        /**
         * @desc    Receive template for GeoNetworking SREM Packet
         * @param   p_destinationShortPosVec    Short position vector of destination
         * @param   p_seqNumber                 Sequence number of GeoUnicast packet
         * @param   p_nextHeader                Id of next header
         */
        template (present) GnNonSecuredPacket mw_geoNwTsbPacketWithNextHeader_srem(
                                                                                   in template (present) UInt16 p_seqNumber := ?,
                                                                                   in template (present) LongPosVector p_sourceLongPosVec := ?,
                                                                                   in template (value) NextHeader p_nextHeader
        ) modifies mw_geoNwTsbPacketWithNextHeader := {
            payload := { 
                decodedPayload := { 
                    btpPacket := mw_btpB(
                        PICS_SREM_BTP_DESTINATION_PORT, 
                        PICS_SREM_BTP_SOURCE_PORT, 
                        ?
                    )
                }, 
                rawPayload := ?
            }
        }
        
        /**
         * @desc    Receive template for GeoNetworking DENM Packet
         * @param   p_destinationShortPosVec    Short position vector of destination
         * @param   p_seqNumber                 Sequence number of GeoUnicast packet
         * @param   p_nextHeader                Id of next header
         */
        template (present) GnNonSecuredPacket mw_geoNwTsbPacketWithNextHeader_denm(
                                                                                   in template (present) LongPosVector p_sourceLongPosVec := ?,
                                                                                   in template (present) UInt8 p_hopLimit := ?,
                                                                                   in template (value) NextHeader p_nextHeader
        ) modifies mw_geoNwShbPacket := {
            commonHeader := mw_commonHeaderWithHopLimit(
                p_nextHeader,
                m_shbHeaderType,
                p_hopLimit
            ),
            payload := { 
                decodedPayload := { 
                    btpPacket := mw_btpB(
                        PICS_DENM_BTP_DESTINATION_PORT, 
                        PICS_DENM_BTP_SOURCE_PORT, 
                        ?
                    )
                }, 
                rawPayload := ?
            }
        } // End of template mw_geoNwTsbPacketWithNextHeader_denm
        
        /**
         * @desc    Receive template for GeoNetworking CAM Packet
         * @param   p_destinationShortPosVec    Short position vector of destination
         * @param   p_seqNumber                 Sequence number of GeoUnicast packet
         * @param   p_nextHeader                Id of next header
         */
        template (present) GnNonSecuredPacket mw_geoNwShbPacketWithNextHeader_cam(
                                                                                  in template (present) LongPosVector p_sourceLongPosVec := ?,
                                                                                  in template (present) UInt8 p_hopLimit := ?,
                                                                                  in template (value) NextHeader p_nextHeader,
                                                                                  in template (present) CAM p_cam := ?
        ) modifies mw_geoNwShbPacket := {
            payload := { 
                decodedPayload := { 
                    btpPacket := mw_btpB(
                        PICS_CAM_BTP_DESTINATION_PORT, 
                        PICS_CAM_BTP_SOURCE_PORT, 
                        {
                            decodedPayload := {
                                camPacket := p_cam
                            },
                            rawPayload := ?
                        }
                    )
                }, 
                rawPayload := ?
            }
        } // End of template mw_geoNwShbPacketWithNextHeader_cam
        
    } // End of group geoNetworkingTemplates 
    
    group positionTemplates {
        
        /**
         * @desc The test system reference position.
         */
        template (value) ReferencePosition m_rsuPosition(
                                                         in template (value) Latitude p_latitude,
                                                         in template (value) Longitude p_longitude
        ) := {
            latitude := f_integer2Latitude(valueof(p_latitude)),
            longitude := f_integer2Latitude(valueof(p_longitude)),
            positionConfidenceEllipse := {
                semiMajorConfidence   := SemiAxisLength_oneCentimeter_,
                semiMinorConfidence   := SemiAxisLength_oneCentimeter_,
                semiMajorOrientation  := HeadingValue_wgs84North_
            },
            altitude := {
                altitudeValue := AltitudeValue_referenceEllipsoidSurface_,
                altitudeConfidence := unavailable
            }
        } // End of template m_rsuPosition
        
        /**
         * @desc    Receive template for long position vector with strict position check
         * @param   p_longPosVector The base long position vector
         */
        template LongPosVector mw_longPosVectorPosition_vendors(
                                                                in template (value) Oct6 p_mid
        ) := {
            gnAddr := {
                typeOfAddress := ?,
                stationType := ?,
                stationCountryCode := ?,
                mid := p_mid
            },
            timestamp_ := ?,
            latitude := ?,
            longitude := ?,
            pai := ?,
            //FIXME May the delta factor should be based on the actual speed value -> low speed=lower delta, high speed=higher delta
            speed := ?,
            heading := ?
        }
        
    } // End of group positionTemplates
    
    group camTemplates {
        
        template (value) HighFrequencyContainer m_highFrequencyContainer_rsuContainerHighFrequency(
                                                                                                   in template (value) RSUContainerHighFrequency p_rsuContainerHighFrequency
        ) := {
            rsuContainerHighFrequency := p_rsuContainerHighFrequency
        }
        
        template (value) RSUContainerHighFrequency m_rSUContainerHighFrequency(
                                                                               in template (value) ProtectedCommunicationZonesRSU p_protectedCommunicationZonesRSU
        ) := {
            protectedCommunicationZonesRSU := p_protectedCommunicationZonesRSU
        }
        
        template (value) CAM m_camParm(
                                       in template (value) StationID p_stationID,
                                       in template (value) ITS_Container.StationType p_stationType := StationType_roadSideUnit_,
                                       in template (value) VehicleRole p_vehicleRole := roadOperator,
                                       in template (value) ReferencePosition p_rsuPosition,
                                       in template (value) PathHistory p_pathHistory,
                                       in template (value) HighFrequencyContainer p_highFrequencyContainer
        ) := {
            header := {
                protocolVersion := ItsPduHeader_protocolVersion_currentVersion_,
                messageID := ItsPduHeader_messageID_cam_,
                stationID := p_stationID
            },
            cam := {
                generationDeltaTime := 0, // Dynamic parameter
                camParameters := {
                    basicContainer := {
                        stationType := p_stationType,
                        referencePosition := p_rsuPosition
                    },
                    highFrequencyContainer := p_highFrequencyContainer,
                    lowFrequencyContainer := {
                        basicVehicleContainerLowFrequency := {
                            vehicleRole := p_vehicleRole,
                            exteriorLights := '00000000'B,
                            pathHistory := p_pathHistory
                        }
                    },
                    specialVehicleContainer := omit
                }
            }
        } // End of template m_camParm
        
        template (present) CAM mw_cam_stationID(
                                                in template (present) BasicVehicleContainerHighFrequency p_basicVehicleContainer := mw_HF_BV_speed(?),
                                                in template (value) StationID p_stationID,
                                                in template (present) ReferencePosition p_referencePosition := ?
        ) modifies mw_camMsg_HF_BV := {
            header := {
                stationID := p_stationID
            }, 
            cam := {
                camParameters := {
                    basicContainer := {
                        stationType := ?,
                        referencePosition := p_referencePosition
                    }
                }
            }
        } // End of template mw_cam_stationID
        
    } // End of group camTemplates
    
    group mapemTemplates {
        
        template (value) MAPEM m_mapemParm(
                                           in template (value) StationID p_stationID,
                                           in template (value) MapData p_map
        ) := {
            header := {
                protocolVersion := ItsPduHeader_protocolVersion_currentVersion_,
                messageID := ItsPduHeader_messageID_mapem_,
                stationID := p_stationID
            },
            map_ := p_map
        }
        
    } // End of group mapemTemplates
    
    group spatemTemplates {
        
        template (value) SPATEM m_spatemParm(
                                             in template (value) StationID p_stationID,
                                             in template (value) SPAT p_spat
        ) := {
            header := {
                protocolVersion := ItsPduHeader_protocolVersion_currentVersion_,
                messageID := ItsPduHeader_messageID_spatem_,
                stationID := p_stationID
            },
            spat := p_spat
        }
        
    } // End of group spatemTemplates
    
    group ivimTemplates {
        
        template (value) IVIM m_ivimParm(
                                         in template (value) StationID p_stationID,
                                         in template (value) IviStructure p_ivi
        ) := {
            header := {
                protocolVersion := ItsPduHeader_protocolVersion_currentVersion_,
                messageID := ItsPduHeader_messageID_ivim_,
                stationID := p_stationID
            },
            ivi := p_ivi
        }
        
    } // End of group ivimTemplates
    
    group denmTemplates {
        
        /**
         * @desc    Send template for DENM PDU
         * @param   p_denm  The DEN Message
         */
        template (value) DENM m_denmPdu_rsu(
                                            in template (value) StationID p_stationID,
                                            in template (value) DecentralizedEnvironmentalNotificationMessage p_denm
        ) := {
            header := LibItsDenm_Templates.m_itsPduHeader(p_stationID),
            denm := p_denm
        }
        
        /**
         * @desc    Send template for Alacarte Container including lanePosition
         */
        template (omit) AlacarteContainer m_alacarte(
                                                     in template (omit) RoadWorksContainerExtended p_roadWorksContainerExtended
        ) := {
            lanePosition := omit,
            impactReduction := omit,
            externalTemperature := omit,
            roadWorks := p_roadWorksContainerExtended,
            positioningSolution := omit,
            stationaryVehicle := omit
        }
        
        template (value) DenmParmContainers m_denmParmContainers(
                                                                 in template (value) StationID p_originatingStationID,
                                                                 in template (value) SequenceNumber p_sequenceNumber,
                                                                 in template (value) TransmissionInterval p_repetitionInterval,
                                                                 in template (value) ReferencePosition p_eventPosition,
                                                                 in template (value) CauseCodeType p_causeCodeType,
                                                                 in template (value) EventHistory p_eventHistory,
                                                                 in template (value) Traces p_traces,
                                                                 in template (value) ValidityDuration p_validityDuration := 86400,
                                                                 in template (value) RelevanceDistance p_relevanceDistance := lessThan100m,
                                                                 in template (value) RelevanceTrafficDirection p_relevanceTrafficDirection := upstreamTraffic
        ) := {
            managementContainer := {
                actionID := {
                    originatingStationID    := p_originatingStationID,
                    sequenceNumber          := p_sequenceNumber
                },
                detectionTime               := f_getCurrentTime(),
                referenceTime               := f_getCurrentTime(), // FIXME To be checked
                termination                 := omit,
                eventPosition               := p_eventPosition,
                relevanceDistance           := p_relevanceDistance,
                relevanceTrafficDirection   := omit,
                validityDuration            := p_validityDuration,
                transmissionInterval        := p_repetitionInterval,
                stationType                 := StationType_roadSideUnit_
            }, // End of field managementContainer
            situationContainer := {
                informationQuality          := 0,
                eventType := {
                    causeCode               := p_causeCodeType,
                    subCauseCode            := 0
                },
                linkedCause                 := omit,
                eventHistory                := p_eventHistory
            }, // End of field situationContainer
            locationContainer := {
                eventSpeed := omit,
                eventPositionHeading := omit,
                traces := p_traces,
                roadType := omit 
            } // End of field locationContainer
        } // End of template m_denmParm
    } // End of group denmTemplates
    
} // End of module ItsRSUsSimulator_Templates 