unit uDataTableUtils;

interface

uses
  uDACDSDataTable, uDADataTable, uDAInterfaces;

const
  ID_NULO = -9000;
  ID_TODOS = -9001;
  ID_PRIMERO = -9002;

type
  TModoDuplicarRegistros = (mdrTodos, mdrActual, mdrSeleccionados);

procedure CloneDataTable(const ASource : TDACDSDataTable;
                         var ATarget : TDACDSDataTable;
                         RemoteUpdate: Boolean = True);

procedure DuplicarRegistro(ASource : TDADataTable; ATarget : TDADataTable);
procedure DuplicarRegistros(ASource : TDADataTable; ATarget : TDADataTable;
  AModo : TModoDuplicarRegistros);

procedure CopyDataTable(ASource : TDADataTable; ATarget : TDADataTable;
  const OnlySelectedRows : Boolean = False);

procedure DeleteAllTable(const ADataTable : TDADataTable);
function DeltaValuesAreDifferent(const aDelta : IDADelta): boolean;

procedure EnlazarMaestroDetalle(AMasterDataSource : TDADataSource;
  ADetail : IDAStronglyTypedDataTable);

implementation

uses
  uDAClasses, SysUtils, uDABINAdapter, uROTypes, cxControls,
  Dialogs, Variants, uDBSelectionListUtils, uROClasses;


{procedure EliminarNoSeleccionados(const ASource : IDADataset;
  var ATarget : TDADataTable);
var
  AObj : ISelectedRowList;
  i : Integer;
begin
  if not Supports(ASource, ISelectedRowList, aObj) then
    Exit;

//  ATarget.DisableControls;
//  ATarget.DisableEventHandlers;
  ShowHourglassCursor;
  try
    ATarget.Open;
    ATarget.Last;
    while ATarget.RecordCount > AObj.SelectedRows.Count do
    begin
      if AObj.SelectedRows.IndexOf(ATarget.RecIDValue) < 0 then
        ATarget.Delete
      else
        ATarget.Prior;
    end;
  finally
//    ATarget.EnableControls;
//    ATarget.EnableControls;
    HideHourglassCursor;
  end;
end;}


procedure DeleteAllTable(const ADataTable : TDADataTable);
begin
  ADataTable.ClearRows;
end;

procedure CloneDataTable(const ASource : TDACDSDataTable;
  var ATarget : TDACDSDataTable; RemoteUpdate: Boolean);
var
  i : Integer;
begin
  with ATarget do
  begin
    RemoteService := ASource.GetRemoteService;
    Adapter := ASource.GetAdapter;

    //BusinessRulesID := ASource.BusinessRulesID;
    Randomize;
    Name := ASource.Name + '_' + IntToStr(Random(MAXINT));
    LogicalName := ASource.LogicalName;

    Params.AssignParamCollection(ASource.Params);

    if Assigned(ASource.LocalSchema) then
      LocalSchema := ASource.LocalSchema
    else begin
      with SchemaCall do
      begin
        MethodName := ASource.SchemaCall.MethodName;
        for i := 0 to ASource.SchemaCall.Params.Count - 1 do
        begin
          with Params.Add do begin
            Name := ASource.SchemaCall.Params[i].Name;
            ParamType := ASource.SchemaCall.Params[i].ParamType;
            DataType := ASource.SchemaCall.Params[i].DataType;
            Value := ASource.SchemaCall.Params[i].Value;
            UserClassName := ASource.SchemaCall.Params[i].UserClassName;
          end;
        end;
      end;
      ATarget.Fields.AssignFieldCollection(ASource.Fields);   // o también ATarget.LoadSchema;
    end;
    
    with DataUpdateCall do
    begin
      MethodName := ASource.DataUpdateCall.MethodName;
      for i := 0 to ASource.DataUpdateCall.Params.Count - 1 do
      begin
        with Params.Add do begin
          Name := ASource.DataUpdateCall.Params[i].Name;
          ParamType := ASource.DataUpdateCall.Params[i].ParamType;
          DataType := ASource.DataUpdateCall.Params[i].DataType;
          Value := ASource.DataUpdateCall.Params[i].Value;
          UserClassName := ASource.DataUpdateCall.Params[i].UserClassName;
        end;
      end;
    end;

    with ScriptCall do
    begin
      MethodName := ASource.ScriptCall.MethodName;
      for i := 0 to ASource.ScriptCall.Params.Count - 1 do
      begin
        with Params.Add do begin
          Name := ASource.ScriptCall.Params[i].Name;
          ParamType := ASource.ScriptCall.Params[i].ParamType;
          DataType := ASource.ScriptCall.Params[i].DataType;
          Value := ASource.ScriptCall.Params[i].Value;
          UserClassName := ASource.ScriptCall.Params[i].UserClassName;
        end;
      end;
    end;

    with DataRequestCall do
    begin
      MethodName := ASource.DataRequestCall.MethodName;
      for i := 0 to ASource.DataRequestCall.Params.Count - 1 do
      begin
        with Params.Add do begin
          begin
            Name := ASource.DataRequestCall.Params[i].Name;
            ParamType := ASource.DataRequestCall.Params[i].ParamType;
            DataType := ASource.DataRequestCall.Params[i].DataType;
            Value := ASource.DataRequestCall.Params[i].Value;
            UserClassName := ASource.DataRequestCall.Params[i].UserClassName;
          end;
        end;
      end;
    end;

    with MasterParamsMappings do
      for i := 0 to ASource.MasterParamsMappings.Count - 1 do
        Add(ASource.MasterParamsMappings.Strings[i]);

    with MasterRequestMappings do
      for i := 0 to ASource.MasterRequestMappings.Count - 1 do
        Add(ASource.MasterRequestMappings.Strings[i]);

    MasterMappingMode := ASource.MasterMappingMode;

    MasterFields := ASource.MasterFields;
    MasterOptions := ASource.MasterOptions;

    DetailFields := ASource.DetailFields;
    DetailOptions := ASource.DetailOptions;

    RemoteUpdatesOptions := ASource.RemoteUpdatesOptions;
    StreamingOptions := ASource.StreamingOptions;
    RemoteFetchEnabled := ASource.RemoteFetchEnabled;
  end;

  if not RemoteUpdate then
  begin
    ATarget.LogChanges := False;
    ATarget.RemoteFetchEnabled := False;
  end;
end;
  

function DeltaValuesAreDifferent(const aDelta : IDADelta): boolean;
var
  i, x : integer;
  OldNewAreDifferent: boolean;
begin
  OldNewAreDifferent := FALSE;
  for i := 0 to (aDelta.Count-1) do
  begin
    for x := 0 to (aDelta.LoggedFieldCount-1) do
    begin
      if aDelta.LoggedFieldTypes[x] <> datBlob then
        OldNewAreDifferent := (aDelta.Changes[i].OldValues[x] <> aDelta.Changes[i].NewValues[x]);

      if OldNewAreDifferent then
        Break;    // Abandon iteration at the first difference between old and new.
    end;

    if OldNewAreDifferent then
      Break;    // Abandon iteration at the first difference between old and new.
  end;
  result := OldNewAreDifferent;
end;


procedure CopyDataTable(ASource : TDADataTable; ATarget : TDADataTable;
  const OnlySelectedRows : Boolean = False);
var
  DABin: Binary;
  DAAdapter : TDABINAdapter;
  AFilter : String;
  AFiltered : Boolean;
  AObj : ISelectedRecords;
  i : Integer;
begin
  AFilter := '';
  AFiltered := False;

  if OnlySelectedRows then
  begin
    if not Supports(ASource, ISelectedRecords, aObj) then
      raise Exception.Create('El origen de datos no soporta la interfaz ISelectedRecords (CopyDataTable)');

    if ASource.Filtered then
    begin
      AFiltered := True;
      AFilter := ASource.Filter;
      ASource.Filtered := False;
    end;

    ASource.Filter := '';
    if ASource.Active then
      ASource.Close;

    for i := 0 to AObj.Count - 1 do
    begin
      if (i > 0) then
        ASource.Filter := ASource.Filter + ' or ';
      ASource.Filter := ASource.Filter + '(ID = ' + IntToStr(AObj.Items[i]) + ')';
    end;

    ASource.Filtered := True;
  end;


  DABin := Binary.Create;
  DAAdapter := TDABINAdapter.Create(nil);
  try
    ATarget.LogicalName := ASource.LogicalName;  // We need to specify new dataset LogicalName
    ATarget.RemoteFetchEnabled := False;  // "Desconectamos" la tabla destino del servidor

    if not ASource.Active then
      ASource.Open;
    ASource.First;

    DAAdapter.Initialize(DABin, aiWrite);
    DAAdapter.WriteDataset(DABin, ASource, [woRows]);
    DAAdapter.Initialize(DABin, aiReadFromBeginning);
    DAAdapter.ReadDataset(DABin, ATarget);
    DAAdapter.Finalize;

    ATarget.RemoteFetchEnabled := True; // "Conectamos" la tabla del servidor otra vez

    // Dejar el filtro de la tabla origen como estaba
    if OnlySelectedRows then
    begin
      ASource.Filtered := False;
      ASource.Filter := AFilter;
      if AFiltered then
        ASource.Filtered := True;
    end;

  finally
    FreeAndNil(DABin);
    FreeAndNil(DAAdapter);
  end;
end;

procedure DuplicarRegistro(ASource : TDADataTable; ATarget : TDADataTable);
var
  i: Integer;
  ATargetField: TDAField;
  ASourceField: TDAField;
  ADetailFields : String;
begin
  if not ASource.Active then
    ASource.Open;

  if not ASource.Active then
    ATarget.Open;

  // ¿ATarget es una tabla detalle?
  if Assigned(ATarget.MasterSource) then
  begin
    case ATarget.MasterMappingMode of
      //mmDataRequest: //Sin hacer;
      mmParams: ADetailFields := ATarget.DetailFields;
    end;
  end
  else
    ADetailFields := '';

  ATarget.Insert;
  { Hay que desactivar los eventos para que dejan de funcionar
    las reglas de negocio y no nos interfieran en la copia
    de valores de los campos. }
  ATarget.DisableEventHandlers;
  try
    for i := 0 to ASource.Fields.Count - 1 do
    begin
      ASourceField := ASource.Fields[i];
      ATargetField := ATarget.FindField(ASourceField.Name);

      if Assigned(ATargetField) then
      begin
        // Los campos AutoInc no se rellenan y tampoco los campos que
        // formen parte de la relación maestro-detalle en el
        // caso de que la tabla destino sea una tabla detalle.
        if (ATargetField.DataType <> datAutoInc) and
           (Pos(ATargetField.Name, ADetailFields) = 0) then
          ATargetField.Value := ASourceField.Value;
      end;
    end;
  finally
    ATarget.EnableEventHandlers;
    ATarget.Post;
  end;
end;


procedure DuplicarRegistros(ASource : TDADataTable; ATarget : TDADataTable;
  AModo : TModoDuplicarRegistros);
begin
  if not ASource.Active then
    ASource.Open;

  if not ATarget.Active then
    ATarget.Open;

  if AModo = mdrActual then
    DuplicarRegistro(ASource, ATarget) //ATarget.CloneSelectedRecord(ASource, True)
  else begin
    ASource.First;
    while not ASource.EOF do
    begin
      DuplicarRegistro(ASource, ATarget);
      ASource.Next;
    end;
  end;
end;


procedure EnlazarMaestroDetalle(AMasterDataSource : TDADataSource;
  ADetail : IDAStronglyTypedDataTable);
begin
  if Assigned(ADetail) then
  begin
    // ¡¡¡¡¡ MUY IMPORTANTE !!!!!!!!!!!!!!!!!!
    ADetail.DataTable.DisableEventHandlers;
    try
      ADetail.DataTable.MasterSource := AMasterDataSource;
    finally
    { Hay que activar los eventos porque dejan de funcionar
      las reglas de negocio al establecer la relación
      maestro-detalle. (Fallo de Data Abstract 3) }
      ADetail.DataTable.EnableEventHandlers;
    end;
  end;
end;

end.
