public void Ret(OrgFunctionData orgFunction, UpdateIndicator userIndicator, UpdateIndicator unitIndicator, UpdateIndicator taskIndicator)
        {
            log.Debug("Attempting Ret on OrganisationFunction with uuid " + orgFunction.Uuid);

            RegistreringType1 registration = GetLatestRegistration(orgFunction.Uuid);

            if (registration == null)
            {
                log.Debug("Cannot call Ret on OrganisationFunktion with uuid " + orgFunction.Uuid + " because it does not exist in Organisation");
                return;
            }

            VirkningType virkning = helper.GetVirkning(orgFunction.Timestamp);

            OrganisationFunktionPortType channel = StubUtil.CreateChannel <OrganisationFunktionPortType>(OrganisationFunktionStubHelper.SERVICE, "Ret", helper.CreatePort());

            try
            {
                bool changes = false;

                RetInputType1 input = new RetInputType1();
                input.UUIDIdentifikator = orgFunction.Uuid;
                input.AttributListe     = registration.AttributListe;
                input.TilstandListe     = registration.TilstandListe;
                input.RelationListe     = registration.RelationListe;

                changes = helper.SetTilstandToActive(virkning, registration, orgFunction.Timestamp) | changes;

                #region Update attributes if needed
                EgenskabType latestProperty = StubUtil.GetLatestProperty(input.AttributListe.Egenskab);
                if (latestProperty == null || latestProperty.FunktionNavn == null ||
                    (orgFunction.Name != null && !latestProperty.FunktionNavn.Equals(orgFunction.Name)) ||
                    (orgFunction.ShortKey != null && !latestProperty.BrugervendtNoegleTekst.Equals(orgFunction.ShortKey)))
                {
                    if (latestProperty == null)
                    {
                        orgFunction.ShortKey = (orgFunction.ShortKey != null) ? orgFunction.ShortKey : IdUtil.GenerateShortKey();

                        // special case where editing a function that has been orphaned, without supplying a name - should never really happen, but the API allows it
                        orgFunction.Name = (orgFunction.Name != null) ? orgFunction.Name : "Unknown Function";
                    }

                    // create a new property
                    EgenskabType newProperty = new EgenskabType();
                    newProperty.Virkning = helper.GetVirkning(orgFunction.Timestamp);
                    newProperty.BrugervendtNoegleTekst = (orgFunction.ShortKey != null) ? orgFunction.ShortKey : latestProperty.BrugervendtNoegleTekst;
                    newProperty.FunktionNavn           = (orgFunction.Name != null) ? orgFunction.Name : latestProperty.FunktionNavn;

                    // create a new set of properties
                    input.AttributListe.Egenskab    = new EgenskabType[1];
                    input.AttributListe.Egenskab[0] = newProperty;

                    changes = true;
                }
                #endregion

                #region update tasks if needed
                if (taskIndicator.Equals(UpdateIndicator.COMPARE))
                {
                    // terminate the Virkning on all address relationships that no longer exists locally
                    changes = StubUtil.TerminateObjectsInOrgNoLongerPresentLocally(input.RelationListe.Opgaver, orgFunction.Tasks, orgFunction.Timestamp, true) || changes;

                    // add references to address objects that are new
                    List <string> taskUuidsToAdd = StubUtil.FindAllObjectsInLocalNotInOrg(input.RelationListe.Opgaver, orgFunction.Tasks, true);

                    if (taskUuidsToAdd.Count > 0)
                    {
                        int size = taskUuidsToAdd.Count + ((input.RelationListe.Opgaver != null) ? input.RelationListe.Opgaver.Length : 0);
                        KlasseFlerRelationType[] newTasks = new KlasseFlerRelationType[size];

                        int i = 0;
                        if (input.RelationListe.Opgaver != null)
                        {
                            foreach (var taskInOrg in input.RelationListe.Opgaver)
                            {
                                newTasks[i++] = taskInOrg;
                            }
                        }

                        foreach (string uuidToAdd in taskUuidsToAdd)
                        {
                            foreach (var taskInLocal in orgFunction.Tasks)
                            {
                                if (taskInLocal.Equals(uuidToAdd))
                                {
                                    KlasseFlerRelationType newTask = helper.CreateOpgaveRelation(uuidToAdd, virkning);
                                    newTasks[i++] = newTask;
                                }
                            }
                        }

                        input.RelationListe.Opgaver = newTasks;
                        changes = true;
                    }
                }
                #endregion

                #region Update TilknyttedeBrugere relationships
                // terminate references
                if (userIndicator.Equals(UpdateIndicator.COMPARE))
                {
                    // terminate the references in Org that no longer exist locally
                    changes = StubUtil.TerminateObjectsInOrgNoLongerPresentLocally(input.RelationListe.TilknyttedeBrugere, orgFunction.Users, orgFunction.Timestamp, false) || changes;
                }
                else if (userIndicator.Equals(UpdateIndicator.REMOVE))
                {
                    changes = TerminateObjectsInOrgThatAreInLocal(input.RelationListe.TilknyttedeBrugere, orgFunction.Users, orgFunction.Timestamp) || changes;
                }

                if (userIndicator.Equals(UpdateIndicator.COMPARE) || userIndicator.Equals(UpdateIndicator.ADD))
                {
                    // get the set of new local objects only
                    List <string> uuidsToAdd = StubUtil.FindAllObjectsInLocalNotInOrg(input.RelationListe.TilknyttedeBrugere, orgFunction.Users, false);

                    // add all the new references
                    if (uuidsToAdd.Count > 0)
                    {
                        int size = uuidsToAdd.Count + ((input.RelationListe.TilknyttedeBrugere != null) ? input.RelationListe.TilknyttedeBrugere.Length : 0);
                        BrugerFlerRelationType[] newUsers = new BrugerFlerRelationType[size];

                        int i = 0;
                        if (input.RelationListe.TilknyttedeBrugere != null)
                        {
                            foreach (var usersInOrg in input.RelationListe.TilknyttedeBrugere)
                            {
                                newUsers[i++] = usersInOrg;
                            }
                        }

                        foreach (string uuidToAdd in uuidsToAdd)
                        {
                            newUsers[i++] = helper.CreateBrugerRelation(uuidToAdd, virkning);
                        }

                        input.RelationListe.TilknyttedeBrugere = newUsers;
                        changes = true;
                    }
                }
                #endregion

                #region Update TilknyttedeEnheder relationships
                // terminate references
                if (unitIndicator.Equals(UpdateIndicator.COMPARE))
                {
                    // terminate the references in Org that no longer exist locally
                    changes = StubUtil.TerminateObjectsInOrgNoLongerPresentLocally(input.RelationListe.TilknyttedeEnheder, orgFunction.OrgUnits, orgFunction.Timestamp, false) || changes;
                }
                else if (unitIndicator.Equals(UpdateIndicator.REMOVE))
                {
                    changes = TerminateObjectsInOrgThatAreInLocal(input.RelationListe.TilknyttedeEnheder, orgFunction.OrgUnits, orgFunction.Timestamp) || changes;
                }

                if (unitIndicator.Equals(UpdateIndicator.COMPARE) || unitIndicator.Equals(UpdateIndicator.ADD))
                {
                    // get the set of new local objects
                    List <string> uuidsToAdd = StubUtil.FindAllObjectsInLocalNotInOrg(input.RelationListe.TilknyttedeEnheder, orgFunction.OrgUnits, false);

                    // add all the new references
                    if (uuidsToAdd.Count > 0)
                    {
                        int size = uuidsToAdd.Count + ((input.RelationListe.TilknyttedeEnheder != null) ? input.RelationListe.TilknyttedeEnheder.Length : 0);
                        OrganisationEnhedFlerRelationType[] newUnits = new OrganisationEnhedFlerRelationType[size];

                        int i = 0;
                        if (input.RelationListe.TilknyttedeEnheder != null)
                        {
                            foreach (var unit in input.RelationListe.TilknyttedeEnheder)
                            {
                                newUnits[i++] = unit;
                            }
                        }

                        foreach (string uuidToAdd in uuidsToAdd)
                        {
                            newUnits[i++] = helper.CreateOrgEnhedRelation(uuidToAdd, virkning);
                        }

                        input.RelationListe.TilknyttedeEnheder = newUnits;
                        changes = true;
                    }
                }
                #endregion

                #region Update organisation relationship
                bool foundExistingValidOrganisationRelation = false;
                if (registration.RelationListe.TilknyttedeOrganisationer != null && registration.RelationListe.TilknyttedeOrganisationer.Length > 0)
                {
                    foreach (OrganisationFlerRelationType orgRelation in registration.RelationListe.TilknyttedeOrganisationer)
                    {
                        // make sure that the pointer is set correctly
                        if (!StubUtil.GetMunicipalityOrganisationUUID().Equals(orgRelation.ReferenceID.Item))
                        {
                            orgRelation.ReferenceID.Item = StubUtil.GetMunicipalityOrganisationUUID();
                            changes = true;
                        }

                        // update the Virkning on the TilknyttedeOrganisationer relationship if needed (undelete feature)
                        object endTime = orgRelation.Virkning.TilTidspunkt.Item;

                        // endTime is bool => ok
                        // endTime is DateTime, but Now is before endTime => ok
                        if (!(endTime is DateTime) || (DateTime.Compare(DateTime.Now, (DateTime)endTime) < 0))
                        {
                            foundExistingValidOrganisationRelation = true;
                        }
                    }
                }

                if (!foundExistingValidOrganisationRelation)
                {
                    helper.AddOrganisationRelation(StubUtil.GetMunicipalityOrganisationUUID(), virkning, registration);
                    changes = true;
                }
                #endregion

                // TODO: addresses are not currently used for functions, this is a left-over from the days of it-systems and JumpUrls
                #region Update Address relationships
                // terminate the Virkning on all address relationships that no longer exists locally
                changes = StubUtil.TerminateObjectsInOrgNoLongerPresentLocally(input.RelationListe.Adresser, orgFunction.Addresses, orgFunction.Timestamp, true) || changes;

                // add references to address objects that are new
                List <string> addressUuidsToAdd = StubUtil.FindAllObjectsInLocalNotInOrg(input.RelationListe.Adresser, orgFunction.Addresses, true);

                if (addressUuidsToAdd.Count > 0)
                {
                    int size = addressUuidsToAdd.Count + ((input.RelationListe.Adresser != null) ? input.RelationListe.Adresser.Length : 0);
                    AdresseFlerRelationType[] newAdresser = new AdresseFlerRelationType[size];

                    int i = 0;
                    if (input.RelationListe.Adresser != null)
                    {
                        foreach (var addressInOrg in input.RelationListe.Adresser)
                        {
                            newAdresser[i++] = addressInOrg;
                        }
                    }

                    foreach (string uuidToAdd in addressUuidsToAdd)
                    {
                        foreach (var addressInLocal in orgFunction.Addresses)
                        {
                            if (addressInLocal.Uuid.Equals(uuidToAdd))
                            {
                                string roleUuid = null;
                                switch (addressInLocal.Type)
                                {
                                case AddressRelationType.URL:
                                    roleUuid = UUIDConstants.ADDRESS_ROLE_ORGFUNCTION_URL;
                                    break;

                                default:
                                    log.Warn("Cannot add relationship to address of type " + addressInLocal.Type + " with uuid " + addressInLocal.Uuid + " as the type is unknown");
                                    continue;
                                }

                                AdresseFlerRelationType newAddress = helper.CreateAddressReference(uuidToAdd, (i + 1), roleUuid, virkning);
                                newAdresser[i++] = newAddress;
                            }
                        }
                    }

                    input.RelationListe.Adresser = newAdresser;
                    changes = true;
                }
                #endregion

                // if no changes are made, we do not call the service
                if (!changes)
                {
                    log.Debug("Ret on OrganisationFunktion with uuid " + orgFunction.Uuid + " cancelled because of no changes");
                    return;
                }

                // send Ret request
                retRequest request = new retRequest();
                request.RetRequest1                  = new RetRequestType();
                request.RetRequest1.RetInput         = input;
                request.RetRequest1.AuthorityContext = new AuthorityContextType();
                request.RetRequest1.AuthorityContext.MunicipalityCVR = OrganisationRegistryProperties.GetMunicipality();

                retResponse response = channel.ret(request);

                int statusCode = Int32.Parse(response.RetResponse1.RetOutput.StandardRetur.StatusKode);
                if (statusCode != 20)
                {
                    string message = StubUtil.ConstructSoapErrorMessage(statusCode, "Ret", OrganisationFunktionStubHelper.SERVICE, response.RetResponse1.RetOutput.StandardRetur.FejlbeskedTekst);
                    log.Error(message);
                    throw new SoapServiceException(message);
                }

                log.Debug("Ret succesful on OrganisationFunktion with uuid " + orgFunction.Uuid);
            }
            catch (Exception ex) when(ex is CommunicationException || ex is IOException || ex is TimeoutException || ex is WebException)
            {
                throw new ServiceNotFoundException("Failed to establish connection to the Ret service on OrganisationFunktion", ex);
            }
        }
 private void EnsureKeys(OrgFunctionData orgFunction)
 {
     orgFunction.Uuid     = (orgFunction.Uuid != null) ? orgFunction.Uuid : IdUtil.GenerateUuid();
     orgFunction.ShortKey = (orgFunction.ShortKey != null) ? orgFunction.ShortKey : IdUtil.GenerateShortKey();
 }
        public void Importer(OrgFunctionData orgFunction)
        {
            // create ShortKey and Uuid if not supplied
            EnsureKeys(orgFunction);

            log.Debug("Attempting Import on OrgFunction with uuid " + orgFunction.Uuid);

            // create timestamp object to be used on all registrations, properties and relations
            VirkningType virkning = helper.GetVirkning(orgFunction.Timestamp);

            // setup registration
            RegistreringType1 registration = helper.CreateRegistration(orgFunction.Timestamp, LivscyklusKodeType.Importeret);

            // add properties
            helper.AddProperties(orgFunction.ShortKey, orgFunction.Name, virkning, registration);

            // add relationships on registration
            helper.AddTilknyttedeBrugere(orgFunction.Users, virkning, registration);
            helper.AddTilknyttedeEnheder(orgFunction.OrgUnits, virkning, registration);
            helper.AddTilknyttedeItSystemer(orgFunction.ItSystems, virkning, registration);
            helper.AddOpgaver(orgFunction.Tasks, virkning, registration);
            helper.AddOrganisationRelation(StubUtil.GetMunicipalityOrganisationUUID(), virkning, registration);
            helper.AddAddressReferences(orgFunction.Addresses, virkning, registration);
            helper.SetFunktionsType(orgFunction.FunctionTypeUuid, virkning, registration);

            // set Tilstand to Active
            helper.SetTilstandToActive(virkning, registration, orgFunction.Timestamp);

            // wire everything together
            OrganisationFunktionType organisationFunktionType = helper.GetOrganisationFunktionType(orgFunction.Uuid, registration);
            ImportInputType          importInput = new ImportInputType();

            importInput.OrganisationFunktion = organisationFunktionType;

            // construct request
            importerRequest request = new importerRequest();

            request.ImporterRequest1                  = new ImporterRequestType();
            request.ImporterRequest1.ImportInput      = importInput;
            request.ImporterRequest1.AuthorityContext = new AuthorityContextType();
            request.ImporterRequest1.AuthorityContext.MunicipalityCVR = OrganisationRegistryProperties.GetMunicipality();

            // send request
            OrganisationFunktionPortType channel = StubUtil.CreateChannel <OrganisationFunktionPortType>(OrganisationFunktionStubHelper.SERVICE, "Import", helper.CreatePort());

            try
            {
                importerResponse result = channel.importer(request);

                int statusCode = Int32.Parse(result.ImporterResponse1.ImportOutput.StandardRetur.StatusKode);
                if (statusCode != 20)
                {
                    string message = StubUtil.ConstructSoapErrorMessage(statusCode, "Import", OrganisationFunktionStubHelper.SERVICE, result.ImporterResponse1.ImportOutput.StandardRetur.FejlbeskedTekst);
                    log.Error(message);
                    throw new SoapServiceException(message);
                }

                log.Debug("Import successful on OrgFunction with uuid " + orgFunction.Uuid);
            }
            catch (Exception ex) when(ex is CommunicationException || ex is IOException || ex is TimeoutException || ex is WebException)
            {
                throw new ServiceNotFoundException("Failed to establish connection to the Importer service on OrganisationFunktion", ex);
            }
        }