/*
* Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package eu.teraflow.policy;

import acl.Acl;
import context.ContextOuterClass;
import context.ContextOuterClass.ConfigRule_ACL;
import context.ContextOuterClass.ConfigRule_Custom;
import context.ContextOuterClass.ContextId;
import context.ContextOuterClass.DeviceId;
import context.ContextOuterClass.DeviceOperationalStatusEnum;
import context.ContextOuterClass.Uuid;
import eu.teraflow.policy.acl.AclAction;
import eu.teraflow.policy.acl.AclEntry;
import eu.teraflow.policy.acl.AclForwardActionEnum;
import eu.teraflow.policy.acl.AclLogActionEnum;
import eu.teraflow.policy.acl.AclMatch;
import eu.teraflow.policy.acl.AclRuleSet;
import eu.teraflow.policy.acl.AclRuleTypeEnum;
import eu.teraflow.policy.context.model.ConfigActionEnum;
import eu.teraflow.policy.context.model.ConfigRule;
import eu.teraflow.policy.context.model.ConfigRuleAcl;
import eu.teraflow.policy.context.model.ConfigRuleCustom;
import eu.teraflow.policy.context.model.ConfigRuleTypeAcl;
import eu.teraflow.policy.context.model.ConfigRuleTypeCustom;
import eu.teraflow.policy.context.model.Constraint;
import eu.teraflow.policy.context.model.ConstraintCustom;
import eu.teraflow.policy.context.model.ConstraintEndPointLocation;
import eu.teraflow.policy.context.model.ConstraintSchedule;
import eu.teraflow.policy.context.model.ConstraintSlaAvailability;
import eu.teraflow.policy.context.model.ConstraintSlaCapacity;
import eu.teraflow.policy.context.model.ConstraintSlaIsolationLevel;
import eu.teraflow.policy.context.model.ConstraintSlaLatency;
import eu.teraflow.policy.context.model.ConstraintTypeCustom;
import eu.teraflow.policy.context.model.ConstraintTypeEndPointLocation;
import eu.teraflow.policy.context.model.ConstraintTypeSchedule;
import eu.teraflow.policy.context.model.ConstraintTypeSlaAvailability;
import eu.teraflow.policy.context.model.ConstraintTypeSlaCapacity;
import eu.teraflow.policy.context.model.ConstraintTypeSlaIsolationLevel;
import eu.teraflow.policy.context.model.ConstraintTypeSlaLatency;
import eu.teraflow.policy.context.model.Device;
import eu.teraflow.policy.context.model.DeviceConfig;
import eu.teraflow.policy.context.model.DeviceDriverEnum;
import eu.teraflow.policy.context.model.DeviceOperationalStatus;
import eu.teraflow.policy.context.model.EndPoint;
import eu.teraflow.policy.context.model.EndPointId;
import eu.teraflow.policy.context.model.Event;
import eu.teraflow.policy.context.model.EventTypeEnum;
import eu.teraflow.policy.context.model.GpsPosition;
import eu.teraflow.policy.context.model.IsolationLevelEnum;
import eu.teraflow.policy.context.model.Location;
import eu.teraflow.policy.context.model.LocationTypeGpsPosition;
import eu.teraflow.policy.context.model.LocationTypeRegion;
import eu.teraflow.policy.context.model.Service;
import eu.teraflow.policy.context.model.ServiceConfig;
import eu.teraflow.policy.context.model.ServiceId;
import eu.teraflow.policy.context.model.ServiceStatus;
import eu.teraflow.policy.context.model.ServiceStatusEnum;
import eu.teraflow.policy.context.model.ServiceTypeEnum;
import eu.teraflow.policy.context.model.SliceId;
import eu.teraflow.policy.context.model.TopologyId;
import eu.teraflow.policy.kpi_sample_types.model.KpiSampleType;
import eu.teraflow.policy.model.BooleanOperator;
import eu.teraflow.policy.model.NumericalOperator;
import eu.teraflow.policy.model.PolicyRuleAction;
import eu.teraflow.policy.model.PolicyRuleActionEnum;
import eu.teraflow.policy.model.PolicyRuleBasic;
import eu.teraflow.policy.model.PolicyRuleCondition;
import eu.teraflow.policy.model.PolicyRuleDevice;
import eu.teraflow.policy.model.PolicyRuleService;
import eu.teraflow.policy.model.PolicyRuleState;
import eu.teraflow.policy.model.RuleState;
import eu.teraflow.policy.monitoring.model.AlarmDescriptor;
import eu.teraflow.policy.monitoring.model.AlarmResponse;
import eu.teraflow.policy.monitoring.model.BooleanKpiValue;
import eu.teraflow.policy.monitoring.model.FloatKpiValue;
import eu.teraflow.policy.monitoring.model.IntegerKpiValue;
import eu.teraflow.policy.monitoring.model.Kpi;
import eu.teraflow.policy.monitoring.model.KpiDescriptor;
import eu.teraflow.policy.monitoring.model.KpiValue;
import eu.teraflow.policy.monitoring.model.KpiValueRange;
import eu.teraflow.policy.monitoring.model.StringKpiValue;
import eu.teraflow.policy.monitoring.model.SubsDescriptor;
import java.util.stream.Collectors;
import javax.inject.Singleton;
import kpi_sample_types.KpiSampleTypes;
import monitoring.Monitoring;
import monitoring.Monitoring.KpiId;
import policy.Policy;
import policy.Policy.PolicyRuleId;
import policy.PolicyAction;
import policy.PolicyCondition;

@Singleton
public class Serializer {

    public DeviceId serializeDeviceId(String expectedDeviceId) {
        final var builder = DeviceId.newBuilder();
        final var uuid = serializeUuid(expectedDeviceId);

        builder.setDeviceUuid(uuid);

        return builder.build();
    }

    public String deserialize(DeviceId deviceId) {
        return deviceId.getDeviceUuid().getUuid();
    }

    public ContextId serializeContextId(String expectedContextId) {
        final var builder = ContextId.newBuilder();
        final var uuid = serializeUuid(expectedContextId);

        builder.setContextUuid(uuid);

        return builder.build();
    }

    public String deserialize(ContextId contextId) {
        return contextId.getContextUuid().getUuid();
    }

    public PolicyRuleId serializePolicyRuleId(String expectedPolicyRuleId) {
        final var builder = PolicyRuleId.newBuilder();
        final var uuid = serializeUuid(expectedPolicyRuleId);

        builder.setUuid(uuid);

        return builder.build();
    }

    public String deserialize(PolicyRuleId policyRuleId) {
        return policyRuleId.getUuid().getUuid();
    }

    public ContextOuterClass.TopologyId serialize(TopologyId topologyId) {
        final var builder = ContextOuterClass.TopologyId.newBuilder();

        final var topologyIdContextId = topologyId.getContextId();
        final var topologyIdId = topologyId.getId();

        final var contextId = serializeContextId(topologyIdContextId);
        final var topologyIdIdUuid = serializeUuid(topologyIdId);

        builder.setContextId(contextId);
        builder.setTopologyUuid(topologyIdIdUuid);

        return builder.build();
    }

    public TopologyId deserialize(ContextOuterClass.TopologyId topologyId) {
        final var topologyIdContextId = deserialize(topologyId.getContextId());
        final var topologyIdId = deserialize(topologyId.getTopologyUuid());

        return new TopologyId(topologyIdContextId, topologyIdId);
    }

    public ContextOuterClass.ConfigActionEnum serialize(ConfigActionEnum configActionEnum) {
        switch (configActionEnum) {
            case SET:
                return ContextOuterClass.ConfigActionEnum.CONFIGACTION_SET;
            case DELETE:
                return ContextOuterClass.ConfigActionEnum.CONFIGACTION_DELETE;
            case UNDEFINED:
                return ContextOuterClass.ConfigActionEnum.CONFIGACTION_UNDEFINED;
            default:
                return ContextOuterClass.ConfigActionEnum.UNRECOGNIZED;
        }
    }

    public ConfigActionEnum deserialize(
            ContextOuterClass.ConfigActionEnum serializedConfigActionEnum) {
        switch (serializedConfigActionEnum) {
            case CONFIGACTION_SET:
                return ConfigActionEnum.SET;
            case CONFIGACTION_DELETE:
                return ConfigActionEnum.DELETE;
            case CONFIGACTION_UNDEFINED:
            case UNRECOGNIZED:
            default:
                return ConfigActionEnum.UNDEFINED;
        }
    }

    public Acl.AclRuleTypeEnum serialize(AclRuleTypeEnum aclRuleTypeEnum) {
        switch (aclRuleTypeEnum) {
            case IPV4:
                return Acl.AclRuleTypeEnum.ACLRULETYPE_IPV4;
            case IPV6:
                return Acl.AclRuleTypeEnum.ACLRULETYPE_IPV6;
            case L2:
                return Acl.AclRuleTypeEnum.ACLRULETYPE_L2;
            case MPLS:
                return Acl.AclRuleTypeEnum.ACLRULETYPE_MPLS;
            case MIXED:
                return Acl.AclRuleTypeEnum.ACLRULETYPE_MIXED;
            case UNDEFINED:
                return Acl.AclRuleTypeEnum.ACLRULETYPE_UNDEFINED;
            default:
                return Acl.AclRuleTypeEnum.UNRECOGNIZED;
        }
    }

    public AclRuleTypeEnum deserialize(Acl.AclRuleTypeEnum serializedAclRuleTypeEnum) {
        switch (serializedAclRuleTypeEnum) {
            case ACLRULETYPE_IPV4:
                return AclRuleTypeEnum.IPV4;
            case ACLRULETYPE_IPV6:
                return AclRuleTypeEnum.IPV6;
            case ACLRULETYPE_L2:
                return AclRuleTypeEnum.L2;
            case ACLRULETYPE_MPLS:
                return AclRuleTypeEnum.MPLS;
            case ACLRULETYPE_MIXED:
                return AclRuleTypeEnum.MIXED;
            case UNRECOGNIZED:
            default:
                return AclRuleTypeEnum.UNDEFINED;
        }
    }

    public Acl.AclMatch serialize(AclMatch aclMatch) {
        final var builder = Acl.AclMatch.newBuilder();

        final var dscp = aclMatch.getDscp();
        final var protocol = aclMatch.getProtocol();
        final var srcAddress = aclMatch.getSrcAddress();
        final var dstAddress = aclMatch.getDstAddress();
        final var srcPort = aclMatch.getSrcPort();
        final var dstPort = aclMatch.getDstPort();
        final var startMplsLabel = aclMatch.getStartMplsLabel();
        final var endMplsLabel = aclMatch.getEndMplsLabel();

        builder.setDscp(dscp);
        builder.setProtocol(protocol);
        builder.setSrcAddress(srcAddress);
        builder.setDstAddress(dstAddress);
        builder.setSrcPort(srcPort);
        builder.setDstPort(dstPort);
        builder.setStartMplsLabel(startMplsLabel);
        builder.setEndMplsLabel(endMplsLabel);

        return builder.build();
    }

    public AclMatch deserialize(Acl.AclMatch serializedAclMatch) {
        final var dscp = serializedAclMatch.getDscp();
        final var protocol = serializedAclMatch.getProtocol();
        final var srcAddress = serializedAclMatch.getSrcAddress();
        final var dstAddress = serializedAclMatch.getDstAddress();
        final var srcPort = serializedAclMatch.getSrcPort();
        final var dstPort = serializedAclMatch.getDstPort();
        final var startMplsLabel = serializedAclMatch.getStartMplsLabel();
        final var endMplsLabel = serializedAclMatch.getEndMplsLabel();

        return new AclMatch(
                dscp, protocol, srcAddress, dstAddress, srcPort, dstPort, startMplsLabel, endMplsLabel);
    }

    public Acl.AclForwardActionEnum serialize(AclForwardActionEnum aclForwardActionEnum) {
        switch (aclForwardActionEnum) {
            case DROP:
                return Acl.AclForwardActionEnum.ACLFORWARDINGACTION_DROP;
            case ACCEPT:
                return Acl.AclForwardActionEnum.ACLFORWARDINGACTION_ACCEPT;
            case REJECT:
                return Acl.AclForwardActionEnum.ACLFORWARDINGACTION_REJECT;
            case UNDEFINED:
                return Acl.AclForwardActionEnum.ACLFORWARDINGACTION_UNDEFINED;
            default:
                return Acl.AclForwardActionEnum.UNRECOGNIZED;
        }
    }

    public AclForwardActionEnum deserialize(Acl.AclForwardActionEnum serializedAclForwardActionEnum) {
        switch (serializedAclForwardActionEnum) {
            case ACLFORWARDINGACTION_DROP:
                return AclForwardActionEnum.DROP;
            case ACLFORWARDINGACTION_ACCEPT:
                return AclForwardActionEnum.ACCEPT;
            case ACLFORWARDINGACTION_REJECT:
                return AclForwardActionEnum.REJECT;
            case UNRECOGNIZED:
            default:
                return AclForwardActionEnum.UNDEFINED;
        }
    }

    public Acl.AclLogActionEnum serialize(AclLogActionEnum aclLogActionEnum) {
        switch (aclLogActionEnum) {
            case NO_LOG:
                return Acl.AclLogActionEnum.ACLLOGACTION_NOLOG;
            case SYSLOG:
                return Acl.AclLogActionEnum.ACLLOGACTION_SYSLOG;
            case UNDEFINED:
                return Acl.AclLogActionEnum.ACLLOGACTION_UNDEFINED;
            default:
                return Acl.AclLogActionEnum.UNRECOGNIZED;
        }
    }

    public AclLogActionEnum deserialize(Acl.AclLogActionEnum serializedAclLogActionEnum) {
        switch (serializedAclLogActionEnum) {
            case ACLLOGACTION_NOLOG:
                return AclLogActionEnum.NO_LOG;
            case ACLLOGACTION_SYSLOG:
                return AclLogActionEnum.SYSLOG;
            case UNRECOGNIZED:
            default:
                return AclLogActionEnum.UNDEFINED;
        }
    }

    public Acl.AclAction serialize(AclAction aclAction) {
        final var builder = Acl.AclAction.newBuilder();

        final var aclForwardActionEnum = aclAction.getAclForwardActionEnum();
        final var aclLogActionEnum = aclAction.getAclLogActionEnum();

        final var serializedAclForwardActionEnum = serialize(aclForwardActionEnum);
        final var serializedAclLogActionEnum = serialize(aclLogActionEnum);

        builder.setForwardAction(serializedAclForwardActionEnum);
        builder.setLogAction(serializedAclLogActionEnum);

        return builder.build();
    }

    public AclAction deserialize(Acl.AclAction serializedAclAction) {
        final var serializedAclForwardActionEnum = serializedAclAction.getForwardAction();
        final var serializedAclLogActionEnum = serializedAclAction.getLogAction();

        final var aclForwardActionEnum = deserialize(serializedAclForwardActionEnum);
        final var aclLogActionEnum = deserialize(serializedAclLogActionEnum);

        return new AclAction(aclForwardActionEnum, aclLogActionEnum);
    }

    public Acl.AclEntry serialize(AclEntry aclEntry) {
        final var builder = Acl.AclEntry.newBuilder();

        final var sequenceId = aclEntry.getSequenceId();
        final var description = aclEntry.getDescription();
        final var aclMatch = aclEntry.getMatch();
        final var aclAction = aclEntry.getAction();

        final var serializedAclMatch = serialize(aclMatch);
        final var serializedAclAction = serialize(aclAction);

        builder.setSequenceId(sequenceId);
        builder.setDescription(description);
        builder.setMatch(serializedAclMatch);
        builder.setAction(serializedAclAction);

        return builder.build();
    }

    public AclEntry deserialize(Acl.AclEntry serializedAclEntry) {
        final var sequenceId = serializedAclEntry.getSequenceId();
        final var description = serializedAclEntry.getDescription();
        final var serializedAclMatch = serializedAclEntry.getMatch();
        final var serializedAclAction = serializedAclEntry.getAction();

        final var aclMatch = deserialize(serializedAclMatch);
        final var aclAction = deserialize(serializedAclAction);

        return new AclEntry(sequenceId, description, aclMatch, aclAction);
    }

    public Acl.AclRuleSet serialize(AclRuleSet aclRuleSet) {
        final var builder = Acl.AclRuleSet.newBuilder();

        final var name = aclRuleSet.getName();
        final var type = aclRuleSet.getType();
        final var description = aclRuleSet.getDescription();
        final var userId = aclRuleSet.getUserId();
        final var entries = aclRuleSet.getEntries();

        final var serializedType = serialize(type);
        final var serializedEntries =
                entries.stream().map(this::serialize).collect(Collectors.toList());

        builder.setName(name);
        builder.setType(serializedType);
        builder.setDescription(description);
        builder.setUserId(userId);
        builder.addAllEntries(serializedEntries);

        return builder.build();
    }

    public AclRuleSet deserialize(Acl.AclRuleSet serializedAclRuleSet) {
        final var serializedName = serializedAclRuleSet.getName();
        final var serializedType = serializedAclRuleSet.getType();
        final var serializedDescription = serializedAclRuleSet.getDescription();
        final var serializedUserId = serializedAclRuleSet.getUserId();
        final var serializedEntries = serializedAclRuleSet.getEntriesList();

        final var type = deserialize(serializedType);
        final var entries =
                serializedEntries.stream().map(this::deserialize).collect(Collectors.toList());

        return new AclRuleSet(serializedName, type, serializedDescription, serializedUserId, entries);
    }

    public ConfigRule_ACL serialize(ConfigRuleAcl configRuleAcl) {
        final var builder = ContextOuterClass.ConfigRule_ACL.newBuilder();

        final var endPointId = configRuleAcl.getEndPointId();
        final var aclRuleSet = configRuleAcl.getRuleSet();

        final var serializedEndPointId = serialize(endPointId);
        final var serializedAclRuleSet = serialize(aclRuleSet);

        builder.setEndpointId(serializedEndPointId);
        builder.setRuleSet(serializedAclRuleSet);

        return builder.build();
    }

    public ConfigRuleAcl deserialize(ConfigRule_ACL serializedConfigRuleAcl) {
        final var serializedEndPointId = serializedConfigRuleAcl.getEndpointId();
        final var serializedAclRuleSet = serializedConfigRuleAcl.getRuleSet();

        final var endPointId = deserialize(serializedEndPointId);
        final var aclRuleSet = deserialize(serializedAclRuleSet);

        return new ConfigRuleAcl(endPointId, aclRuleSet);
    }

    public ConfigRule_Custom serialize(ConfigRuleCustom configRuleCustom) {
        final var builder = ConfigRule_Custom.newBuilder();

        final var resourceKey = configRuleCustom.getResourceKey();
        final var resourceValue = configRuleCustom.getResourceValue();

        builder.setResourceKey(resourceKey);
        builder.setResourceValue(resourceValue);

        return builder.build();
    }

    public ConfigRuleCustom deserialize(ConfigRule_Custom serializedConfigRuleCustom) {
        final var serializedResourceKey = serializedConfigRuleCustom.getResourceKey();
        final var serializedResourceValue = serializedConfigRuleCustom.getResourceValue();

        return new ConfigRuleCustom(serializedResourceKey, serializedResourceValue);
    }

    public ContextOuterClass.ConfigRule serialize(ConfigRule configRule) {
        final var builder = ContextOuterClass.ConfigRule.newBuilder();

        final var configActionEnum = configRule.getConfigActionEnum();
        final var configRuleType = configRule.getConfigRuleType();
        final var configRuleTypeSpecificType = configRuleType.getConfigRuleType();

        if (configRuleTypeSpecificType instanceof ConfigRuleAcl) {
            final var endPointId = ((ConfigRuleAcl) configRuleTypeSpecificType).getEndPointId();
            final var aclRuleSet = ((ConfigRuleAcl) configRuleTypeSpecificType).getRuleSet();

            final var serializedEndPointId = serialize(endPointId);
            final var serializedAclRuleSet = serialize(aclRuleSet);

            final var serializedConfigRuleAcl =
                    ConfigRule_ACL.newBuilder()
                            .setEndpointId(serializedEndPointId)
                            .setRuleSet(serializedAclRuleSet)
                            .build();

            builder.setAcl(serializedConfigRuleAcl);
        }

        if (configRuleTypeSpecificType instanceof ConfigRuleCustom) {
            final var configRuleCustomResourceKey =
                    ((ConfigRuleCustom) configRuleTypeSpecificType).getResourceKey();
            final var configRuleCustomResourceValue =
                    ((ConfigRuleCustom) configRuleTypeSpecificType).getResourceValue();

            final var serializedConfigRuleCustom =
                    ConfigRule_Custom.newBuilder()
                            .setResourceKey(configRuleCustomResourceKey)
                            .setResourceValue(configRuleCustomResourceValue)
                            .build();

            builder.setCustom(serializedConfigRuleCustom);
        }

        final var serializedConfigActionEnum = serialize(configActionEnum);

        builder.setAction(serializedConfigActionEnum);

        return builder.build();
    }

    public ConfigRule deserialize(ContextOuterClass.ConfigRule serializedConfigRule) {
        final var serializedConfigActionEnum = serializedConfigRule.getAction();
        final var typeOfConfigRule = serializedConfigRule.getConfigRuleCase();

        final var configActionEnum = deserialize(serializedConfigActionEnum);

        switch (typeOfConfigRule) {
            case ACL:
                final var serializedConfigRuleAcl = serializedConfigRule.getAcl();

                final var configRuleAcl = deserialize(serializedConfigRuleAcl);
                final var configRuleTypeAcl = new ConfigRuleTypeAcl(configRuleAcl);

                return new ConfigRule(configActionEnum, configRuleTypeAcl);
            case CUSTOM:
                final var serializedConfigRuleCustom = serializedConfigRule.getCustom();

                final var configRuleCustom = deserialize(serializedConfigRuleCustom);
                final var configRuleTypeCustom = new ConfigRuleTypeCustom(configRuleCustom);

                return new ConfigRule(configActionEnum, configRuleTypeCustom);
            default:
            case CONFIGRULE_NOT_SET:
                throw new IllegalStateException("Config Rule not set");
        }
    }

    public ContextOuterClass.Location serialize(Location location) {
        final var builder = ContextOuterClass.Location.newBuilder();

        final var locationType = location.getLocationType();
        final var locationTypeSpecificType = locationType.getLocationType();

        if (locationTypeSpecificType instanceof GpsPosition) {
            final var latitude = ((GpsPosition) locationTypeSpecificType).getLatitude();
            final var longitude = ((GpsPosition) locationTypeSpecificType).getLongitude();

            final var serializedGpsPosition =
                    ContextOuterClass.GPS_Position.newBuilder()
                            .setLatitude(latitude)
                            .setLongitude(longitude)
                            .build();

            builder.setGpsPosition(serializedGpsPosition);
        }

        if (locationTypeSpecificType instanceof String) {
            final var region = ((String) locationTypeSpecificType);

            builder.setRegion(region);
        }

        return builder.build();
    }

    public Location deserialize(ContextOuterClass.Location serializedLocation) {
        final var typeOfLocation = serializedLocation.getLocationCase();

        switch (typeOfLocation) {
            case REGION:
                final var region = serializedLocation.getRegion();
                final var locationTypeRegion = new LocationTypeRegion(region);

                return new Location(locationTypeRegion);
            case GPS_POSITION:
                final var serializedGpsPosition = serializedLocation.getGpsPosition();
                final var latitude = serializedGpsPosition.getLatitude();
                final var longitude = serializedGpsPosition.getLongitude();

                final var gpsPosition = new GpsPosition(latitude, longitude);
                final var locationTypeGpsPosition = new LocationTypeGpsPosition(gpsPosition);

                return new Location(locationTypeGpsPosition);
            default:
            case LOCATION_NOT_SET:
                throw new IllegalStateException("Location value not set");
        }
    }

    public ContextOuterClass.IsolationLevelEnum serialize(IsolationLevelEnum isolationLevelEnum) {
        switch (isolationLevelEnum) {
            case NO_ISOLATION:
                return ContextOuterClass.IsolationLevelEnum.NO_ISOLATION;
            case PHYSICAL_ISOLATION:
                return ContextOuterClass.IsolationLevelEnum.PHYSICAL_ISOLATION;
            case LOGICAL_ISOLATION:
                return ContextOuterClass.IsolationLevelEnum.LOGICAL_ISOLATION;
            case PROCESS_ISOLATION:
                return ContextOuterClass.IsolationLevelEnum.PROCESS_ISOLATION;
            case PHYSICAL_MEMORY_ISOLATION:
                return ContextOuterClass.IsolationLevelEnum.PHYSICAL_MEMORY_ISOLATION;
            case PHYSICAL_NETWORK_ISOLATION:
                return ContextOuterClass.IsolationLevelEnum.PHYSICAL_NETWORK_ISOLATION;
            case VIRTUAL_RESOURCE_ISOLATION:
                return ContextOuterClass.IsolationLevelEnum.VIRTUAL_RESOURCE_ISOLATION;
            case NETWORK_FUNCTIONS_ISOLATION:
                return ContextOuterClass.IsolationLevelEnum.NETWORK_FUNCTIONS_ISOLATION;
            case SERVICE_ISOLATION:
                return ContextOuterClass.IsolationLevelEnum.SERVICE_ISOLATION;
            default:
                return ContextOuterClass.IsolationLevelEnum.UNRECOGNIZED;
        }
    }

    public IsolationLevelEnum deserialize(
            ContextOuterClass.IsolationLevelEnum serializedIsolationLevelEnum) {
        switch (serializedIsolationLevelEnum) {
            case PHYSICAL_ISOLATION:
                return IsolationLevelEnum.PHYSICAL_ISOLATION;
            case LOGICAL_ISOLATION:
                return IsolationLevelEnum.LOGICAL_ISOLATION;
            case PROCESS_ISOLATION:
                return IsolationLevelEnum.PROCESS_ISOLATION;
            case PHYSICAL_MEMORY_ISOLATION:
                return IsolationLevelEnum.PHYSICAL_MEMORY_ISOLATION;
            case PHYSICAL_NETWORK_ISOLATION:
                return IsolationLevelEnum.PHYSICAL_NETWORK_ISOLATION;
            case VIRTUAL_RESOURCE_ISOLATION:
                return IsolationLevelEnum.VIRTUAL_RESOURCE_ISOLATION;
            case NETWORK_FUNCTIONS_ISOLATION:
                return IsolationLevelEnum.NETWORK_FUNCTIONS_ISOLATION;
            case SERVICE_ISOLATION:
                return IsolationLevelEnum.SERVICE_ISOLATION;
            case UNRECOGNIZED:
            default:
                return IsolationLevelEnum.NO_ISOLATION;
        }
    }

    public ContextOuterClass.Constraint_Custom serialize(ConstraintCustom constraintCustom) {
        final var builder = ContextOuterClass.Constraint_Custom.newBuilder();

        final var constraintType = constraintCustom.getConstraintType();
        final var constraintValue = constraintCustom.getConstraintValue();

        builder.setConstraintType(constraintType);
        builder.setConstraintValue(constraintValue);

        return builder.build();
    }

    public ConstraintCustom deserialize(
            ContextOuterClass.Constraint_Custom serializedConstraintCustom) {
        final var constraintType = serializedConstraintCustom.getConstraintType();
        final var constraintValue = serializedConstraintCustom.getConstraintValue();

        return new ConstraintCustom(constraintType, constraintValue);
    }

    public ContextOuterClass.Constraint_Schedule serialize(ConstraintSchedule constraintSchedule) {
        final var builder = ContextOuterClass.Constraint_Schedule.newBuilder();

        final var startTimestamp = constraintSchedule.getStartTimestamp();
        final var durationDays = constraintSchedule.getDurationDays();

        builder.setStartTimestamp(startTimestamp);
        builder.setDurationDays(durationDays);

        return builder.build();
    }

    public ConstraintSchedule deserialize(
            ContextOuterClass.Constraint_Schedule serializedConstraintSchedule) {
        final var startTimestamp = serializedConstraintSchedule.getStartTimestamp();
        final var durationDays = serializedConstraintSchedule.getDurationDays();

        return new ConstraintSchedule(startTimestamp, durationDays);
    }

    public ContextOuterClass.Constraint_EndPointLocation serialize(
            ConstraintEndPointLocation constraintEndPointLocation) {
        final var builder = ContextOuterClass.Constraint_EndPointLocation.newBuilder();

        final var endPointId = constraintEndPointLocation.getEndPointId();
        final var location = constraintEndPointLocation.getLocation();

        final var serializedEndPointId = serialize(endPointId);
        final var serializedLocation = serialize(location);

        builder.setEndpointId(serializedEndPointId);
        builder.setLocation(serializedLocation);

        return builder.build();
    }

    public ConstraintEndPointLocation deserialize(
            ContextOuterClass.Constraint_EndPointLocation serializedConstraintEndPointLocation) {
        final var serializedEndPointId = serializedConstraintEndPointLocation.getEndpointId();
        final var serializedLocation = serializedConstraintEndPointLocation.getLocation();

        final var endPointId = deserialize(serializedEndPointId);
        final var location = deserialize(serializedLocation);

        return new ConstraintEndPointLocation(endPointId, location);
    }

    public ContextOuterClass.Constraint_SLA_Availability serialize(
            ConstraintSlaAvailability constraintSlaAvailability) {
        final var builder = ContextOuterClass.Constraint_SLA_Availability.newBuilder();

        final var numDisjointPaths = constraintSlaAvailability.getNumDisjointPaths();
        final var isAllActive = constraintSlaAvailability.isAllActive();

        builder.setNumDisjointPaths(numDisjointPaths);
        builder.setAllActive(isAllActive);

        return builder.build();
    }

    public ConstraintSlaAvailability deserialize(
            ContextOuterClass.Constraint_SLA_Availability serializedConstraintSlaAvailability) {
        final var numDisjointPaths = serializedConstraintSlaAvailability.getNumDisjointPaths();
        final var isAllActive = serializedConstraintSlaAvailability.getAllActive();

        return new ConstraintSlaAvailability(numDisjointPaths, isAllActive);
    }

    public ContextOuterClass.Constraint_SLA_Capacity serialize(
            ConstraintSlaCapacity constraintSlaCapacity) {
        final var builder = ContextOuterClass.Constraint_SLA_Capacity.newBuilder();

        final var capacityGbps = constraintSlaCapacity.getCapacityGbps();

        builder.setCapacityGbps(capacityGbps);

        return builder.build();
    }

    public ConstraintSlaCapacity deserialize(
            ContextOuterClass.Constraint_SLA_Capacity serializedConstraintSlaCapacity) {
        final var capacityGbps = serializedConstraintSlaCapacity.getCapacityGbps();

        return new ConstraintSlaCapacity(capacityGbps);
    }

    public ContextOuterClass.Constraint_SLA_Isolation_level serialize(
            ConstraintSlaIsolationLevel constraintSlaIsolationLevel) {
        final var builder = ContextOuterClass.Constraint_SLA_Isolation_level.newBuilder();

        final var isolationLevelEnum = constraintSlaIsolationLevel.getIsolationLevelEnum();

        final var serializedIsolationLevelEnum = serialize(isolationLevelEnum);

        builder.setIsolationLevel(serializedIsolationLevelEnum);

        return builder.build();
    }

    public ConstraintSlaIsolationLevel deserialize(
            ContextOuterClass.Constraint_SLA_Isolation_level serializedConstraintIsolationLevel) {
        final var serializedIsolationLevelEnum = serializedConstraintIsolationLevel.getIsolationLevel();

        final var isolationLevelEnum = deserialize(serializedIsolationLevelEnum);

        return new ConstraintSlaIsolationLevel(isolationLevelEnum);
    }

    public ContextOuterClass.Constraint_SLA_Latency serialize(
            ConstraintSlaLatency constraintSlaLatency) {
        final var builder = ContextOuterClass.Constraint_SLA_Latency.newBuilder();

        final var e2eLatencyMs = constraintSlaLatency.getE2eLatencyMs();

        builder.setE2ELatencyMs(e2eLatencyMs);

        return builder.build();
    }

    public ConstraintSlaLatency deserialize(
            ContextOuterClass.Constraint_SLA_Latency serializedConstraintSlaLatency) {
        final var e2ELatencyMs = serializedConstraintSlaLatency.getE2ELatencyMs();

        return new ConstraintSlaLatency(e2ELatencyMs);
    }

    public ContextOuterClass.Constraint serialize(Constraint constraint) {
        final var builder = ContextOuterClass.Constraint.newBuilder();

        final var constraintType = constraint.getConstraintType();
        final var constraintTypeSpecificType = constraintType.getConstraintType();

        if (constraintTypeSpecificType instanceof ConstraintCustom) {
            final var constraintCustomType =
                    ((ConstraintCustom) constraintTypeSpecificType).getConstraintType();
            final var constraintCustomValue =
                    ((ConstraintCustom) constraintTypeSpecificType).getConstraintValue();

            final var serializedConstraintCustom =
                    ContextOuterClass.Constraint_Custom.newBuilder()
                            .setConstraintType(constraintCustomType)
                            .setConstraintValue(constraintCustomValue)
                            .build();

            builder.setCustom(serializedConstraintCustom);
        }

        if (constraintTypeSpecificType instanceof ConstraintSchedule) {
            final var startTimestamp =
                    ((ConstraintSchedule) constraintTypeSpecificType).getStartTimestamp();
            final var durationDays = ((ConstraintSchedule) constraintTypeSpecificType).getDurationDays();

            final var serializedConstraintSchedule =
                    ContextOuterClass.Constraint_Schedule.newBuilder()
                            .setStartTimestamp(startTimestamp)
                            .setDurationDays(durationDays)
                            .build();

            builder.setSchedule(serializedConstraintSchedule);
        }

        if (constraintTypeSpecificType instanceof ConstraintEndPointLocation) {
            final var endPointId =
                    ((ConstraintEndPointLocation) constraintTypeSpecificType).getEndPointId();
            final var location = ((ConstraintEndPointLocation) constraintTypeSpecificType).getLocation();

            final var serializedEndPointId = serialize(endPointId);
            final var serializedLocation = serialize(location);

            final var serializedConstraintEndPointLocation =
                    ContextOuterClass.Constraint_EndPointLocation.newBuilder()
                            .setEndpointId(serializedEndPointId)
                            .setLocation(serializedLocation)
                            .build();

            builder.setEndpointLocation(serializedConstraintEndPointLocation);
        }

        if (constraintTypeSpecificType instanceof ConstraintSlaAvailability) {
            final var numDisJointPaths =
                    ((ConstraintSlaAvailability) constraintTypeSpecificType).getNumDisjointPaths();
            final var isAllActive =
                    ((ConstraintSlaAvailability) constraintTypeSpecificType).isAllActive();

            final var serializedConstraintSlaAvailability =
                    ContextOuterClass.Constraint_SLA_Availability.newBuilder()
                            .setNumDisjointPaths(numDisJointPaths)
                            .setAllActive(isAllActive)
                            .build();

            builder.setSlaAvailability(serializedConstraintSlaAvailability);
        }

        if (constraintTypeSpecificType instanceof ConstraintSlaCapacity) {
            final var capacityGbps =
                    ((ConstraintSlaCapacity) constraintTypeSpecificType).getCapacityGbps();

            final var serializedConstraintSlaCapacity =
                    ContextOuterClass.Constraint_SLA_Capacity.newBuilder()
                            .setCapacityGbps(capacityGbps)
                            .build();

            builder.setSlaCapacity(serializedConstraintSlaCapacity);
        }

        if (constraintTypeSpecificType instanceof ConstraintSlaIsolationLevel) {
            final var isolationLevelEnum =
                    ((ConstraintSlaIsolationLevel) constraintTypeSpecificType).getIsolationLevelEnum();

            final var serializedIsolationLevelEnum = serialize(isolationLevelEnum);
            final var serializedConstraintSlaIsolationLevel =
                    ContextOuterClass.Constraint_SLA_Isolation_level.newBuilder()
                            .setIsolationLevel(serializedIsolationLevelEnum)
                            .build();

            builder.setSlaIsolation(serializedConstraintSlaIsolationLevel);
        }

        if (constraintTypeSpecificType instanceof ConstraintSlaLatency) {
            final var e2eLatencyMs =
                    ((ConstraintSlaLatency) constraintTypeSpecificType).getE2eLatencyMs();

            final var serializedConstraintSlaLatency =
                    ContextOuterClass.Constraint_SLA_Latency.newBuilder()
                            .setE2ELatencyMs(e2eLatencyMs)
                            .build();

            builder.setSlaLatency(serializedConstraintSlaLatency);
        }

        return builder.build();
    }

    public Constraint deserialize(ContextOuterClass.Constraint serializedConstraint) {
        final var typeOfConstraint = serializedConstraint.getConstraintCase();

        switch (typeOfConstraint) {
            case CUSTOM:
                final var serializedConstraintCustom = serializedConstraint.getCustom();
                final var constraintType = serializedConstraintCustom.getConstraintType();
                final var constraintValue = serializedConstraintCustom.getConstraintValue();

                final var constraintCustom = new ConstraintCustom(constraintType, constraintValue);
                final var constraintTypeCustom = new ConstraintTypeCustom(constraintCustom);

                return new Constraint(constraintTypeCustom);
            case SCHEDULE:
                final var serializedConstraintSchedule = serializedConstraint.getSchedule();
                final var startTimestamp = serializedConstraintSchedule.getStartTimestamp();
                final var durationDays = serializedConstraintSchedule.getDurationDays();

                final var constraintSchedule = new ConstraintSchedule(startTimestamp, durationDays);
                final var constraintTypeSchedule = new ConstraintTypeSchedule(constraintSchedule);

                return new Constraint(constraintTypeSchedule);
            case ENDPOINT_LOCATION:
                final var serializedConstrainEndPointLocation = serializedConstraint.getEndpointLocation();
                final var serializedEndPointId = serializedConstrainEndPointLocation.getEndpointId();
                final var serializedLocation = serializedConstrainEndPointLocation.getLocation();

                final var endPointId = deserialize(serializedEndPointId);
                final var location = deserialize(serializedLocation);
                final var constraintEndPointLocation = new ConstraintEndPointLocation(endPointId, location);
                final var constraintTypeEndPointLocation =
                        new ConstraintTypeEndPointLocation(constraintEndPointLocation);

                return new Constraint(constraintTypeEndPointLocation);
            case SLA_CAPACITY:
                final var serializedConstrainSlaCapacity = serializedConstraint.getSlaCapacity();
                final var capacityGbps = serializedConstrainSlaCapacity.getCapacityGbps();

                final var constraintSlaCapacity = new ConstraintSlaCapacity(capacityGbps);
                final var constraintTypeSlaCapacity = new ConstraintTypeSlaCapacity(constraintSlaCapacity);

                return new Constraint(constraintTypeSlaCapacity);
            case SLA_LATENCY:
                final var serializedConstrainSlaLatency = serializedConstraint.getSlaLatency();
                final var e2ELatencyMs = serializedConstrainSlaLatency.getE2ELatencyMs();

                final var constraintSlaLatency = new ConstraintSlaLatency(e2ELatencyMs);
                final var constraintTypeSlaLatency = new ConstraintTypeSlaLatency(constraintSlaLatency);

                return new Constraint(constraintTypeSlaLatency);
            case SLA_AVAILABILITY:
                final var serializedConstrainSlaAvailability = serializedConstraint.getSlaAvailability();
                final var numDisjointPaths = serializedConstrainSlaAvailability.getNumDisjointPaths();
                final var isAllActive = serializedConstrainSlaAvailability.getAllActive();

                final var constraintSlaAvailability =
                        new ConstraintSlaAvailability(numDisjointPaths, isAllActive);
                final var constraintTypeSlaAvailability =
                        new ConstraintTypeSlaAvailability(constraintSlaAvailability);

                return new Constraint(constraintTypeSlaAvailability);
            case SLA_ISOLATION:
                final var serializedConstrainSlaIsolation = serializedConstraint.getSlaIsolation();
                final var serializedIsolationLevelEnum =
                        serializedConstrainSlaIsolation.getIsolationLevel();

                final var isolationLevelEnum = deserialize(serializedIsolationLevelEnum);
                final var constraintSlaIsolation = new ConstraintSlaIsolationLevel(isolationLevelEnum);
                final var constraintTypeSlaIsolation =
                        new ConstraintTypeSlaIsolationLevel(constraintSlaIsolation);

                return new Constraint(constraintTypeSlaIsolation);

            default:
            case CONSTRAINT_NOT_SET:
                throw new IllegalStateException("Constraint value not set");
        }
    }

    public ContextOuterClass.EndPointId serialize(EndPointId endPointId) {
        final var builder = ContextOuterClass.EndPointId.newBuilder();

        final var endPointIdTopologyId = endPointId.getTopologyId();
        final var endPointIdDeviceId = endPointId.getDeviceId();
        final var endPointIdId = endPointId.getId();

        final var serializedTopologyId = serialize(endPointIdTopologyId);
        final var serializedDeviceId = serializeDeviceId(endPointIdDeviceId);
        final var serializedEndPointIdId = serializeUuid(endPointIdId);

        builder.setTopologyId(serializedTopologyId);
        builder.setDeviceId(serializedDeviceId);
        builder.setEndpointUuid(serializedEndPointIdId);

        return builder.build();
    }

    public EndPointId deserialize(ContextOuterClass.EndPointId serializedEndPointId) {
        final var serializedTopologyId = serializedEndPointId.getTopologyId();
        final var serializedDeviceId = serializedEndPointId.getDeviceId();
        final var serializedId = serializedEndPointId.getEndpointUuid();

        final var topologyId = deserialize(serializedTopologyId);
        final var deviceId = deserialize(serializedDeviceId);
        final var id = deserialize(serializedId);

        return new EndPointId(topologyId, deviceId, id);
    }

    public ContextOuterClass.EventTypeEnum serialize(EventTypeEnum eventTypeEnum) {
        switch (eventTypeEnum) {
            case CREATE:
                return ContextOuterClass.EventTypeEnum.EVENTTYPE_CREATE;
            case REMOVE:
                return ContextOuterClass.EventTypeEnum.EVENTTYPE_REMOVE;
            case UPDATE:
                return ContextOuterClass.EventTypeEnum.EVENTTYPE_UPDATE;
            case UNDEFINED:
                return ContextOuterClass.EventTypeEnum.EVENTTYPE_UNDEFINED;
            default:
                return ContextOuterClass.EventTypeEnum.UNRECOGNIZED;
        }
    }

    public EventTypeEnum deserialize(ContextOuterClass.EventTypeEnum serializedEventType) {
        switch (serializedEventType) {
            case EVENTTYPE_CREATE:
                return EventTypeEnum.CREATE;
            case EVENTTYPE_REMOVE:
                return EventTypeEnum.REMOVE;
            case EVENTTYPE_UPDATE:
                return EventTypeEnum.UPDATE;
            case EVENTTYPE_UNDEFINED:
            case UNRECOGNIZED:
            default:
                return EventTypeEnum.UNDEFINED;
        }
    }

    public ContextOuterClass.Timestamp serialize(double timestamp) {
        final var builder = ContextOuterClass.Timestamp.newBuilder();

        builder.setTimestamp(timestamp);

        return builder.build();
    }

    public double deserialize(ContextOuterClass.Timestamp serializedTimeStamp) {

        return serializedTimeStamp.getTimestamp();
    }

    public ContextOuterClass.Event serialize(Event event) {
        final var builder = ContextOuterClass.Event.newBuilder();

        final var eventType = serialize(event.getEventTypeEnum());
        final var timestamp = serialize(event.getTimestamp());
        builder.setEventType(eventType);
        builder.setTimestamp(timestamp);

        return builder.build();
    }

    public Event deserialize(ContextOuterClass.Event serializedEvent) {
        final var timestamp = deserialize(serializedEvent.getTimestamp());
        final var eventType = deserialize(serializedEvent.getEventType());

        return new Event(timestamp, eventType);
    }

    public ContextOuterClass.ServiceId serialize(ServiceId serviceId) {
        final var builder = ContextOuterClass.ServiceId.newBuilder();

        final var contextId = serviceId.getContextId();
        final var id = serviceId.getId();

        final var serializedContextId = serializeContextId(contextId);
        final var serializedId = serializeUuid(id);

        builder.setContextId(serializedContextId);
        builder.setServiceUuid(serializedId);

        return builder.build();
    }

    public ServiceId deserialize(ContextOuterClass.ServiceId serializedServiceId) {
        final var serializedContextId = serializedServiceId.getContextId();
        final var serializedId = serializedServiceId.getServiceUuid();

        final var contextId = deserialize(serializedContextId);
        final var id = deserialize(serializedId);

        return new ServiceId(contextId, id);
    }

    public ContextOuterClass.SliceId serialize(SliceId sliceId) {
        final var builder = ContextOuterClass.SliceId.newBuilder();

        final var contextId = sliceId.getContextId();
        final var id = sliceId.getId();

        final var serializedContextId = serializeContextId(contextId);
        final var serializedId = serializeUuid(id);

        builder.setContextId(serializedContextId);
        builder.setSliceUuid(serializedId);

        return builder.build();
    }

    public SliceId deserialize(ContextOuterClass.SliceId serializedSliceId) {
        final var serializedContextId = serializedSliceId.getContextId();
        final var serializedId = serializedSliceId.getSliceUuid();

        final var contextId = deserialize(serializedContextId);
        final var id = deserialize(serializedId);

        return new SliceId(contextId, id);
    }

    public ContextOuterClass.ServiceStatusEnum serialize(ServiceStatusEnum serviceStatusEnum) {
        switch (serviceStatusEnum) {
            case ACTIVE:
                return ContextOuterClass.ServiceStatusEnum.SERVICESTATUS_ACTIVE;
            case PLANNED:
                return ContextOuterClass.ServiceStatusEnum.SERVICESTATUS_PLANNED;
            case PENDING_REMOVAL:
                return ContextOuterClass.ServiceStatusEnum.SERVICESTATUS_PENDING_REMOVAL;
            case UNDEFINED:
                return ContextOuterClass.ServiceStatusEnum.SERVICESTATUS_UNDEFINED;
            default:
                return ContextOuterClass.ServiceStatusEnum.UNRECOGNIZED;
        }
    }

    public ServiceStatusEnum deserialize(
            ContextOuterClass.ServiceStatusEnum serializedServiceStatusEnum) {
        switch (serializedServiceStatusEnum) {
            case SERVICESTATUS_ACTIVE:
                return ServiceStatusEnum.ACTIVE;
            case SERVICESTATUS_PLANNED:
                return ServiceStatusEnum.PLANNED;
            case SERVICESTATUS_PENDING_REMOVAL:
                return ServiceStatusEnum.PENDING_REMOVAL;
            case SERVICESTATUS_UNDEFINED:
            case UNRECOGNIZED:
            default:
                return ServiceStatusEnum.UNDEFINED;
        }
    }

    public ContextOuterClass.ServiceTypeEnum serialize(ServiceTypeEnum serviceTypeEnum) {
        switch (serviceTypeEnum) {
            case L2NM:
                return ContextOuterClass.ServiceTypeEnum.SERVICETYPE_L2NM;
            case L3NM:
                return ContextOuterClass.ServiceTypeEnum.SERVICETYPE_L3NM;
            case TAPI_CONNECTIVITY_SERVICE:
                return ContextOuterClass.ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE;
            case UNKNOWN:
                return ContextOuterClass.ServiceTypeEnum.SERVICETYPE_UNKNOWN;
            default:
                return ContextOuterClass.ServiceTypeEnum.UNRECOGNIZED;
        }
    }

    public ServiceTypeEnum deserialize(ContextOuterClass.ServiceTypeEnum serializedServiceTypeEnum) {
        switch (serializedServiceTypeEnum) {
            case SERVICETYPE_L2NM:
                return ServiceTypeEnum.L2NM;
            case SERVICETYPE_L3NM:
                return ServiceTypeEnum.L3NM;
            case SERVICETYPE_TAPI_CONNECTIVITY_SERVICE:
                return ServiceTypeEnum.TAPI_CONNECTIVITY_SERVICE;
            case SERVICETYPE_UNKNOWN:
            case UNRECOGNIZED:
            default:
                return ServiceTypeEnum.UNKNOWN;
        }
    }

    public ContextOuterClass.ServiceStatus serialize(ServiceStatus serviceStatus) {
        final var builder = ContextOuterClass.ServiceStatus.newBuilder();

        final var serviceStatusEnum = serviceStatus.getServiceStatus();
        final var serializedServiceStatusEnum = serialize(serviceStatusEnum);

        builder.setServiceStatus(serializedServiceStatusEnum);

        return builder.build();
    }

    public ServiceStatus deserialize(ContextOuterClass.ServiceStatus serializedServiceStatus) {
        final var serializedServiceStatusEnum = serializedServiceStatus.getServiceStatus();
        final var serviceStatusEnum = deserialize(serializedServiceStatusEnum);

        return new ServiceStatus(serviceStatusEnum);
    }

    public ContextOuterClass.ServiceConfig serialize(ServiceConfig serviceConfig) {
        final var builder = ContextOuterClass.ServiceConfig.newBuilder();

        final var serializedConfigRules =
                serviceConfig.getConfigRules().stream().map(this::serialize).collect(Collectors.toList());

        builder.addAllConfigRules(serializedConfigRules);

        return builder.build();
    }

    public ServiceConfig deserialize(ContextOuterClass.ServiceConfig serviceConfig) {
        final var configRules =
                serviceConfig.getConfigRulesList().stream()
                        .map(this::deserialize)
                        .collect(Collectors.toList());

        return new ServiceConfig(configRules);
    }

    public ContextOuterClass.Service serialize(Service service) {
        final var builder = ContextOuterClass.Service.newBuilder();

        final var serviceId = service.getServiceId();
        final var serviceType = service.getServiceType();
        final var serviceEndPointIds = service.getServiceEndPointIds();
        final var serviceConstraints = service.getServiceConstraints();
        final var serviceStatus = service.getServiceStatus();
        final var serviceConfig = service.getServiceConfig();
        final var serviceTimestamp = service.getTimestamp();

        final var serializedServiceId = serialize(serviceId);
        final var serializedServiceType = serialize(serviceType);
        final var serializedServiceEndPointIds =
                serviceEndPointIds.stream().map(this::serialize).collect(Collectors.toList());
        final var serializedServiceConstraints =
                serviceConstraints.stream().map(this::serialize).collect(Collectors.toList());
        final var serializedServiceStatus = serialize(serviceStatus);
        final var serializedServiceConfig = serialize(serviceConfig);
        final var serializedTimestamp = serialize(serviceTimestamp);

        builder.setServiceId(serializedServiceId);
        builder.setServiceType(serializedServiceType);
        builder.addAllServiceEndpointIds(serializedServiceEndPointIds);
        builder.addAllServiceConstraints(serializedServiceConstraints);
        builder.setServiceStatus(serializedServiceStatus);
        builder.setServiceConfig(serializedServiceConfig);
        builder.setTimestamp(serializedTimestamp);

        return builder.build();
    }

    public Service deserialize(ContextOuterClass.Service serializedService) {

        final var serializedServiceId = serializedService.getServiceId();
        final var serializedServiceType = serializedService.getServiceType();
        final var serializedServiceEndPointIds = serializedService.getServiceEndpointIdsList();
        final var serializedServiceConstraints = serializedService.getServiceConstraintsList();
        final var serializedServiceStatus = serializedService.getServiceStatus();
        final var serializedServiceConfig = serializedService.getServiceConfig();
        final var serializedTimestamp = serializedService.getTimestamp();

        final var serviceId = deserialize(serializedServiceId);
        final var serviceType = deserialize(serializedServiceType);
        final var serviceEndPointIds =
                serializedServiceEndPointIds.stream().map(this::deserialize).collect(Collectors.toList());
        final var serviceConstraints =
                serializedServiceConstraints.stream().map(this::deserialize).collect(Collectors.toList());
        final var serviceStatus = deserialize(serializedServiceStatus);
        final var serviceConfig = deserialize(serializedServiceConfig);
        final var timestamp = deserialize(serializedTimestamp);

        return new Service(
                serviceId,
                serviceType,
                serviceEndPointIds,
                serviceConstraints,
                serviceStatus,
                serviceConfig,
                timestamp);
    }

    public KpiSampleTypes.KpiSampleType serialize(KpiSampleType kpiSampleType) {
        switch (kpiSampleType) {
            case PACKETS_TRANSMITTED:
                return KpiSampleTypes.KpiSampleType.KPISAMPLETYPE_PACKETS_TRANSMITTED;
            case PACKETS_RECEIVED:
                return KpiSampleTypes.KpiSampleType.KPISAMPLETYPE_PACKETS_RECEIVED;
            case BYTES_TRANSMITTED:
                return KpiSampleTypes.KpiSampleType.KPISAMPLETYPE_BYTES_TRANSMITTED;
            case BYTES_RECEIVED:
                return KpiSampleTypes.KpiSampleType.KPISAMPLETYPE_BYTES_RECEIVED;
            case UNKNOWN:
                return KpiSampleTypes.KpiSampleType.KPISAMPLETYPE_UNKNOWN;
            default:
                return KpiSampleTypes.KpiSampleType.UNRECOGNIZED;
        }
    }

    public KpiSampleType deserialize(KpiSampleTypes.KpiSampleType serializedKpiSampleType) {
        switch (serializedKpiSampleType) {
            case KPISAMPLETYPE_PACKETS_TRANSMITTED:
                return KpiSampleType.PACKETS_TRANSMITTED;
            case KPISAMPLETYPE_PACKETS_RECEIVED:
                return KpiSampleType.PACKETS_RECEIVED;
            case KPISAMPLETYPE_BYTES_TRANSMITTED:
                return KpiSampleType.BYTES_TRANSMITTED;
            case KPISAMPLETYPE_BYTES_RECEIVED:
                return KpiSampleType.BYTES_RECEIVED;
            case KPISAMPLETYPE_UNKNOWN:
            default:
                return KpiSampleType.UNKNOWN;
        }
    }

    public Policy.RuleState serialize(RuleState rulestate) {
        switch (rulestate) {
            case POLICY_FAILED:
                return Policy.RuleState.POLICY_FAILED;
            case POLICY_INSERTED:
                return Policy.RuleState.POLICY_INSERTED;
            case POLICY_VALIDATED:
                return Policy.RuleState.POLICY_VALIDATED;
            case POLICY_PROVISIONED:
                return Policy.RuleState.POLICY_PROVISIONED;
            case POLICY_ACTIVE:
                return Policy.RuleState.POLICY_ACTIVE;
            case POLICY_ENFORCED:
                return Policy.RuleState.POLICY_ENFORCED;
            case POLICY_INEFFECTIVE:
                return Policy.RuleState.POLICY_INEFFECTIVE;
            case POLICY_EFFECTIVE:
                return Policy.RuleState.POLICY_EFFECTIVE;
            case POLICY_UPDATED:
                return Policy.RuleState.POLICY_UPDATED;
            case POLICY_REMOVED:
                return Policy.RuleState.POLICY_REMOVED;
            case POLICY_UNDEFINED:
                return Policy.RuleState.POLICY_UNDEFINED;
            default:
                return Policy.RuleState.UNRECOGNIZED;
        }
    }

    public RuleState deserialize(Policy.RuleState serializedRuleState) {
        switch (serializedRuleState) {
            case POLICY_INSERTED:
                return RuleState.POLICY_INSERTED;
            case POLICY_VALIDATED:
                return RuleState.POLICY_VALIDATED;
            case POLICY_PROVISIONED:
                return RuleState.POLICY_PROVISIONED;
            case POLICY_ACTIVE:
                return RuleState.POLICY_ACTIVE;
            case POLICY_ENFORCED:
                return RuleState.POLICY_ENFORCED;
            case POLICY_INEFFECTIVE:
                return RuleState.POLICY_INEFFECTIVE;
            case POLICY_EFFECTIVE:
                return RuleState.POLICY_EFFECTIVE;
            case POLICY_UPDATED:
                return RuleState.POLICY_UPDATED;
            case POLICY_REMOVED:
                return RuleState.POLICY_REMOVED;
            case POLICY_FAILED:
                return RuleState.POLICY_FAILED;
            case POLICY_UNDEFINED:
            case UNRECOGNIZED:
            default:
                return RuleState.POLICY_UNDEFINED;
        }
    }

    public Policy.PolicyRuleState serialize(PolicyRuleState policyRuleState) {
        final var builder = Policy.PolicyRuleState.newBuilder();

        final var ruleState = policyRuleState.getRuleState();

        final var serializedRuleState = serialize(ruleState);

        builder.setPolicyRuleState(serializedRuleState);

        return builder.build();
    }

    public PolicyRuleState deserialize(Policy.PolicyRuleState serializedPolicyRuleState) {
        final var serializedRuleState = serializedPolicyRuleState.getPolicyRuleState();

        final var ruleState = deserialize(serializedRuleState);

        return new PolicyRuleState(ruleState);
    }

    public PolicyCondition.NumericalOperator serialize(NumericalOperator numericalOperator) {
        switch (numericalOperator) {
            case POLICY_RULE_CONDITION_NUMERICAL_EQUAL:
                return PolicyCondition.NumericalOperator.POLICYRULE_CONDITION_NUMERICAL_EQUAL;
            case POLICY_RULE_CONDITION_NUMERICAL_NOT_EQUAL:
                return PolicyCondition.NumericalOperator.POLICYRULE_CONDITION_NUMERICAL_NOT_EQUAL;
            case POLICY_RULE_CONDITION_NUMERICAL_LESS_THAN:
                return PolicyCondition.NumericalOperator.POLICYRULE_CONDITION_NUMERICAL_LESS_THAN;
            case POLICY_RULE_CONDITION_NUMERICAL_LESS_THAN_EQUAL:
                return PolicyCondition.NumericalOperator.POLICYRULE_CONDITION_NUMERICAL_LESS_THAN_EQUAL;
            case POLICY_RULE_CONDITION_NUMERICAL_GREATER_THAN:
                return PolicyCondition.NumericalOperator.POLICYRULE_CONDITION_NUMERICAL_GREATER_THAN;
            case POLICY_RULE_CONDITION_NUMERICAL_GREATER_THAN_EQUAL:
                return PolicyCondition.NumericalOperator.POLICYRULE_CONDITION_NUMERICAL_GREATER_THAN_EQUAL;
            case POLICY_RULE_CONDITION_NUMERICAL_UNDEFINED:
                return PolicyCondition.NumericalOperator.POLICYRULE_CONDITION_NUMERICAL_UNDEFINED;
            default:
                return PolicyCondition.NumericalOperator.UNRECOGNIZED;
        }
    }

    public NumericalOperator deserialize(
            PolicyCondition.NumericalOperator serializedNumericalOperator) {
        switch (serializedNumericalOperator) {
            case POLICYRULE_CONDITION_NUMERICAL_EQUAL:
                return NumericalOperator.POLICY_RULE_CONDITION_NUMERICAL_EQUAL;
            case POLICYRULE_CONDITION_NUMERICAL_NOT_EQUAL:
                return NumericalOperator.POLICY_RULE_CONDITION_NUMERICAL_NOT_EQUAL;
            case POLICYRULE_CONDITION_NUMERICAL_LESS_THAN:
                return NumericalOperator.POLICY_RULE_CONDITION_NUMERICAL_LESS_THAN;
            case POLICYRULE_CONDITION_NUMERICAL_LESS_THAN_EQUAL:
                return NumericalOperator.POLICY_RULE_CONDITION_NUMERICAL_LESS_THAN_EQUAL;
            case POLICYRULE_CONDITION_NUMERICAL_GREATER_THAN:
                return NumericalOperator.POLICY_RULE_CONDITION_NUMERICAL_GREATER_THAN;
            case POLICYRULE_CONDITION_NUMERICAL_GREATER_THAN_EQUAL:
                return NumericalOperator.POLICY_RULE_CONDITION_NUMERICAL_GREATER_THAN_EQUAL;
            case POLICYRULE_CONDITION_NUMERICAL_UNDEFINED:
            case UNRECOGNIZED:
            default:
                return NumericalOperator.POLICY_RULE_CONDITION_NUMERICAL_UNDEFINED;
        }
    }

    public Monitoring.KpiValue serializeStringKpiValue(KpiValue<String> kpiValue) {
        final var builder = Monitoring.KpiValue.newBuilder();

        return builder.setStringVal(kpiValue.getValue()).build();
    }

    public String deserializeStringKpiValue(Monitoring.KpiValue serializedKpiValue) {

        return serializedKpiValue.getStringVal();
    }

    public Monitoring.KpiValue serializeBooleanKpiValue(KpiValue<Boolean> kpiValue) {
        final var builder = Monitoring.KpiValue.newBuilder();

        return builder.setBoolVal(kpiValue.getValue()).build();
    }

    public boolean deserializeBooleanKpiValue(Monitoring.KpiValue serializedKpiValue) {

        return serializedKpiValue.getBoolVal();
    }

    public Monitoring.KpiValue serializeFloatKpiValue(KpiValue<Float> kpiValue) {
        final var builder = Monitoring.KpiValue.newBuilder();

        return builder.setFloatVal(kpiValue.getValue()).build();
    }

    public float deserializeFloatKpiValue(Monitoring.KpiValue serializedKpiValue) {

        return serializedKpiValue.getFloatVal();
    }

    public Monitoring.KpiValue serializeIntegerKpiValue(KpiValue<Integer> kpiValue) {
        final var builder = Monitoring.KpiValue.newBuilder();

        return builder.setIntVal(kpiValue.getValue()).build();
    }

    public int deserializeIntegerKpiValue(Monitoring.KpiValue serializedKpiValue) {

        return serializedKpiValue.getIntVal();
    }

    public Monitoring.KpiValue serialize(KpiValue<?> kpiValue) {
        final var builder = Monitoring.KpiValue.newBuilder();

        if (kpiValue.getValue() instanceof Integer) {
            final var serializedIntegerKpiValue = serializeIntegerKpiValue((KpiValue<Integer>) kpiValue);
            builder.setIntVal(serializedIntegerKpiValue.getIntVal());
        }
        if (kpiValue.getValue() instanceof Float) {
            final var serializedFloatKpiValue = serializeFloatKpiValue((KpiValue<Float>) kpiValue);
            builder.setFloatVal(serializedFloatKpiValue.getFloatVal());
        }
        if (kpiValue.getValue() instanceof String) {
            final var serializedStringKpiValue = serializeStringKpiValue((KpiValue<String>) kpiValue);
            builder.setStringVal(serializedStringKpiValue.getStringVal());
        }
        if (kpiValue.getValue() instanceof Boolean) {
            final var serializedBooleanKpiValue = serializeBooleanKpiValue((KpiValue<Boolean>) kpiValue);
            builder.setBoolVal(serializedBooleanKpiValue.getBoolVal());
        }

        return builder.build();
    }

    public KpiValue deserialize(Monitoring.KpiValue serializedKpiValue) {

        final var typeOfKpiValue = serializedKpiValue.getValueCase();

        switch (typeOfKpiValue) {
            case INTVAL:
                final var intValue = deserializeIntegerKpiValue(serializedKpiValue);
                return new IntegerKpiValue(intValue);
            case BOOLVAL:
                final var booleanValue = deserializeBooleanKpiValue(serializedKpiValue);
                return new BooleanKpiValue(booleanValue);
            case FLOATVAL:
                final var floatValue = deserializeFloatKpiValue(serializedKpiValue);
                return new FloatKpiValue(floatValue);
            case STRINGVAL:
                final var stringValue = deserializeStringKpiValue(serializedKpiValue);
                return new StringKpiValue(stringValue);
            default:
            case VALUE_NOT_SET:
                throw new IllegalStateException("Kpi value not set");
        }
    }

    public Monitoring.KpiValueRange serialize(KpiValueRange kpiValueRange) {
        final var builder = Monitoring.KpiValueRange.newBuilder();

        final var kpiValueMin = kpiValueRange.getKpiMinValue();
        final var kpiValueMax = kpiValueRange.getKpiMaxValue();

        final var serializedKpiValueMin = serialize(kpiValueMin);
        final var serializedKpiValueMax = serialize(kpiValueMax);

        builder.setKpiMinValue(serializedKpiValueMin);
        builder.setKpiMaxValue(serializedKpiValueMax);

        return builder.build();
    }

    public KpiValueRange deserialize(Monitoring.KpiValueRange serializedKpiValueRange) {
        final var serializedMinKpiValue = serializedKpiValueRange.getKpiMinValue();
        final var serializedMaxKpiValue = serializedKpiValueRange.getKpiMaxValue();

        final var minKpiValue = deserialize(serializedMinKpiValue);
        final var maxKpiValue = deserialize(serializedMaxKpiValue);

        return new KpiValueRange(minKpiValue, maxKpiValue);
    }

    public Monitoring.AlarmDescriptor serialize(AlarmDescriptor alarmDescriptor) {
        final var builder = Monitoring.AlarmDescriptor.newBuilder();

        final var alarmDescription = alarmDescriptor.getAlarmDescription();
        final var name = alarmDescriptor.getName();
        final var kpiId = alarmDescriptor.getKpiId();
        final var kpiValueRange = alarmDescriptor.getKpiValueRange();
        final var timestamp = alarmDescriptor.getTimestamp();

        final var serializedKpiIdUuid = serializeUuid(kpiId);
        final var serializedKpiId = KpiId.newBuilder().setKpiId(serializedKpiIdUuid).build();
        final var serializedKpiValueRange = serialize(kpiValueRange);

        builder.setAlarmDescription(alarmDescription);
        builder.setName(name);
        builder.setKpiId(serializedKpiId);
        builder.setKpiValueRange(serializedKpiValueRange);
        builder.setTimestamp(timestamp);

        return builder.build();
    }

    public AlarmDescriptor deserialize(Monitoring.AlarmDescriptor serializedAlarmDescriptor) {

        final var alarmDescription = serializedAlarmDescriptor.getAlarmDescription();
        final var name = serializedAlarmDescriptor.getName();
        final var serializedKpiId = serializedAlarmDescriptor.getKpiId();
        final var serializedKpiValueRange = serializedAlarmDescriptor.getKpiValueRange();
        final var timestamp = serializedAlarmDescriptor.getTimestamp();

        final var kpiId = deserialize(serializedKpiId);
        final var kpiValueRange = deserialize(serializedKpiValueRange);

        return new AlarmDescriptor(alarmDescription, name, kpiId, kpiValueRange, timestamp);
    }

    public Monitoring.AlarmResponse serialize(AlarmResponse alarmResponse) {
        final var builder = Monitoring.AlarmResponse.newBuilder();

        final var alarmId = alarmResponse.getAlarmId();
        final var text = alarmResponse.getText();
        final var kpiValue = alarmResponse.getKpiValue();

        final var serializedAlarmIdUuid = serializeUuid(alarmId);
        final var serializedAlarmId =
                Monitoring.AlarmID.newBuilder().setAlarmId(serializedAlarmIdUuid).build();
        final var serializedKpiValue = serialize(kpiValue);

        builder.setAlarmId(serializedAlarmId);
        builder.setText(text);
        builder.setKpiValue(serializedKpiValue);

        return builder.build();
    }

    public AlarmResponse deserialize(Monitoring.AlarmResponse serializedAlarmResponse) {
        final var serializedAlarmId = serializedAlarmResponse.getAlarmId().getAlarmId();
        final var text = serializedAlarmResponse.getText();
        final var serializedKpiValue = serializedAlarmResponse.getKpiValue();

        final var alarmId = deserialize(serializedAlarmId);
        final var kpiValue = deserialize(serializedKpiValue);

        return new AlarmResponse(alarmId, text, kpiValue);
    }

    public Monitoring.SubsDescriptor serialize(SubsDescriptor subDescriptor) {
        final var builder = Monitoring.SubsDescriptor.newBuilder();

        final var kpiId = subDescriptor.getKpiId();
        final var samplingDurationS = subDescriptor.getSamplingDurationS();
        final var samplingIntervalS = subDescriptor.getSamplingIntervalS();
        final var startDate = subDescriptor.getStartDate();
        final var endDate = subDescriptor.getEndDate();

        final var serializedKpiIdUuid = serializeUuid(kpiId);
        final var serializedKpiId = Monitoring.KpiId.newBuilder().setKpiId(serializedKpiIdUuid).build();

        builder.setKpiId(serializedKpiId);
        builder.setSamplingDurationS(samplingDurationS);
        builder.setSamplingIntervalS(samplingIntervalS);
        builder.setStartDate(startDate);
        builder.setEndDate(endDate);

        return builder.build();
    }

    public SubsDescriptor deserialize(Monitoring.SubsDescriptor serializedSubDescriptor) {
        final var serializedKpiId = serializedSubDescriptor.getKpiId();
        final var samplingDurationS = serializedSubDescriptor.getSamplingDurationS();
        final var samplingIntervalS = serializedSubDescriptor.getSamplingIntervalS();
        final var startDate = serializedSubDescriptor.getStartDate();
        final var endDate = serializedSubDescriptor.getEndDate();

        final var kpiId = deserialize(serializedKpiId);

        return new SubsDescriptor(kpiId, samplingDurationS, samplingIntervalS, startDate, endDate);
    }

    public PolicyCondition.PolicyRuleCondition serialize(PolicyRuleCondition policyRuleCondition) {
        final var builder = PolicyCondition.PolicyRuleCondition.newBuilder();

        final var policyRuleConditionKpiId = policyRuleCondition.getKpiId();
        final var numericalOperator = policyRuleCondition.getNumericalOperator();
        final var policyRuleConditionKpiValue = policyRuleCondition.getKpiValue();

        final var serializedKpiIdUuid = serializeUuid(policyRuleConditionKpiId);
        final var serializedKpiId = KpiId.newBuilder().setKpiId(serializedKpiIdUuid).build();
        final var serializedNumericalOperator = serialize(numericalOperator);
        final var serializedPolicyRuleConditionKpiValue = serialize(policyRuleConditionKpiValue);

        builder.setKpiId(serializedKpiId);
        builder.setNumericalOperator(serializedNumericalOperator);
        builder.setKpiValue(serializedPolicyRuleConditionKpiValue);

        return builder.build();
    }

    public PolicyRuleCondition deserialize(
            PolicyCondition.PolicyRuleCondition serializedPolicyRuleCondition) {

        final var serializedPolicyRuleConditionKpiId =
                serializedPolicyRuleCondition.getKpiId().getKpiId();
        final var serializedNumericalOperator = serializedPolicyRuleCondition.getNumericalOperator();
        final var serializedPolicyRuleConditionKpiValue = serializedPolicyRuleCondition.getKpiValue();

        final var policyRuleConditionKpiId = deserialize(serializedPolicyRuleConditionKpiId);
        final var numericalOperator = deserialize(serializedNumericalOperator);
        final var policyRuleConditionKpiValue = deserialize(serializedPolicyRuleConditionKpiValue);

        return new PolicyRuleCondition(
                policyRuleConditionKpiId, numericalOperator, policyRuleConditionKpiValue);
    }

    public PolicyAction.PolicyRuleActionEnum serialize(PolicyRuleActionEnum policyRuleActionEnum) {
        switch (policyRuleActionEnum) {
            case POLICY_RULE_ACTION_SET_DEVICE_STATUS:
                return PolicyAction.PolicyRuleActionEnum.POLICYRULE_ACTION_SET_DEVICE_STATUS;
            case POLICY_RULE_ACTION_ADD_SERVICE_CONFIGRULE:
                return PolicyAction.PolicyRuleActionEnum.POLICYRULE_ACTION_ADD_SERVICE_CONFIGRULE;
            case POLICY_RULE_ACTION_ADD_SERVICE_CONSTRAINT:
                return PolicyAction.PolicyRuleActionEnum.POLICYRULE_ACTION_ADD_SERVICE_CONSTRAINT;
            case POLICY_RULE_ACTION_NO_ACTION:
                return PolicyAction.PolicyRuleActionEnum.POLICYRULE_ACTION_NO_ACTION;
            default:
                return PolicyAction.PolicyRuleActionEnum.UNRECOGNIZED;
        }
    }

    public PolicyRuleActionEnum deserialize(
            PolicyAction.PolicyRuleActionEnum serializePolicyRuleActionEnum) {
        switch (serializePolicyRuleActionEnum) {
            case POLICYRULE_ACTION_SET_DEVICE_STATUS:
                return PolicyRuleActionEnum.POLICY_RULE_ACTION_SET_DEVICE_STATUS;
            case POLICYRULE_ACTION_ADD_SERVICE_CONFIGRULE:
                return PolicyRuleActionEnum.POLICY_RULE_ACTION_ADD_SERVICE_CONFIGRULE;
            case POLICYRULE_ACTION_ADD_SERVICE_CONSTRAINT:
                return PolicyRuleActionEnum.POLICY_RULE_ACTION_ADD_SERVICE_CONSTRAINT;
            case POLICYRULE_ACTION_NO_ACTION:
            case UNRECOGNIZED:
            default:
                return PolicyRuleActionEnum.POLICY_RULE_ACTION_NO_ACTION;
        }
    }

    public PolicyAction.PolicyRuleAction serialize(PolicyRuleAction policyRuleAction) {
        final var builder = PolicyAction.PolicyRuleAction.newBuilder();

        final var policyRuleActionEnum = policyRuleAction.getPolicyRuleActionEnum();
        final var policyRuleActionParameters = policyRuleAction.getPolicyRuleActionParameters();

        final var serializedPolicyRuleActionEnum = serialize(policyRuleActionEnum);

        builder.setAction(serializedPolicyRuleActionEnum);
        builder.addAllParameters(policyRuleActionParameters);

        return builder.build();
    }

    public PolicyRuleAction deserialize(PolicyAction.PolicyRuleAction serializedPolicyRuleAction) {
        final var serializedPolicyRuleActionEnum = serializedPolicyRuleAction.getAction();
        final var policyRuleActionParameters = serializedPolicyRuleAction.getParametersList();

        final var policyRuleActionEnum = deserialize(serializedPolicyRuleActionEnum);

        return new PolicyRuleAction(policyRuleActionEnum, policyRuleActionParameters);
    }

    public PolicyCondition.BooleanOperator serialize(BooleanOperator booleanOperator) {
        switch (booleanOperator) {
            case POLICYRULE_CONDITION_BOOLEAN_AND:
                return PolicyCondition.BooleanOperator.POLICYRULE_CONDITION_BOOLEAN_AND;
            case POLICYRULE_CONDITION_BOOLEAN_OR:
                return PolicyCondition.BooleanOperator.POLICYRULE_CONDITION_BOOLEAN_OR;
            case POLICYRULE_CONDITION_BOOLEAN_UNDEFINED:
                return PolicyCondition.BooleanOperator.POLICYRULE_CONDITION_BOOLEAN_UNDEFINED;
            default:
                return PolicyCondition.BooleanOperator.UNRECOGNIZED;
        }
    }

    public BooleanOperator deserialize(PolicyCondition.BooleanOperator serializedBooleanOperator) {
        switch (serializedBooleanOperator) {
            case POLICYRULE_CONDITION_BOOLEAN_OR:
                return BooleanOperator.POLICYRULE_CONDITION_BOOLEAN_OR;
            case POLICYRULE_CONDITION_BOOLEAN_AND:
                return BooleanOperator.POLICYRULE_CONDITION_BOOLEAN_AND;
            case POLICYRULE_CONDITION_BOOLEAN_UNDEFINED:
            case UNRECOGNIZED:
            default:
                return BooleanOperator.POLICYRULE_CONDITION_BOOLEAN_UNDEFINED;
        }
    }

    public Policy.PolicyRuleBasic serialize(PolicyRuleBasic policyRuleBasic) {
        final var builder = Policy.PolicyRuleBasic.newBuilder();

        final var policyRuleId = policyRuleBasic.getPolicyRuleId();
        final var policyRuleState = policyRuleBasic.getPolicyRuleState();
        final var priority = policyRuleBasic.getPriority();
        final var policyRuleConditions = policyRuleBasic.getPolicyRuleConditions();
        final var booleanOperator = policyRuleBasic.getBooleanOperator();
        final var policyRuleActions = policyRuleBasic.getPolicyRuleActions();

        final var serializedPolicyRuleId = serializePolicyRuleId(policyRuleId);
        final var serializedPolicyRuleState = serialize(policyRuleState);
        final var serializedPolicyRuleConditions =
                policyRuleConditions.stream().map(this::serialize).collect(Collectors.toList());
        final var serializedBooleanOperator = serialize(booleanOperator);
        final var serializedPolicyRuleActions =
                policyRuleActions.stream().map(this::serialize).collect(Collectors.toList());

        builder.setPolicyRuleId(serializedPolicyRuleId);
        builder.setPolicyRuleState(serializedPolicyRuleState);
        builder.setPriority(priority);
        builder.addAllConditionList(serializedPolicyRuleConditions);
        builder.setBooleanOperator(serializedBooleanOperator);
        builder.addAllActionList(serializedPolicyRuleActions);

        return builder.build();
    }

    public PolicyRuleBasic deserialize(Policy.PolicyRuleBasic serializedPolicyRuleBasic) {
        final var serializedPolicyRuleId = serializedPolicyRuleBasic.getPolicyRuleId();
        final var serializedPolicyRuleState = serializedPolicyRuleBasic.getPolicyRuleState();
        final var priority = serializedPolicyRuleBasic.getPriority();
        final var serializedPolicyRuleConditions = serializedPolicyRuleBasic.getConditionListList();
        final var serializedBooleanOperator = serializedPolicyRuleBasic.getBooleanOperator();
        final var serializedPolicyRuleActions = serializedPolicyRuleBasic.getActionListList();

        final var policyRuleId = deserialize(serializedPolicyRuleId);
        final var policyRuleState = deserialize(serializedPolicyRuleState);
        final var policyRuleConditions =
                serializedPolicyRuleConditions.stream().map(this::deserialize).collect(Collectors.toList());
        final var booleanOperator = deserialize(serializedBooleanOperator);
        final var policyRuleActions =
                serializedPolicyRuleActions.stream().map(this::deserialize).collect(Collectors.toList());

        return new PolicyRuleBasic(
                policyRuleId,
                policyRuleState,
                priority,
                policyRuleConditions,
                booleanOperator,
                policyRuleActions);
    }

    public Policy.PolicyRuleService serialize(PolicyRuleService policyRuleService) {
        final var builder = Policy.PolicyRuleService.newBuilder();

        final var policyRuleBasic = policyRuleService.getPolicyRuleBasic();
        final var policyRuleServiceId = policyRuleService.getServiceId();
        final var policyRuleDeviceIds = policyRuleService.getDeviceIds();

        final var serializedPolicyRuleBasic = serialize(policyRuleBasic);
        final var serializedPolicyRuleServiceId = serialize(policyRuleServiceId);
        final var serializedPolicyRuleDeviceIds =
                policyRuleDeviceIds.stream().map(this::serializeDeviceId).collect(Collectors.toList());

        builder.setPolicyRuleBasic(serializedPolicyRuleBasic);
        builder.setServiceId(serializedPolicyRuleServiceId);
        builder.addAllDeviceList(serializedPolicyRuleDeviceIds);

        return builder.build();
    }

    public PolicyRuleService deserialize(Policy.PolicyRuleService serializedPolicyRuleService) {
        final var serializedPolicyRuleBasic = serializedPolicyRuleService.getPolicyRuleBasic();
        final var serializedPolicyRuleServiceId = serializedPolicyRuleService.getServiceId();
        final var serializedPolicyRuleDeviceIds = serializedPolicyRuleService.getDeviceListList();

        final var policyRuleBasic = deserialize(serializedPolicyRuleBasic);
        final var policyRuleServiceId = deserialize(serializedPolicyRuleServiceId);
        final var policyRuleDeviceIds =
                serializedPolicyRuleDeviceIds.stream().map(this::deserialize).collect(Collectors.toList());

        return new PolicyRuleService(policyRuleBasic, policyRuleServiceId, policyRuleDeviceIds);
    }

    public Policy.PolicyRuleDevice serialize(PolicyRuleDevice policyRuleDevice) {
        final var builder = Policy.PolicyRuleDevice.newBuilder();

        final var policyRuleBasic = policyRuleDevice.getPolicyRuleBasic();
        final var policyRuleDeviceIds = policyRuleDevice.getDeviceIds();

        final var serializedPolicyRuleBasic = serialize(policyRuleBasic);
        final var serializedPolicyRuleDeviceIds =
                policyRuleDeviceIds.stream().map(this::serializeDeviceId).collect(Collectors.toList());

        builder.setPolicyRuleBasic(serializedPolicyRuleBasic);
        builder.addAllDeviceList(serializedPolicyRuleDeviceIds);

        return builder.build();
    }

    public PolicyRuleDevice deserialize(Policy.PolicyRuleDevice serializedPolicyRuleDevice) {
        final var serializedPolicyRuleBasic = serializedPolicyRuleDevice.getPolicyRuleBasic();
        final var serializedPolicyRuleDeviceIds = serializedPolicyRuleDevice.getDeviceListList();

        final var policyRuleBasic = deserialize(serializedPolicyRuleBasic);
        final var policyRuleDeviceIds =
                serializedPolicyRuleDeviceIds.stream().map(this::deserialize).collect(Collectors.toList());

        return new PolicyRuleDevice(policyRuleBasic, policyRuleDeviceIds);
    }

    public KpiId serializeKpiId(String kpiId) {
        final var builder = Monitoring.KpiId.newBuilder();

        final var serializedKpiIdUuid = serializeUuid(kpiId);
        builder.setKpiId(serializedKpiIdUuid);

        return builder.build();
    }

    public String deserialize(KpiId serializedKpiId) {
        final var serializedKpiIdUuid = serializedKpiId.getKpiId();

        return deserialize(serializedKpiIdUuid);
    }

    public Monitoring.Kpi serialize(Kpi kpi) {
        final var builder = Monitoring.Kpi.newBuilder();

        final var kpiId = kpi.getKpiId();
        final var timestamp = kpi.getTimestamp();
        final var kpiValue = kpi.getKpiValue();

        final var serializedKpiId = serializeKpiId(kpiId);
        final var serializedKpiValue = serialize(kpiValue);

        builder.setKpiId(serializedKpiId);
        builder.setTimestamp(timestamp);
        builder.setKpiValue(serializedKpiValue);

        return builder.build();
    }

    public Kpi deserialize(Monitoring.Kpi serializedKpi) {

        final var serializedKpiId = serializedKpi.getKpiId();
        final var timestamp = serializedKpi.getTimestamp();
        final var serializedKpiValue = serializedKpi.getKpiValue();

        final var kpiId = deserialize(serializedKpiId);
        final var kpiValue = deserialize(serializedKpiValue);

        return new Kpi(kpiId, timestamp, kpiValue);
    }

    public Monitoring.KpiDescriptor serialize(KpiDescriptor kpiDescriptor) {
        final var builder = Monitoring.KpiDescriptor.newBuilder();

        final var kpiDescriptorDescription = kpiDescriptor.getKpiDescription();
        final var kpiDescriptorKpiSampleType = kpiDescriptor.getKpiSampleType();
        final var kpiDescriptorDeviceId = kpiDescriptor.getDeviceId();
        final var kpiDescriptorEndPointId = kpiDescriptor.getEndPointId();
        final var kpiDescriptorServiceId = kpiDescriptor.getServiceId();
        final var kpiDescriptorSliceId = kpiDescriptor.getSliceId();

        final var serializedKpiDescriptorKpiSampleType = serialize(kpiDescriptorKpiSampleType);
        final var serializedKpiDescriptorDeviceId = serializeDeviceId(kpiDescriptorDeviceId);
        final var serializedKpiDescriptorEndPointId = serialize(kpiDescriptorEndPointId);
        final var serializedKpiDescriptorServiceId = serialize(kpiDescriptorServiceId);
        final var serializedKpiDescriptorSliceId = serialize(kpiDescriptorSliceId);

        builder.setKpiDescription(kpiDescriptorDescription);
        builder.setKpiSampleType(serializedKpiDescriptorKpiSampleType);
        builder.setDeviceId(serializedKpiDescriptorDeviceId);
        builder.setEndpointId(serializedKpiDescriptorEndPointId);
        builder.setServiceId(serializedKpiDescriptorServiceId);
        builder.setSliceId(serializedKpiDescriptorSliceId);

        return builder.build();
    }

    public KpiDescriptor deserialize(Monitoring.KpiDescriptor serializedKpiDescriptor) {

        final var serializedKpiDescriptorDescription = serializedKpiDescriptor.getKpiDescription();
        final var serializedKpiDescriptorKpiSampleType = serializedKpiDescriptor.getKpiSampleType();
        final var serializedKpiDescriptorDeviceId = serializedKpiDescriptor.getDeviceId();
        final var serializedKpiDescriptorEndPointId = serializedKpiDescriptor.getEndpointId();
        final var serializedKpiDescriptorServiceId = serializedKpiDescriptor.getServiceId();
        final var serializedKpiDescriptorSLiceId = serializedKpiDescriptor.getSliceId();

        final var kpiSampleType = deserialize(serializedKpiDescriptorKpiSampleType);
        final var deviceId = deserialize(serializedKpiDescriptorDeviceId);
        final var endPointId = deserialize(serializedKpiDescriptorEndPointId);
        final var serviceId = deserialize(serializedKpiDescriptorServiceId);
        final var sliceId = deserialize(serializedKpiDescriptorSLiceId);

        return new KpiDescriptor(
                serializedKpiDescriptorDescription,
                kpiSampleType,
                deviceId,
                endPointId,
                serviceId,
                sliceId);
    }

    public ContextOuterClass.DeviceConfig serialize(DeviceConfig deviceConfig) {
        final var builder = ContextOuterClass.DeviceConfig.newBuilder();

        final var serializedConfigRules =
                deviceConfig.getConfigRules().stream().map(this::serialize).collect(Collectors.toList());
        builder.addAllConfigRules(serializedConfigRules);

        return builder.build();
    }

    public DeviceConfig deserialize(ContextOuterClass.DeviceConfig deviceConfig) {
        final var configRules =
                deviceConfig.getConfigRulesList().stream()
                        .map(this::deserialize)
                        .collect(Collectors.toList());

        return new DeviceConfig(configRules);
    }

    public ContextOuterClass.DeviceOperationalStatusEnum serialize(DeviceOperationalStatus opStatus) {
        switch (opStatus) {
            case ENABLED:
                return DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED;
            case DISABLED:
                return DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_DISABLED;
            case UNDEFINED:
            default:
                return DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_UNDEFINED;
        }
    }

    public DeviceOperationalStatus deserialize(
            ContextOuterClass.DeviceOperationalStatusEnum opStatus) {
        switch (opStatus) {
            case DEVICEOPERATIONALSTATUS_ENABLED:
                return DeviceOperationalStatus.ENABLED;
            case DEVICEOPERATIONALSTATUS_DISABLED:
                return DeviceOperationalStatus.DISABLED;
            case DEVICEOPERATIONALSTATUS_UNDEFINED:
            case UNRECOGNIZED:
            default:
                return DeviceOperationalStatus.UNDEFINED;
        }
    }

    public ContextOuterClass.DeviceDriverEnum serialize(DeviceDriverEnum deviceDriverEnum) {
        switch (deviceDriverEnum) {
            case OPENCONFIG:
                return ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG;
            case TRANSPORT_API:
                return ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_TRANSPORT_API;
            case P4:
                return ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_P4;
            case IETF_NETWORK_TOPOLOGY:
                return ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_IETF_NETWORK_TOPOLOGY;
            case ONF_TR_352:
                return ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_ONF_TR_352;
            case UNDEFINED:
            default:
                return ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_UNDEFINED;
        }
    }

    public DeviceDriverEnum deserialize(
            ContextOuterClass.DeviceDriverEnum serializedDeviceDriverEnum) {
        switch (serializedDeviceDriverEnum) {
            case DEVICEDRIVER_OPENCONFIG:
                return DeviceDriverEnum.OPENCONFIG;
            case DEVICEDRIVER_TRANSPORT_API:
                return DeviceDriverEnum.TRANSPORT_API;
            case DEVICEDRIVER_P4:
                return DeviceDriverEnum.P4;
            case DEVICEDRIVER_IETF_NETWORK_TOPOLOGY:
                return DeviceDriverEnum.IETF_NETWORK_TOPOLOGY;
            case DEVICEDRIVER_ONF_TR_352:
                return DeviceDriverEnum.ONF_TR_352;
            case DEVICEDRIVER_UNDEFINED:
            case UNRECOGNIZED:
            default:
                return DeviceDriverEnum.UNDEFINED;
        }
    }

    public ContextOuterClass.EndPoint serialize(EndPoint endPoint) {
        final var builder = ContextOuterClass.EndPoint.newBuilder();

        final var endPointId = endPoint.getEndPointId();
        final var endPointType = endPoint.getEndPointType();
        final var kpiSampleTypes = endPoint.getKpiSampleTypes();
        final var endPointLocation = endPoint.getEndPointLocation();

        final var serializedEndPointId = serialize(endPointId);
        final var serializedKpiSampleTypes =
                kpiSampleTypes.stream().map(this::serialize).collect(Collectors.toList());
        final var serializedEndPointLocation = serialize(endPointLocation);

        builder.setEndpointId(serializedEndPointId);
        builder.setEndpointType(endPointType);
        builder.addAllKpiSampleTypes(serializedKpiSampleTypes);
        builder.setEndpointLocation(serializedEndPointLocation);

        return builder.build();
    }

    public EndPoint deserialize(ContextOuterClass.EndPoint serializedEndPoint) {
        final var serializedEndPointId = serializedEndPoint.getEndpointId();
        final var endPointType = serializedEndPoint.getEndpointType();
        final var serializedKpiSampleTypes = serializedEndPoint.getKpiSampleTypesList();
        final var serializedEndPointLocation = serializedEndPoint.getEndpointLocation();

        final var endPointId = deserialize(serializedEndPointId);
        final var kpiSampleTypes =
                serializedKpiSampleTypes.stream().map(this::deserialize).collect(Collectors.toList());
        final var endPointLocation = deserialize(serializedEndPointLocation);

        return new EndPoint(endPointId, endPointType, kpiSampleTypes, endPointLocation);
    }

    public ContextOuterClass.Device serialize(Device device) {
        final var builder = ContextOuterClass.Device.newBuilder();

        final var deviceIdUuid = serializeUuid(device.getDeviceId());
        final var deviceId = DeviceId.newBuilder().setDeviceUuid(deviceIdUuid);
        final var deviceType = device.getDeviceType();
        final var deviceConfig = device.getDeviceConfig();
        final var deviceOperationalStatus = device.getDeviceOperationalStatus();
        final var deviceDrivers = device.getDeviceDrivers();
        final var deviceEndPoints = device.getEndPoints();

        final var serializedDeviceConfig = serialize(deviceConfig);
        final var serializedDeviceOperationalStatus = serialize(deviceOperationalStatus);
        final var serializedDeviceDrivers =
                deviceDrivers.stream().map(this::serialize).collect(Collectors.toList());
        final var serializedDeviceEndPoints =
                deviceEndPoints.stream().map(this::serialize).collect(Collectors.toList());

        builder.setDeviceId(deviceId);
        builder.setDeviceType(deviceType);
        builder.setDeviceConfig(serializedDeviceConfig);
        builder.setDeviceOperationalStatus(serializedDeviceOperationalStatus);
        builder.addAllDeviceDrivers(serializedDeviceDrivers);
        builder.addAllDeviceEndpoints(serializedDeviceEndPoints);

        return builder.build();
    }

    public Device deserialize(ContextOuterClass.Device device) {

        final var serializedDeviceId = device.getDeviceId();
        final var deviceType = device.getDeviceType();
        final var serializedDeviceConfig = device.getDeviceConfig();
        final var serializedDeviceOperationalStatus = device.getDeviceOperationalStatus();
        final var serializedDeviceDrivers = device.getDeviceDriversList();
        final var serializedDeviceEndPoints = device.getDeviceEndpointsList();

        final var deviceId = deserialize(serializedDeviceId);
        final var deviceConfig = deserialize(serializedDeviceConfig);
        final var deviceOperationalStatus = deserialize(serializedDeviceOperationalStatus);
        final var deviceDrivers =
                serializedDeviceDrivers.stream().map(this::deserialize).collect(Collectors.toList());
        final var deviceEndPoints =
                serializedDeviceEndPoints.stream().map(this::deserialize).collect(Collectors.toList());

        return new Device(
                deviceId,
                deviceType,
                deviceConfig,
                deviceOperationalStatus,
                deviceDrivers,
                deviceEndPoints);
    }

    public Uuid serializeUuid(String uuid) {
        return Uuid.newBuilder().setUuid(uuid).build();
    }

    public String deserialize(Uuid uuid) {
        return uuid.getUuid();
    }
}
