/// <summary>
            /// Create a new charge detail record builder.
            /// </summary>
            /// <param name="ChargeDetailRecord">An optional charge detail record.</param>
            /// <param name="CustomData">Optional custom data.</param>
            public Builder(ChargeDetailRecord ChargeDetailRecord           = null,
                           IReadOnlyDictionary <String, Object> CustomData = null)

                : base(CustomData)

            {
                if (ChargeDetailRecord != null)
                {
                    this.CDRNature           = ChargeDetailRecord.CDRNature;
                    this.ServiceSessionId    = ChargeDetailRecord.ServiceSessionId;
                    this.RequestedServiceId  = ChargeDetailRecord.RequestedServiceId;
                    this.EVSEId              = ChargeDetailRecord.EVSEId;
                    this.UserContractIdAlias = ChargeDetailRecord.UserContractIdAlias;
                    this.UserId              = ChargeDetailRecord.UserId;
                    this.StartTime           = ChargeDetailRecord.StartTime;
                    this.EndTime             = ChargeDetailRecord.EndTime;

                    this.ExecPartnerSessionId   = ChargeDetailRecord.ExecPartnerSessionId;
                    this.ExecPartnerOperatorId  = ChargeDetailRecord.ExecPartnerOperatorId;
                    this.SalesPartnerSessionId  = ChargeDetailRecord.SalesPartnerSessionId;
                    this.SalesPartnerOperatorId = ChargeDetailRecord.SalesPartnerOperatorId;
                    this.PartnerProductId       = ChargeDetailRecord.PartnerProductId;
                    this.MeterReports           = ChargeDetailRecord.MeterReports;
                }
            }
        /// <summary>
        /// Convert a WWCP charge detail record into a corresponding eMIP charge detail record.
        /// </summary>
        /// <param name="ChargeDetailRecord">A WWCP charge detail record.</param>
        /// <param name="WWCPChargeDetailRecord2ChargeDetailRecord">A delegate which allows you to modify the convertion from WWCP charge detail records to eMIP charge detail records.</param>
        public static ChargeDetailRecord ToEMIP(this WWCP.ChargeDetailRecord ChargeDetailRecord,
                                                CPO.WWCPChargeDetailRecord2ChargeDetailRecordDelegate WWCPChargeDetailRecord2ChargeDetailRecord = null)

        {
            var CDR = new ChargeDetailRecord(
                CDRNature:               CDRNatures.Final,
                ServiceSessionId:        ServiceSession_Id.Parse(ChargeDetailRecord.SessionId.ToString()),
                RequestedServiceId:      Service_Id.GenericChargeService,
                EVSEId:                  ChargeDetailRecord.EVSEId.Value.ToEMIP().Value,
                UserId:                  ChargeDetailRecord.AuthenticationStart.ToEMIP().Value,
                StartTime:               ChargeDetailRecord.SessionTime.StartTime,
                EndTime:                 ChargeDetailRecord.SessionTime.EndTime.Value,
                UserContractIdAlias:     null,
                ExecPartnerSessionId:    null,
                ExecPartnerOperatorId:   null,
                SalesPartnerSessionId:   null,           //ChargeDetailRecord.GetCustomDataAs<PartnerSession_Id?>("eMIP.PartnerSessionId"),
                SalesPartnerOperatorId:  null,
                PartnerProductId:        ChargeDetailRecord.ChargingProduct?.Id.ToEMIP(),
                MeterReports:            new MeterReport[] {
                MeterReport.Create(ChargeDetailRecord.Duration.HasValue
                                                                               ?  ChargeDetailRecord.Duration.Value.TotalMinutes.ToString("0.##").Replace(',', '.')
                                                                               : (ChargeDetailRecord.EnergyMeteringValues.Last().Timestamp - ChargeDetailRecord.EnergyMeteringValues.First().Timestamp).TotalMinutes.ToString("0.##").Replace(',', '.'),
                                   "min",
                                   MeterTypes.TotalDuration),
                MeterReport.Create(ChargeDetailRecord.ConsumedEnergy.HasValue
                                                                               ?  ChargeDetailRecord.ConsumedEnergy.Value.ToString("0.##").Replace(',', '.')
                                                                               : (ChargeDetailRecord.EnergyMeteringValues.Last().Value - ChargeDetailRecord.EnergyMeteringValues.First().Value).ToString("0.##").Replace(',', '.'),
                                   "kWh",
                                   MeterTypes.TotalEnergy),
            },
                InternalData:              new Dictionary <String, Object> {
                { WWCP_CDR, ChargeDetailRecord }
            });

            if (WWCPChargeDetailRecord2ChargeDetailRecord != null)
            {
                CDR = WWCPChargeDetailRecord2ChargeDetailRecord(ChargeDetailRecord, CDR);
            }

            return(CDR);
        }
            /// <summary>
            /// Compares two charge detail records for equality.
            /// </summary>
            /// <param name="ChargeDetailRecord">A charge detail record to compare with.</param>
            /// <returns>True if both match; False otherwise.</returns>
            public Boolean Equals(ChargeDetailRecord ChargeDetailRecord)
            {
                if ((Object)ChargeDetailRecord == null)
                {
                    return(false);
                }

                return(CDRNature.Equals(ChargeDetailRecord.CDRNature) &&
                       ServiceSessionId.Equals(ChargeDetailRecord.ServiceSessionId) &&
                       RequestedServiceId.Equals(ChargeDetailRecord.RequestedServiceId) &&
                       EVSEId.Equals(ChargeDetailRecord.EVSEId) &&
                       UserContractIdAlias.Equals(ChargeDetailRecord.UserContractIdAlias) &&
                       UserId.Equals(ChargeDetailRecord.UserId) &&
                       StartTime.Equals(ChargeDetailRecord.StartTime) &&
                       EndTime.Equals(ChargeDetailRecord.EndTime) &&

                       ExecPartnerSessionId.Equals(ChargeDetailRecord.ExecPartnerSessionId) &&
                       ExecPartnerOperatorId.Equals(ChargeDetailRecord.ExecPartnerOperatorId) &&
                       SalesPartnerSessionId.Equals(ChargeDetailRecord.SalesPartnerSessionId) &&
                       SalesPartnerOperatorId.Equals(ChargeDetailRecord.SalesPartnerOperatorId) &&
                       PartnerProductId.Equals(ChargeDetailRecord.PartnerProductId) &&
                       MeterReports.Equals(ChargeDetailRecord.MeterReports));
            }
        /// <summary>
        /// Convert an eMIP charge detail record into a corresponding WWCP charge detail record.
        /// </summary>
        /// <param name="ChargeDetailRecord">An eMIP charge detail record.</param>
        /// <param name="ChargeDetailRecord2WWCPChargeDetailRecord">A delegate which allows you to modify the convertion from eMIP charge detail records to WWCP charge detail records.</param>
        public static WWCP.ChargeDetailRecord ToWWCP(this ChargeDetailRecord ChargeDetailRecord,
                                                     CPO.ChargeDetailRecord2WWCPChargeDetailRecordDelegate ChargeDetailRecord2WWCPChargeDetailRecord = null)
        {
            //var CustomData = new Dictionary<String, Object>();

            //CustomData.Add("eMIP.CDR", ChargeDetailRecord);

            //if (ChargeDetailRecord.PartnerSessionId.HasValue)
            //    CustomData.Add("eMIP.PartnerSessionId",  ChargeDetailRecord.PartnerSessionId.ToString());

            //if (ChargeDetailRecord.HubOperatorId.HasValue)
            //    CustomData.Add("eMIP.HubOperatorId",     ChargeDetailRecord.HubOperatorId.   ToString());

            //if (ChargeDetailRecord.HubProviderId.HasValue)
            //    CustomData.Add("eMIP.HubProviderId",     ChargeDetailRecord.HubProviderId.   ToString());


            //var CDR = new  WWCP.ChargeDetailRecord(SessionId:             ChargeDetailRecord.SessionId.ToWWCP(),
            //                                       EVSEId:                ChargeDetailRecord.EVSEId.   ToWWCP(),

            //                                       ChargingProduct:       ChargeDetailRecord.PartnerProductId.HasValue
            //                                                                  ? new ChargingProduct(ChargeDetailRecord.PartnerProductId.Value.ToWWCP())
            //                                                                  : null,

            //                                       SessionTime:           new StartEndDateTime(ChargeDetailRecord.SessionStart,
            //                                                                                   ChargeDetailRecord.SessionEnd),

            //                                       IdentificationStart:   ChargeDetailRecord.Identification.ToWWCP(),

            //                                       EnergyMeteringValues:  (ChargeDetailRecord.ChargingStart.HasValue &&
            //                                                               ChargeDetailRecord.ChargingEnd  .HasValue)
            //                                                                  ? new Timestamped<Single>[] {

            //                                                                        new Timestamped<Single>(
            //                                                                            ChargeDetailRecord.ChargingStart.  Value,
            //                                                                            ChargeDetailRecord.MeterValueStart.Value
            //                                                                        ),

            //                                                                        //ToDo: Meter values in between... but we don't have timestamps for them!

            //                                                                        new Timestamped<Single>(
            //                                                                            ChargeDetailRecord.ChargingEnd.  Value,
            //                                                                            ChargeDetailRecord.MeterValueEnd.Value
            //                                                                        )

            //                                                                    }
            //                                                                  : new Timestamped<Single>[0],

            //                                       //ConsumedEnergy:      Will be calculated!

            //                                       MeteringSignature:     ChargeDetailRecord.MeteringSignature,

            //                                       CustomData:            CustomData

            //                                      );

            //if (ChargeDetailRecord2WWCPChargeDetailRecord != null)
            //    CDR = ChargeDetailRecord2WWCPChargeDetailRecord(ChargeDetailRecord, CDR);

            return(null);
        }