private DialogResult ConfirmCascadeDeletion(string message, string messageRelations, GISADataset.NivelRow nivelRow, ref List<string> uaAssociadas, ref List<UnidadesFisicasHelper.UaInfo> uaFrdAssociadas)
		{
            string detalhes = GetUFRelatedDataReport(nivelRow, ref uaAssociadas, ref uaFrdAssociadas);
			DialogResult formResult = 0;
			if (detalhes == null || detalhes.Length == 0)
				formResult = MessageBox.Show(message, "Unidade física", MessageBoxButtons.YesNo);
			else
			{
				FormDeletionReport formReport = new FormDeletionReport();
				formReport.Text = "Unidade física";
				formReport.Interrogacao = messageRelations;
				formReport.Detalhes = detalhes;
				formResult = formReport.ShowDialog();
			}
			return formResult;
		}
        private void RemoveNivel()
        {
            GISATreeNode node = null;
            GISATreeNode parentNode = null;
            GISADataset.NivelRow nUpperRow = null;
            GISADataset.RelacaoHierarquicaRow rhRow = null;
            GISADataset.NivelRow nRow = null;
            var objDigital = default(ObjDigital);
            if (this.nivelNavigator1.PanelToggleState == NivelNavigator.ToggleState.Estrutural)
            {
                if (this.nivelNavigator1.SelectedNode != null)
                {
                    nRow = ((GISATreeNode)this.nivelNavigator1.SelectedNode).NivelRow;
                    rhRow = ((GISATreeNode)this.nivelNavigator1.SelectedNode).RelacaoHierarquicaRow;
                }
                node = (GISATreeNode)this.nivelNavigator1.SelectedNode;
                parentNode = (GISATreeNode)node.Parent;
                nUpperRow = (GISADataset.NivelRow)node.NivelUpperRow;
            }
            else
            {
                nRow = this.nivelNavigator1.SelectedNivel;
                // Verificar se a relacção hierárquica ainda é a mesma apresentada na interface (se o
                // utilizador estiver a ver a lista que contem o nível a apagar e entretanto outro utilizador
                // o ter colocado noutro ponto da árvore, a relação hierárquica presente em memória deixa
                // de corresponder com aquela que é apresentada na interface quando esse nível é selecionado;
                // quando o nível é selecionado a informação no DataSet de trabalho é actualizado mas não
                // actualiza a interface)
                if (GisaDataSetHelper.GetInstance().RelacaoHierarquica.Select(string.Format("ID={0} AND IDUpper={1}", nRow.ID, this.nivelNavigator1.ContextBreadCrumbsPathID)).Length > 0)
                    rhRow = (GISADataset.RelacaoHierarquicaRow)(GisaDataSetHelper.GetInstance().RelacaoHierarquica.Select(string.Format("ID={0} AND IDUpper={1}", nRow.ID, this.nivelNavigator1.ContextBreadCrumbsPathID))[0]);
                else
                {
                    MessageBox.Show("Esta operação não pode ser concluída pelo facto de a localização na estrutura " + System.Environment.NewLine + "do nível selecionado ter sido alterada por outro utilizador.", "Eliminar Nível", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    return;
                }
                nUpperRow = (GISADataset.NivelRow)(GisaDataSetHelper.GetInstance().Nivel.Select(string.Format("ID={0}", this.nivelNavigator1.ContextBreadCrumbsPathID))[0]);

                if (!FedoraHelper.CanDeleteODsAssociated2UI(nRow, out objDigital))
                    return;
            }

            // Não permitir a eliminação de relações entre EPs
            if (TipoNivel.isNivelOrganico(nRow) && TipoNivel.isNivelOrganico(nUpperRow))
            {
                MessageBox.Show("A alteração de relações entre entidades produtoras deverão ser efectuadas através do controlo de autoridade.", "Eliminação de relação", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }

            var assocODs = FedoraHelper.GetAssociatedODsDetailsMsg(nRow.ID);
            if (assocODs.Length > 0)
            {
                FormDeletionReport form = new FormDeletionReport();
                form.Text = "Eliminação de unidade de informação";
                form.Interrogacao = "A unidade de informação selecionada tem objeto(s) digital(ais) associado(s). " + System.Environment.NewLine +
                        "Se eliminar esta unidade de informação, os objeto(s) digital(ais) " + System.Environment.NewLine + " também serão eliminado(s)." + System.Environment.NewLine +
                        "Pretende continuar?";
                form.Detalhes = assocODs;

                if (form.ShowDialog() == DialogResult.Cancel) return;
            }
            else if (MessageBox.Show("Tem a certeza que deseja eliminar o nível selecionado?", "Eliminação de relação", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.Cancel)
                return;

            Trace.WriteLine("A apagar nível...");

            // actualizar objecto digital caso exista
            var preTransactionAction = new PreTransactionAction();
            var fedArgs = new PersistencyHelper.FedoraIngestPreTransactionArguments();
            preTransactionAction.args = fedArgs;

            preTransactionAction.preTransactionDelegate = delegate(PersistencyHelper.PreTransactionArguments preTransactionArgs)
            {
                bool ingestSuccess = true;
                string msg = null;

                var odsToIngest = FedoraHelper.DeleteObjDigital(nRow);
                odsToIngest.ForEach(od => ingestSuccess &= SessionHelper.AppConfiguration.GetCurrentAppconfiguration().FedoraHelperSingleton.Ingest(od, out msg));

                preTransactionArgs.cancelAction = !ingestSuccess;
                preTransactionArgs.message = msg;

            };

            // Se se tratar da relação entre um nível orgânico e uma ED ou GA 
            // ou se se tratar da relação entre um nível documental e um nível 
            // orgânio é necessário proceder de outras formas
            if (TipoNivel.isNivelOrganico(nRow) && TipoNivel.isNivelLogico(nUpperRow))
            {
                if (MessageBox.Show(
                    "Por favor tenha em atenção que a entidade produtora propriamente " + System.Environment.NewLine +
                    "dita não será eliminada, apenas a relação ao nível superior o será.", "Eliminação de relação", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.Cancel)
                    return;

                ((frmMain)TopLevelControl).EnterWaitMode();

                string key = ControloNivelList.getKey(node);
                PersistencyHelper.canDeleteRHRowPreConcArguments args = new PersistencyHelper.canDeleteRHRowPreConcArguments();
                args.nRowID = node.NivelRow.ID;
                args.nUpperRowID = node.NivelUpperRow.ID;
                args.rhRowID = node.RelacaoHierarquicaRow.ID;
                args.rhRowIDUpper = node.RelacaoHierarquicaRow.IDUpper;
                CurrentContext.RaiseRegisterModificationEvent(nRow.GetFRDBaseRows()[0]);
                var successfulSave = PersistencyHelper.save(DelegatesHelper.verifyIfCanDeleteRH, args);
                //tds.Add(GisaDataSetHelper.GetInstance().Tables["RelacaoHierarquica"]);
                PersistencyHelper.cleanDeletedData(PersistencyHelper.determinaNuvem("RelacaoHierarquica"));
                if (args.deleteSuccessful)
                {
                    GISA.Search.Updater.updateProdutor(node.NivelRow.GetNivelControloAutRows()[0].IDControloAut);

                    //Prevenir o beforeNewSelection que o Remove ia desencadear.
                    this.nivelNavigator1.AddHandlers();
                    this.nivelNavigator1.RemoveFromTreeview(node, key);
                    this.nivelNavigator1.RemoveHandlers();
                }
                else
                    MessageBox.Show(args.message, "Eliminação de relação", MessageBoxButtons.OK, MessageBoxIcon.Information);

                ((frmMain)TopLevelControl).LeaveWaitMode();
            }
            else if (TipoNivel.isNivelDocumental(nRow) && TipoNivel.isNivelOrganico(nUpperRow))
            {
                // Verificar que existem várias relações hierárquicas deste 
                // nível documental a entidades produtoras superiores. Nesse 
                // caso deverá ser removida a relação, caso contrário, se não 
                // existirem subníveis documentais, será eliminado o próprio 
                // nível(documental)
                int numRHs = nRow.GetRelacaoHierarquicaRowsByNivelRelacaoHierarquica().Length;
                if (numRHs > 1)
                {
                    if (MessageBox.Show(
                        "Por favor tenha em atenção que são vários os produtores deste " + System.Environment.NewLine +
                        "nível documental. O nível documental propriamente dito não " + System.Environment.NewLine +
                        "será eliminado, apenas a sua relação ao nível orgânico " + System.Environment.NewLine +
                        "superior o será.", "Eliminação de relação", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.Cancel)
                        return;

                    ((frmMain)TopLevelControl).EnterWaitMode();

                    CurrentContext.RaiseRegisterModificationEvent(nRow.GetFRDBaseRows()[0]);

                    PersistencyHelper.canDeleteRHRowPreConcArguments args = new PersistencyHelper.canDeleteRHRowPreConcArguments();
                    args.nRowID = nRow.ID;
                    args.nUpperRowID = nUpperRow.ID;
                    args.rhRowID = rhRow.ID;
                    args.rhRowIDUpper = rhRow.IDUpper;
                    PersistencyHelper.SaveResult successfulSave = PersistencyHelper.save(DelegatesHelper.verifyIfCanDeleteRH, args);
                    PersistencyHelper.cleanDeletedData(PersistencyHelper.determinaNuvem("RelacaoHierarquica"));
                    if (args.deleteSuccessful)
                    {
                        if (successfulSave == PersistencyHelper.SaveResult.successful)
                        {
                            List<string> IDNiveis = new List<string>();
                            IDNiveis.Add(args.nRowID.ToString());
                            GISA.Search.Updater.updateNivelDocumental(IDNiveis);
                            GISA.Search.Updater.updateNivelDocumentalComProdutores(nRow.ID);

                            this.nivelNavigator1.RemoveSelectedLVItem();
                        }
                    }
                    else
                        MessageBox.Show(args.message, "Eliminação de relação", MessageBoxButtons.OK, MessageBoxIcon.Information);

                    ((frmMain)TopLevelControl).LeaveWaitMode();
                }
                else if (numRHs == 1)
                {
                    // Verificar que não existem subníveis documentais
                    int numSubRHs = GisaDataSetHelper.GetInstance().RelacaoHierarquica.Select(string.Format("IDUpper={0}", nRow.ID)).Length;
                    if (numSubRHs > 0)
                    {
                        MessageBox.Show("Só é possível eliminar os níveis que não tenham outros directamente associados", "Eliminação de relação", MessageBoxButtons.OK, MessageBoxIcon.Information);
                        return;
                    }
                    else
                    {
                        if (MessageBox.Show(
                            "Por favor tenha em atenção que este nível documental é produzido" + System.Environment.NewLine +
                            "por apenas uma entidade. Ao remover esta relação será perdida " + System.Environment.NewLine +
                            "não só a relação como o nível documental propriamente dito.", "Eliminação de relação", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.Cancel)
                            return;

                        ((frmMain)TopLevelControl).EnterWaitMode();

                        CurrentContext.RaiseRegisterModificationEvent(nRow.GetFRDBaseRows()[0]);

                        PersistencyHelper.canDeleteRHRowPreConcArguments argsPca = new PersistencyHelper.canDeleteRHRowPreConcArguments();
                        argsPca.nRowID = nRow.ID;
                        argsPca.nUpperRowID = nUpperRow.ID;
                        argsPca.rhRowID = 0;
                        argsPca.rhRowIDUpper = 0;
                        PersistencyHelper.DeleteIDXPreSaveArguments argsPsa = new PersistencyHelper.DeleteIDXPreSaveArguments();
                        argsPsa.ID = nRow.ID;
                        PersistencyHelper.SaveResult successfulSave = PersistencyHelper.save(DelegatesHelper.verifyIfCanDeleteRH, argsPca, Nivel.DeleteNivelXInDataBase, argsPsa, preTransactionAction);
                        if (argsPca.deleteSuccessful)
                        {
                            if (successfulSave == PersistencyHelper.SaveResult.successful)
                            {
                                List<string> IDNiveis = new List<string>();
                                IDNiveis.Add(nRow.ID.ToString());
                                GISA.Search.Updater.updateNivelDocumental(IDNiveis);
                                GISA.Search.Updater.updateNivelDocumentalComProdutores(nRow.ID);

                                this.nivelNavigator1.RemoveSelectedLVItem();
                            }
                        }
                        else
                        {
                            // se o nível a eliminar se tratar de uma série ou documento solto mas que 
                            // por motivos de conflito de concorrência não foi possível executar, 
                            // o refrescamento dos botões é feito tendo como o contexto o próprio
                            // nível que se pretendeu eliminar para desta forma o estado dos mesmos
                            // estar correcta (caso contrário o estado dos botões referir-se-ia a 
                            // não haver qualquer item selecionado
                            MessageBox.Show(argsPca.message, "Eliminação de relação", MessageBoxButtons.OK, MessageBoxIcon.Information);
                            UpdateToolBarButtons(this.nivelNavigator1.SelectedItems[0]);
                        }
                        PersistencyHelper.cleanDeletedData(new List<TableDepthOrdered.TableCloudType>(new TableDepthOrdered.TableCloudType[] { PersistencyHelper.determinaNuvem("RelacaoHierarquica"), PersistencyHelper.determinaNuvem("FRDBase") }));

                        ((frmMain)TopLevelControl).LeaveWaitMode();
                    }
                }
                else
                    Debug.Assert(false, "Should never happen. There must be a relation with an upper Nivel.");
            }
            else
            {
                // Entre todos os outros tipos de nível proceder normalmente
                if (this.nivelNavigator1.PanelToggleState == NivelNavigator.ToggleState.Estrutural)
                {
                    ((frmMain)TopLevelControl).EnterWaitMode();

                    string key = ControloNivelList.getKey(node);
                    PersistencyHelper.canDeleteRHRowPreConcArguments argsPca = new PersistencyHelper.canDeleteRHRowPreConcArguments();
                    argsPca.nRowID = node.NivelRow.ID;
                    //se não se tratar de uma entidade detentora nem de um grupo de arquivos não é necessário criar uma entrada na tabela de controlo de descrição
                    if (node.NivelUpperRow != null && node.NivelRow.IDTipoNivel != TipoNivel.LOGICO)
                    {
                        argsPca.nUpperRowID = node.NivelUpperRow.ID;
                        CurrentContext.RaiseRegisterModificationEvent(nRow.GetFRDBaseRows()[0]);
                    }
                    else
                        argsPca.nUpperRowID = 0;

                    argsPca.rhRowID = 0;
                    argsPca.rhRowIDUpper = 0;
                    PersistencyHelper.DeleteIDXPreSaveArguments argsPsa = new PersistencyHelper.DeleteIDXPreSaveArguments();
                    argsPsa.ID = nRow.ID;
                    PersistencyHelper.save(DelegatesHelper.verifyIfCanDeleteRH, argsPca, Nivel.DeleteNivelXInDataBase, argsPsa);
                    PersistencyHelper.cleanDeletedData(new List<TableDepthOrdered.TableCloudType>(new TableDepthOrdered.TableCloudType[] { PersistencyHelper.determinaNuvem("RelacaoHierarquica"), PersistencyHelper.determinaNuvem("FRDBase") }));
                    if (argsPca.deleteSuccessful)
                        this.nivelNavigator1.RemoveFromTreeview(node, key);
                    else
                        MessageBox.Show(argsPca.message, "Eliminação de relação", MessageBoxButtons.OK, MessageBoxIcon.Information);

                    ((frmMain)TopLevelControl).LeaveWaitMode();
                }
                else
                {
                    if ((nRow.GetRelacaoHierarquicaRowsByNivelRelacaoHierarquica()[0].IDTipoNivelRelacionado == TipoNivelRelacionado.D ||
                        nRow.GetRelacaoHierarquicaRowsByNivelRelacaoHierarquica()[0].IDTipoNivelRelacionado == TipoNivelRelacionado.SD) &&
                        NiveisHelper.NivelFoiMovimentado(nRow.ID))
                    {
                        if (MessageBox.Show(
                                "Por favor tenha em atenção que este nível documental já foi " + System.Environment.NewLine +
                                "requisitado/devolvido. Ao remover nível documental serão perdidos " + System.Environment.NewLine +
                                "todos os seus registos referentes a requisições e devoluções.", "Eliminação de nível documental", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.Cancel)
                            return;
                    }

                    ((frmMain)TopLevelControl).EnterWaitMode();

                    CurrentContext.RaiseRegisterModificationEvent(nRow.GetFRDBaseRows()[0]);

                    PersistencyHelper.canDeleteRHRowPreConcArguments argsPca = new PersistencyHelper.canDeleteRHRowPreConcArguments();
                    argsPca.nRowID = nRow.ID;
                    argsPca.nUpperRowID = nUpperRow.ID;
                    argsPca.rhRowID = 0;
                    argsPca.rhRowIDUpper = 0;
                    PersistencyHelper.DeleteIDXPreSaveArguments argsPsa = new PersistencyHelper.DeleteIDXPreSaveArguments();
                    argsPsa.ID = nRow.ID;
                    PersistencyHelper.SaveResult successfulSave = PersistencyHelper.save(DelegatesHelper.verifyIfCanDeleteRH, argsPca, Nivel.DeleteNivelXInDataBase, argsPsa, preTransactionAction);
                    PersistencyHelper.cleanDeletedData(new List<TableDepthOrdered.TableCloudType>(new TableDepthOrdered.TableCloudType[] { PersistencyHelper.determinaNuvem("RelacaoHierarquica"), PersistencyHelper.determinaNuvem("FRDBase"), PersistencyHelper.determinaNuvem("ObjetoDigital") }));
                    if (argsPca.deleteSuccessful)
                    {
                        if (successfulSave == PersistencyHelper.SaveResult.successful)
                        {
                            List<string> IDNiveis = new List<string>();
                            IDNiveis.Add(argsPsa.ID.ToString());
                            GISA.Search.Updater.updateNivelDocumental(IDNiveis);
                            if (nRow.RowState == DataRowState.Detached)
                                GISA.Search.Updater.updateNivelDocumentalComProdutores(argsPsa.ID);
                            else
                                GISA.Search.Updater.updateNivelDocumentalComProdutores(nRow.ID);

                            this.nivelNavigator1.RemoveSelectedLVItem();
                        }
                    }
                    else
                        MessageBox.Show(argsPca.message, "Eliminação de relação", MessageBoxButtons.OK, MessageBoxIcon.Information);

                    ((frmMain)TopLevelControl).LeaveWaitMode();
                }
            }

            RevalidateClipboardNivelItem();

            if (this.nivelNavigator1.PanelToggleState == NivelNavigator.ToggleState.Estrutural && parentNode != null)
            {
                //remover o nó do controlo embora sem refrescar a interface
                this.nivelNavigator1.SelectParentNode(parentNode);
                UpdateContext();
            }
            else
            {
                //A selecção foi limpa aquando da eliminação do item
                UpdateToolBarButtons();
            }
        }
        private void PasteNivel()
        {
            var sources = mClipboardNivelItems;
            var sourceRows = sources.Select(r => r.NivelRowByNivelRelacaoHierarquica).ToList();
            var sourceIDs = sourceRows.Select(r => r.ID).ToList();
            var targetRow =
                this.nivelNavigator1.PanelToggleState == NivelNavigator.ToggleState.Estrutural ?
                ((GISATreeNode)this.nivelNavigator1.SelectedNode).NivelRow :
                GisaDataSetHelper.GetInstance().Nivel.Cast<GISADataset.NivelRow>().Single(r => r.ID == this.nivelNavigator1.ContextBreadCrumbsPathID);

            var ho = new GisaDataSetHelper.HoldOpen(GisaDataSetHelper.GetConnection());
            try
            {
                // carregar todas as relações hierárquicas dos niveis cortados
                DBAbstractDataLayer.DataAccessRules.NivelRule.Current.LoadNivelRelacoesHierarquicas(GisaDataSetHelper.GetInstance(), sourceIDs, ho.Connection);
                // carregar toda a informação sobre permissões dos niveis cortados e do seu parent
                DBAbstractDataLayer.DataAccessRules.PermissoesRule.Current.LoadDataCIPermissoes(GisaDataSetHelper.GetInstance(), sourceIDs, ho.Connection);
                DBAbstractDataLayer.DataAccessRules.PermissoesRule.Current.LoadDataCIPermissoes(GisaDataSetHelper.GetInstance(), targetRow.ID, ho.Connection);
                // carregar toda a informação referente aos objetos digitais dos niveis cortados, do seu upper e do nível de destino
                if (SessionHelper.AppConfiguration.GetCurrentAppconfiguration().IsFedoraEnable())
                {
                    var idTipoNivelRelacionado = sources.First().IDTipoNivelRelacionado;
                    if (idTipoNivelRelacionado == TipoNivelRelacionado.SD) // se os documentos cortados forem subdocumentos, então basta passar o nivel do pai que os subdocumentos são tb carregados
                        DBAbstractDataLayer.DataAccessRules.FedoraRule.Current.LoadObjDigitalData(GisaDataSetHelper.GetInstance(), sources.First().IDUpper, TipoNivelRelacionado.D, ho.Connection);
                    else
                        sourceIDs.ForEach(ID => DBAbstractDataLayer.DataAccessRules.FedoraRule.Current.LoadObjDigitalData(GisaDataSetHelper.GetInstance(), ID, idTipoNivelRelacionado, ho.Connection));

                    DBAbstractDataLayer.DataAccessRules.FedoraRule.Current.LoadObjDigitalData(GisaDataSetHelper.GetInstance(), targetRow.ID, targetRow.GetRelacaoHierarquicaRowsByNivelRelacaoHierarquica().First().IDTipoNivelRelacionado, ho.Connection);
                }
            }
            catch (Exception ex) { Trace.WriteLine(ex.ToString()); throw ex; }
            finally
            {
                ho.Dispose();
            }

            // verificar se o nivel cortado for um documento solto com vários produtores e se vai ser colado debaixo de uma série ou subsérie
            var docsSoltos = new StringBuilder();
            sourceRows.ForEach(sourceRow =>
            {
                var rhRows = sourceRow.GetRelacaoHierarquicaRowsByNivelRelacaoHierarquica();
                var isDocumentoSolto = sourceRow.IDTipoNivel == TipoNivel.DOCUMENTAL && rhRows[0].NivelRowByNivelRelacaoHierarquicaUpper.IDTipoNivel == TipoNivel.ESTRUTURAL;

                if (isDocumentoSolto && rhRows.Count() > 1)
                    docsSoltos.Append(sourceRow.GetNivelDesignadoRows()[0].Designacao + System.Environment.NewLine);
            }
            );

            if (docsSoltos.Length > 0)
            {
                var formReport = new FormDeletionReport();
                formReport.Text = "Mover nível";
                formReport.Interrogacao = "As seguintes unidades informacionais recortadas têm mais do que um produtor." + System.Environment.NewLine +
                                "Ao completar esta operação irá perder todas as relações destes níveis com os respetivos produtores." + System.Environment.NewLine +
                                "Pretende continuar?";
                formReport.Detalhes = docsSoltos.ToString();
                var formResult = formReport.ShowDialog();

                if (formResult == DialogResult.Cancel) return;
            }

            try
            {
                Trace.WriteLine("A colar níveis...");

                var argsPc = new PersistencyHelper.LstPasteRhXPreConcArguments();
                argsPc.pasteRhXPreConcArguments = new List<PersistencyHelper.PasteRhXPreConcArguments>();
                argsPc.IDTipoNivelRelacionado = sources.First().IDTipoNivelRelacionado;
                //var argsPs = new PersistencyHelper.LstPasteRhXPreSaveArguments();
                //argsPs.lstPasteRhXPreSaveArguments = new List<PersistencyHelper.PasteRhXPreSaveArguments>();
                //argsPs.IDTipoNivelRelacionado = sources.First().IDTipoNivelRelacionado;

                // Garantir que não exista ainda a relação que se pretende criar.
                // Essa situação pode existir por exemplo no caso de uma série 
                // contínua em que se tente mover uma das relações para os mesmos 
                // dois nós já afectados pela outra relação.
                sourceRows.Select(r => r.GetRelacaoHierarquicaRowsByNivelRelacaoHierarquica()[0])
                    .Where(r => r.IDUpper != targetRow.ID)
                    .Select(r => r.NivelRowByNivelRelacaoHierarquica).ToList()
                    .ForEach(sourceRow =>
                    {
                        // Actualizar localização do nível colado
                        var rhRow = sourceRow.GetRelacaoHierarquicaRowsByNivelRelacaoHierarquica()[0];
                        var newrhRow = GisaDataSetHelper.GetInstance().RelacaoHierarquica.NewRelacaoHierarquicaRow();
                        newrhRow.ID = rhRow.ID;
                        newrhRow.IDUpper = targetRow.ID;
                        newrhRow.IDTipoNivelRelacionado = rhRow.IDTipoNivelRelacionado;

                        var oldParent = rhRow.NivelRowByNivelRelacaoHierarquicaUpper;
                        var newParent = newrhRow.NivelRowByNivelRelacaoHierarquicaUpper;
                        if (oldParent.IDTipoNivel == TipoNivel.DOCUMENTAL && newParent.IDTipoNivel == TipoNivel.ESTRUTURAL)
                            PermissoesHelper.AddNewNivelGrantPermissions(sourceRow);
                        else if (oldParent.IDTipoNivel == TipoNivel.ESTRUTURAL && newParent.IDTipoNivel == TipoNivel.DOCUMENTAL)
                            PermissoesHelper.UndoAddNivelGrantPermissions(sourceRow, PermissoesHelper.GrpAcessoCompleto);

                        var aPc = new PersistencyHelper.PasteRhXPreConcArguments();
                        aPc.rhRowOldID = rhRow.ID;
                        aPc.rhRowOldIDUpper = rhRow.IDUpper;
                        aPc.rhRowNew = newrhRow;
                        aPc.nivel = targetRow;
                        aPc.ensureUniqueCodigoArgs = new PersistencyHelper.EnsureUniqueCodigoNivelPreConcArguments();
                        aPc.ensureUniqueCodigoArgs.nRowID = newrhRow.NivelRowByNivelRelacaoHierarquica.ID;
                        aPc.ensureUniqueCodigoArgs.ndRowID = newrhRow.NivelRowByNivelRelacaoHierarquica.GetNivelDesignadoRows()[0].ID;
                        aPc.ensureUniqueCodigoArgs.rhRowID = newrhRow.ID;
                        aPc.ensureUniqueCodigoArgs.rhRowIDUpper = newrhRow.IDUpper;
                        aPc.ensureUniqueCodigoArgs.testOnlyWithinNivel = true;

                        argsPc.pasteRhXPreConcArguments.Add(aPc);

                        var manageDocsPermissionsPreConcArguments = new PersistencyHelper.ManageDocsPermissionsPreConcArguments();
                        manageDocsPermissionsPreConcArguments.nRow = sourceRow;
                        manageDocsPermissionsPreConcArguments.oldParentRow = rhRow.NivelRowByNivelRelacaoHierarquicaUpper;
                        manageDocsPermissionsPreConcArguments.newParentRow = targetRow;


                        //var pasteRhXPreSaveArguments = new PersistencyHelper.PasteRhXPreSaveArguments();
                        aPc.manageDocsPermissionsArgs = manageDocsPermissionsPreConcArguments;

                        if (rhRow.IDTipoNivelRelacionado == TipoNivelRelacionado.SD)
                        {
                            var setNivelOrderPreConcArguments = new PersistencyHelper.SetNivelOrderPreConcArguments();
                            setNivelOrderPreConcArguments.nRowID = sourceRow.ID;
                            setNivelOrderPreConcArguments.nRowIDUpper = targetRow.ID;
                            aPc.setNivelOrderPreConcArguments = setNivelOrderPreConcArguments;
                        }

                        //aPc.pasteRhXPreSaveArguments = pasteRhXPreSaveArguments;
                        //argsPs.lstPasteRhXPreSaveArguments.Add(pasteRhXPreSaveArguments);

                        PersistencyHelper.UpdatePermissionsPostSaveArguments argsPostSave = new PersistencyHelper.UpdatePermissionsPostSaveArguments();
                        aPc.updatePermissionsPostSaveArgs = argsPostSave;
                    }
                );

                PostSaveAction postSaveAction = new PostSaveAction();
                PersistencyHelper.UpdatePermissionsPostSaveArguments argPostSave = new PersistencyHelper.UpdatePermissionsPostSaveArguments();
                postSaveAction.args = argPostSave;
                postSaveAction.postSaveDelegate = delegate(PersistencyHelper.PostSaveArguments postSaveArgs)
                {
                    // registar a edição dos níveis cuja operação foi bem sucedida
                    var noErrorArgs = argsPc.pasteRhXPreConcArguments.Where(a => a.PasteError == PersistencyHelper.PasteRhXPreConcArguments.PasteErrors.NoError).ToList();
                    noErrorArgs.ForEach(ID => CurrentContext.RaiseRegisterModificationEvent(ID.nivel.GetFRDBaseRows()[0]));

                    PersistencyHelperRule.Current.saveRows(GisaDataSetHelper.GetInstance().FRDBaseDataDeDescricao,
                        GisaDataSetHelper.GetInstance().FRDBaseDataDeDescricao.Cast<GISADataset.FRDBaseDataDeDescricaoRow>().Where(frd => frd.RowState == DataRowState.Added).ToArray(), postSaveArgs.tran);
                };

                PersistencyHelper.SaveResult successfulSave = PersistencyHelper.save(verifyIfCanPaste, argsPc, postSaveAction, true);
                PersistencyHelper.cleanDeletedData(PersistencyHelper.determinaNuvem("Nivel"));

                mClipboardNivelItems.Clear();
                ToolBarButtonPaste.Enabled = false;

                var nDeletedArg = argsPc.pasteRhXPreConcArguments.FirstOrDefault(a => a.PasteError == PersistencyHelper.PasteRhXPreConcArguments.PasteErrors.NDeleted);
                if (nDeletedArg != null)
                {
                    MessageBox.Show(nDeletedArg.message, "Eliminação de nível", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    return;
                }

                var errorAvaliacao = string.Empty;
                var errorRHDeleted = string.Empty;
                var errorNotUniqueCodigo = string.Empty;
                var errorNivelDeleted = string.Empty;
                var errorObjDigital = string.Empty;
                foreach (var arg in argsPc.pasteRhXPreConcArguments)
                {
                    switch (arg.PasteError)
                    {
                        case PersistencyHelper.PasteRhXPreConcArguments.PasteErrors.Avaliacao:
                            if (errorAvaliacao.Length == 0)
                                errorAvaliacao += arg.message + System.Environment.NewLine;
                            errorAvaliacao += arg.manageDocsPermissionsArgs.nRow.Codigo + " - " + arg.manageDocsPermissionsArgs.nRow.GetNivelDesignadoRows()[0].Designacao + System.Environment.NewLine;
                            break;
                        case PersistencyHelper.PasteRhXPreConcArguments.PasteErrors.RHDeleted:
                            if (errorRHDeleted.Length == 0)
                                errorRHDeleted += arg.message + System.Environment.NewLine;
                            errorRHDeleted += arg.manageDocsPermissionsArgs.nRow.Codigo + " - " + arg.manageDocsPermissionsArgs.nRow.GetNivelDesignadoRows()[0].Designacao + System.Environment.NewLine;
                            break;
                        case PersistencyHelper.PasteRhXPreConcArguments.PasteErrors.NotUniqueCodigo:
                            if (errorNotUniqueCodigo.Length == 0)
                                errorNotUniqueCodigo += arg.message + System.Environment.NewLine;
                            errorNotUniqueCodigo += arg.manageDocsPermissionsArgs.nRow.Codigo + " - " + arg.manageDocsPermissionsArgs.nRow.GetNivelDesignadoRows()[0].Designacao + System.Environment.NewLine;
                            break;
                        case PersistencyHelper.PasteRhXPreConcArguments.PasteErrors.ObjDigital:
                            if (errorObjDigital.Length == 0)
                                errorObjDigital += arg.message + System.Environment.NewLine;
                            errorObjDigital += arg.manageDocsPermissionsArgs.nRow.Codigo + " - " + arg.manageDocsPermissionsArgs.nRow.GetNivelDesignadoRows()[0].Designacao + System.Environment.NewLine;
                            break;
                        default:
                            if (arg.nivel.RowState == DataRowState.Detached)
                            {
                                if (errorNivelDeleted.Length == 0)
                                    errorNivelDeleted += arg.message + System.Environment.NewLine;
                                errorNivelDeleted += arg.manageDocsPermissionsArgs.nRow.Codigo + " - " + arg.manageDocsPermissionsArgs.nRow.GetNivelDesignadoRows()[0].Designacao + System.Environment.NewLine;
                            }
                            break;
                    }
                }

                if (errorAvaliacao.Length > 0 || errorRHDeleted.Length > 0 || errorNotUniqueCodigo.Length > 0 || errorNivelDeleted.Length > 0)
                {
                    var message = "Para os níveis seguintes não foi possível completar a operação.";

                    FormDeletionReport form = new FormDeletionReport();
                    form.Text = "Mover níveis";
                    form.Interrogacao = message;
                    form.Detalhes = errorAvaliacao + errorRHDeleted + errorNotUniqueCodigo + errorNivelDeleted;
                    form.SetBtnOKVisible(false);
                    form.ShowDialog();
                }

                // Cut/Paste de niveis documentais bem sucedidos
                if (successfulSave == PersistencyHelper.SaveResult.successful)
                {
                    var IDs = argsPc.pasteRhXPreConcArguments.Where(a => a.PasteError == PersistencyHelper.PasteRhXPreConcArguments.PasteErrors.NoError).ToList();

                    // recarregar a lista de niveis
                    if (this.nivelNavigator1.PanelToggleState == NivelNavigator.ToggleState.Documental)
                        this.nivelNavigator1.ReloadList();

                    List<string> IDNiveis = new List<string>();
                    IDNiveis.AddRange(IDs.Select(r => r.nivel.ID.ToString()));
                    GISA.Search.Updater.updateNivelDocumental(IDNiveis);
                    GISA.Search.Updater.updateNivelDocumentalComProdutores(IDNiveis);

                    // TODO: arranjar um sítio melhor para fazer a ingestão
                    string msg = null;

                    bool ingestSuccess = true;
                    if (argsPc.ODsToIngest != null)
                        argsPc.ODsToIngest.ForEach(od => ingestSuccess &= SessionHelper.AppConfiguration.GetCurrentAppconfiguration().FedoraHelperSingleton.Ingest(od, out msg));
                }
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex);
                MessageBox.Show("Não foi possível realizar esta operação.");
            }
        }
//INSTANT C# NOTE: C# does not support optional parameters. Overloaded method(s) are created above.
//ORIGINAL LINE: Public Shared Sub DeleteControloAut(ByVal caList As ControloAutList, ByVal Caption As String, ByVal Interrogacao As String, ByVal MessageBoxText As String, Optional ByVal caller As Control = null)
		public static void DeleteControloAut(ControloAutList caList, string Caption, string Interrogacao, string MessageBoxText, Control caller)
		{

			bool HasDocumentData = false;
            List<string> nivelIDsAssoc = new List<string>();
			string Detalhes = null;
			
            if (caller != null) ((frmMain)caller.TopLevelControl).EnterWaitMode();
            Detalhes = ControloAutHelper.GetControloAutUsage(caList.SelectedItems.Cast<ListViewItem>().Select(i => i.Tag as GISADataset.ControloAutDicionarioRow).ToList(), ref HasDocumentData, ref nivelIDsAssoc);
            if (caller != null) ((frmMain)caller.TopLevelControl).LeaveWaitMode();

			if (Detalhes.Length > 0)
			{
                FormDeletionReport form = new FormDeletionReport();
                form.Text = Caption;
                form.Interrogacao = Interrogacao;
                form.Detalhes = Detalhes;
				if (HasDocumentData)
				{
                    form.SetBtnOKVisible(false);
                    form.Interrogacao = "Este elemento não pode ser removido enquanto lhe existirem associados níveis documentais.";
				}

                if (form.ShowDialog() == DialogResult.Cancel) return;
			}
			else
			{
				switch (MessageBox.Show(MessageBoxText, Caption, MessageBoxButtons.OKCancel))
				{
					case System.Windows.Forms.DialogResult.OK:
					break;
					case System.Windows.Forms.DialogResult.Cancel:
						return;
					default:
						Debug.Assert(false, "Unexpected DialogResult.");
						break;
				}
			}

			Trace.WriteLine("A apagar notícia de autoridade...");

			ListViewItem selectedItem = null;
			if (caList.SelectedItems.Count > 0)
			{
				Debug.Assert(caList.SelectedItems.Count == 1, "Só deveria existir 1 item selecionado.");
				selectedItem = caList.SelectedItems[0];

				GISADataset.ControloAutDicionarioRow cadRow = null;
				GISADataset.ControloAutRow caRow = null;
				cadRow = (GISADataset.ControloAutDicionarioRow)selectedItem.Tag;
				caRow = cadRow.ControloAutRow;

				// Remover a selecção do item vai provocar uma mudança de contexto que 
				// por sua vez vai provocar uma gravação dos dados
				caList.ClearItemSelection(selectedItem);

                var ho = default(GisaDataSetHelper.HoldOpen);
                if (caller != null && caller.GetType() == typeof(MasterPanelControloAut))
                {
                    ((MasterPanelControloAut)caller).CurrentContext.RaiseRegisterModificationEvent(caRow);

                    if (caRow.IDTipoNoticiaAut == (long)TipoNoticiaAut.EntidadeProdutora)
                    {
                        var frdRow = default(GISADataset.FRDBaseRow);
                        long IDTipoNivelRelacionado = -1;
                        ho = new GisaDataSetHelper.HoldOpen(GisaDataSetHelper.GetConnection());
                        try
                        {
                            DBAbstractDataLayer.DataAccessRules.FRDRule.Current.LoadFRD(GisaDataSetHelper.GetInstance(), caRow.GetNivelControloAutRows().Single().ID, ho.Connection);
                            frdRow = caRow.GetNivelControloAutRows().Single().NivelRow.GetFRDBaseRows().SingleOrDefault();
                            DBAbstractDataLayer.DataAccessRules.NivelRule.Current.LoadNivelParents(caRow.GetNivelControloAutRows().Single().ID, GisaDataSetHelper.GetInstance(), ho.Connection);
                            if (frdRow != null)
                                IDTipoNivelRelacionado = DBAbstractDataLayer.DataAccessRules.NivelRule.Current.GetNivelLastIDTipoNivelRelacionado(frdRow.ID, ho.Connection);
                        }
                        finally
                        {
                            ho.Dispose();
                        }

                        if (frdRow != null) // frd pode ainda não ter sido criado
                        {
                            var caRegRow = GisaDataSetHelper.GetInstance().ControloAutDataDeDescricao.Cast<GISADataset.ControloAutDataDeDescricaoRow>().Single(r => r.RowState == DataRowState.Added);
                            var nvlRegRow = RecordRegisterHelper
                                            .CreateFRDBaseDataDeDescricaoRow(frdRow,
                                                caRegRow.TrusteeUserRowByTrusteeUserControloAutDataDeDescricao,
                                                caRegRow.TrusteeUserRowByTrusteeUserControloAutDataDeDescricaoAuthority,
                                                caRegRow.DataAutoria,
                                                IDTipoNivelRelacionado);
                            nvlRegRow.DataEdicao = caRegRow.DataEdicao;

                            GisaDataSetHelper.GetInstance().FRDBaseDataDeDescricao.AddFRDBaseDataDeDescricaoRow(nvlRegRow);
                        }
                    }
                }

				selectedItem.Remove();

                ho = new GisaDataSetHelper.HoldOpen(GisaDataSetHelper.GetConnection());
                List<long> lowerIDsList = new List<long>();
                try {
                    lowerIDsList = DiplomaModeloRule.Current.GetIDLowers(caRow.ID, ho.Connection);
                } 
                finally {
                    ho.Dispose();
                }

				// Como os dados acabaram de ser gravados pode ter-se chegado à conclusão que o contexto existente já não existia, daí este teste
				if (caRow.RowState != DataRowState.Detached)
				{
					try
					{
                        var oldTermo = caRow.GetControloAutDicionarioRows().Single(cad => cad.IDTipoControloAutForma == (long)TipoControloAutForma.FormaAutorizada).DicionarioRow.Termo;
                        var IDTipoNoticiaAut = caRow.IDTipoNoticiaAut;
						PersistencyHelper.DeleteIDXPreSaveArguments preSaveArgs = new PersistencyHelper.DeleteIDXPreSaveArguments();
						GISADataset.NivelControloAutRow[] ncaRows = null;
						GISADataset.NivelRow nRow = null;
						ncaRows = caRow.GetNivelControloAutRows();
						if (ncaRows.Length > 0)
						{
							nRow = ((GISADataset.NivelControloAutRow)(ncaRows[0])).NivelRow;
							preSaveArgs.ID = nRow.ID;
						}
						PersistencyHelper.DeleteCAXPreConcArguments preConcArgs = DeleteCAX(caRow);
                        PersistencyHelper.SaveResult successfulSave = PersistencyHelper.save(deleteCAXTermos, preConcArgs, Nivel.DeleteNivelXInDataBase, preSaveArgs);
						PersistencyHelper.cleanDeletedData();

                        if (successfulSave == PersistencyHelper.SaveResult.successful) {
                            if (SessionHelper.AppConfiguration.GetCurrentAppconfiguration().IsFedoraEnable())
                                SessionHelper.AppConfiguration.GetCurrentAppconfiguration().FedoraHelperSingleton.ActualizaObjDigitaisPorNivel(nivelIDsAssoc, oldTermo, null, IDTipoNoticiaAut);
                            Search.Updater.updateNivelDocumental(nivelIDsAssoc);
                            Search.Updater.updateNivelDocumentalComProdutores(lowerIDsList.Select(t => t.ToString()).ToList<string>());
                        }
					}
					catch (Exception ex)
					{
						Trace.WriteLine(ex);
						throw;
					}
				}
                else
                    GisaDataSetHelper.GetInstance().ControloAutDataDeDescricao.Cast<GISADataset.ControloAutDataDeDescricaoRow>().Single(r => r.RowState == DataRowState.Added && r.IDControloAut == caRow.ID).RejectChanges();
			}
		}