context: //
  // DO NOT REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  //
  // @Authors:
  //       christiank, timop
  //
  // Copyright 2004-2013 by OM International
  //
  // This file is part of OpenPetra.org.
  //
  // OpenPetra.org is free software: you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // OpenPetra.org is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  // GNU General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with OpenPetra.org.  If not, see <http://www.gnu.org/licenses/>.
  //
  using System;
  using System.Collections.Specialized;
  using System.Collections.Generic;
  using System.Data;
  using System.Data.Odbc;
  using System.Threading;
  using GNU.Gettext;
  using Ict.Common;
  using Ict.Common.Exceptions;
  using Ict.Common.DB;
  using Ict.Common.Data;
  using Ict.Common.Verification;
  using Ict.Common.Remoting.Shared;
  using Ict.Common.Remoting.Server;
  using Ict.Petra.Shared;
  using Ict.Petra.Shared.MSysMan;
  using Ict.Petra.Shared.Interfaces.MPartner;
  using Ict.Petra.Shared.MCommon;
  using Ict.Petra.Server.MCommon.Data.Cascading;
  using Ict.Petra.Shared.MPartner;
  using Ict.Petra.Server.MPartner.Mailroom.Data.Access;
  using Ict.Petra.Shared.MPartner.Mailroom.Data;
  using Ict.Petra.Server.MPartner.Partner.Data.Access;
  using Ict.Petra.Shared.MPartner.Partner.Data;
  using Ict.Petra.Shared.MPersonnel.Personnel.Data;
  using Ict.Petra.Server.MCommon;
  using Ict.Petra.Server.MFinance.Gift;
  using Ict.Petra.Server.MPartner.Partner;
  using Ict.Petra.Shared.MPersonnel.Person;
  using Ict.Petra.Shared.MCommon.Data;
  using Ict.Petra.Server.App.Core;
  using Ict.Petra.Server.MCommon.UIConnectors;
  using Ict.Petra.Server.MPartner.Common;
  using Ict.Petra.Server.MPartner;
  using Ict.Petra.Server.MPartner.DataAggregates;
  using Ict.Petra.Server.MSysMan.Maintenance.UserDefaults.WebConnectors;
  using Ict.Petra.Server.MPersonnel.Person.DataElements.WebConnectors;
  using Ict.Petra.Server.MFinance.Common;
  using Ict.Petra.Server.App.Core.Security;
  
  namespace Ict.Petra.Server.MPartner.Partner.UIConnectors
  {
      /// <summary>
      /// Partner Edit Screen UIConnector working with a Typed DataSet
      ///
      /// UIConnector Objects are instantiated by the Client's User Interface via the
      /// Instantiator classes.
      /// They handle requests for data retrieval and saving of data (including data
      /// verification).
      ///
      /// Their role is to
      ///   - retrieve (and possibly aggregate) data using Business Objects,
      ///   - put this data into///one* DataSet that is passed to the Client and make
      ///     sure that no unnessary data is transferred to the Client,
      ///   - optionally provide functionality to retrieve additional, different data
      ///     if requested by the Client (for Client screens that load data initially
      ///     as well as later, eg. when a certain tab on the screen is clicked),
      ///   - save data using Business Objects.
      ///
      /// @Comment These Objects would usually not be instantiated by other Server
      ///          Objects, but only by the Client UI via the Instantiator classes.
      ///          However, Server Objects that derive from these objects and that
      ///          are also UIConnectors are feasible.
      ///
      /// </summary>
      public partial class TPartnerEditUIConnector : IPartnerUIConnectorsPartnerEdit
      {
          private const String DATASETNAME = "PartnerEditScreen";
  
          /// <summary>Holds DataTables which are created by the instantiated Partner Business Objects</summary>
          private PartnerEditTDS FPartnerEditScreenDS;
          private Int64 FPartnerKey;
          private Int64 FNewPartnerPartnerKey;
          private TLocationPK FKeyForSelectingPartnerLocation;
          private TPartnerClass FPartnerClass;
          private TPartnerClass FNewPartnerPartnerClass;
          private PartnerEditTDS FSubmissionDS;
  
          #region TPartnerEditUIConnector
  
          /// <summary>
          /// Constructor which automatically loads data for the Partner.
          ///
          /// </summary>
          /// <param name="APartnerKey">PartnerKey for the Partner to instantiate this object with
          /// </param>
          /// <returns>void</returns>
          public TPartnerEditUIConnector(System.Int64 APartnerKey) : base()
          {
              FPartnerKey = APartnerKey;
              FKeyForSelectingPartnerLocation = new TLocationPK(0, 0);
          }
  
          /// <summary>
          /// Constructor which automatically loads data for the Partner.
          ///
          /// @Comment Use this overload to specify which Address should be selected when
          /// the Partner Edit screen is shown.
          ///
          /// </summary>
          /// <param name="APartnerKey">PartnerKey for the Partner to instantiate this object with</param>
          /// <param name="ASiteKey">SiteKey of the PartnerLocation record of the Partner</param>
          /// <param name="ALocationKey">LocationKey of the PartnerLocation record of the Partner
          /// </param>
          /// <returns>void</returns>
          public TPartnerEditUIConnector(Int64 APartnerKey, Int64 ASiteKey, Int32 ALocationKey) : base()
          {
              FPartnerKey = APartnerKey;
              FKeyForSelectingPartnerLocation = new TLocationPK(ASiteKey, ALocationKey);
          }
  
          /// <summary>
          /// Constructor for creating a new Partner.
          ///
          /// </summary>
          /// <returns>void</returns>
          public TPartnerEditUIConnector() : base()
          {
              FKeyForSelectingPartnerLocation = new TLocationPK(0, 0);
          }
  
          #region BankingDetails
  
          private void PrepareBankingDetailsForSaving(ref PartnerEditTDS AInspectDS, ref TVerificationResultCollection AVerificationResult,
              TDBTransaction ATransaction)
          {
              if ((AInspectDS.PBankingDetails != null) && (AInspectDS.PBankingDetails.Rows.Count > 0))
              {
                  AInspectDS.Merge(new PBankingDetailsUsageTable());
                  AInspectDS.InitVars();
                  PBankingDetailsUsageAccess.LoadViaPPartner(AInspectDS, FPartnerKey, ATransaction);
                  AInspectDS.PBankingDetailsUsage.AcceptChanges();
  
                  // make sure there is at least one main account, or no account at all
                  // make sure there are no multiple main accounts
  
                  PartnerEditTDS LocalDS = new PartnerEditTDS();
                  PBankingDetailsAccess.LoadViaPPartner(LocalDS, FPartnerKey, ATransaction);
  
                  // there are problems with Mono on merging deleted rows into the LocalDS, they become modified rows
                  // see https://tracker.openpetra.org/view.php?id=1871
                  LocalDS.Merge(AInspectDS.PBankingDetails);
  
                  // workaround for bug 1871
                  List <Int32>DeletedBankingDetails = new List <Int32>();
  
                  foreach (DataRow bdrow in AInspectDS.PBankingDetails.Rows)
                  {
                      if (bdrow.RowState == DataRowState.Deleted)
                      {
                          DeletedBankingDetails.Add(Convert.ToInt32(bdrow[AInspectDS.PBankingDetails.ColumnBankingDetailsKey, DataRowVersion.Original]));
                      }
                  }
  
                  bool ThereIsAtLeastOneAccount = false;
  
                  // get the main account
                  Int32 MainAccountBankingDetails = Int32.MinValue;
  
                  foreach (PartnerEditTDSPBankingDetailsRow detailRow in LocalDS.PBankingDetails.Rows)
                  {
                      if ((detailRow.RowState != DataRowState.Deleted) && !DeletedBankingDetails.Contains(detailRow.BankingDetailsKey))
                      {
                          ThereIsAtLeastOneAccount = true;
  
                          if (!detailRow.IsMainAccountNull() && detailRow.MainAccount)
                          {
                              if ((MainAccountBankingDetails != Int32.MinValue) && (detailRow.BankingDetailsKey != MainAccountBankingDetails))
                              {
                                  AVerificationResult.Add(new TVerificationResult(
                                          String.Format("Banking Details"),
                                          string.Format("there are multiple main accounts"),
                                          TResultSeverity.Resv_Critical));
                                  return;
                              }
                              else
                              {
                                  // if the main account has been changed
                                  MainAccountBankingDetails = detailRow.BankingDetailsKey;
                              }
                          }
                      }
                  }
  
                  bool alreadyExists = false;
  
                  foreach (PBankingDetailsUsageRow usageRow in AInspectDS.PBankingDetailsUsage.Rows)
                  {
                      if (usageRow.Type == MPartnerConstants.BANKINGUSAGETYPE_MAIN)
                      {
                          DataRow bdrow = LocalDS.PBankingDetails.Rows.Find(usageRow.BankingDetailsKey);
  
                          if ((bdrow == null) || (bdrow.RowState == DataRowState.Deleted)
                              || DeletedBankingDetails.Contains(usageRow.BankingDetailsKey))
                          {
                              // deleting the account
                              usageRow.Delete();
                          }
                          else if (MainAccountBankingDetails == Int32.MinValue)
                          {
                              MainAccountBankingDetails = usageRow.BankingDetailsKey;
                              alreadyExists = true;
                          }
                          else if ((MainAccountBankingDetails != Int32.MinValue) && (usageRow.BankingDetailsKey != MainAccountBankingDetails))
                          {
                              usageRow.Delete();
                          }
                          else
                          {
                              alreadyExists = true;
                          }
                      }
                  }
  
  
gt:                 if (!alreadyExists && ThereIsAtLeastOneAccount)