unit uMedicacionesController;

interface


uses
  Classes, SysUtils, uDADataTable, uEditorDBItem,
  uControllerBase, uIDataModuleMedicaciones, uPacientesController,
  uDetallesMedicacionController, uBizMedicaciones;

type
  IMedicacionesController = interface(IControllerBase)
  ['{351B9280-F927-427D-9042-11EDED8067EF}']
    function GetPacienteController: IPacientesController;
    procedure SetPacienteController(const Value: IPacientesController);
    property PacienteController: IPacientesController read GetPacienteController write SetPacienteController;

    function GetDetallesController: IDetallesMedicacionController;
    procedure SetDetallesController(const Value: IDetallesMedicacionController);
    property DetallesController: IDetallesMedicacionController read GetDetallesController write SetDetallesController;

    function Buscar(const ID: Integer): IBizMedicacion;
    function BuscarTodos: IBizMedicacion; overload;
    function BuscarTodos(const ID_Paciente: Integer): IBizMedicacion; overload;
    procedure Ver(AMedicacion : IBizMedicacion);
    procedure VerTodos(AMedicaciones: IBizMedicacion;
      const AVerModal : Boolean = False; const AWindowCaption: String = '';
      const AHeaderText: String = '');
    function Nuevo(withInsert: Boolean = True): IBizMedicacion;
    function Anadir(AMedicacion : IBizMedicacion): Boolean; overload;
    function Eliminar(const ID : Integer): Boolean; overload;
    function Eliminar(AMedicacion : IBizMedicacion; AllItems: Boolean = false): Boolean; overload;
    function Guardar(AMedicacion : IBizMedicacion): Boolean;
    procedure DescartarCambios(AMedicacion : IBizMedicacion);
    function Existe(const ID: Integer) : Boolean;
    function Duplicar(AMedicacion: IBizMedicacion): IBizMedicacion;

    function ExtraerSeleccionados(AMedicacion: IBizMedicacion) : IBizMedicacion;
    function ElegirMedicacion(AMedicacion: IBizMedicacion; AMensaje: String; AMultiSelect: Boolean): IBizMedicacion;

    procedure Preview(AMedicacion : IBizMedicacion; AllItems: Boolean = false);
    procedure Print(AMedicacion : IBizMedicacion; AllItems: Boolean = false);

    function EsModificable(AMedicacion: IBizMedicacion): Boolean;
    function EsEliminable(AMedicacion: IBizMedicacion): Boolean;

    procedure RecuperarPaciente(AMedicacion: IBizMedicacion);

  end;

  TMedicacionesController = class(TControllerBase, IMedicacionesController)
  protected
    FDataModule : IDataModuleMedicaciones;
    FPacienteController : IPacientesController;
    FDetallesController : IDetallesMedicacionController;

    function GetPacienteController: IPacientesController;
    procedure SetPacienteController(const Value: IPacientesController);
    function GetDetallesController: IDetallesMedicacionController;
    procedure SetDetallesController(const Value: IDetallesMedicacionController);

    //Estos son los tres métodos a sobre escribir si se desea heredar toda la logica de
    //este controller
    procedure AsignarDataModule; virtual;
    procedure RecuperarObjetos(AMedicacion: IBizMedicacion); virtual;

    procedure RecibirAviso(ASujeto: ISujeto; ADataTable: IDAStronglyTypedDataTable); override;
    function CreateEditor(const AName : String; const IID: TGUID; out Intf): Boolean;
    function _Vacio : IBizMedicacion;
    function ValidarMedicacion(AMedicacion: IBizMedicacion): Boolean;
  public
    property PacienteController: IPacientesController read GetPacienteController write SetPacienteController;
    property DetallesController: IDetallesMedicacionController read GetDetallesController write SetDetallesController;

    constructor Create; override;
    destructor Destroy; override;

    function Eliminar(const ID : Integer): Boolean; overload;
    function Eliminar(AMedicacion : IBizMedicacion; AllItems: Boolean = false): Boolean; overload;
    function Guardar(AMedicacion : IBizMedicacion): Boolean;
    procedure DescartarCambios(AMedicacion : IBizMedicacion); virtual;
    function Existe(const ID: Integer) : Boolean; virtual;
    function Anadir(AMedicacion : IBizMedicacion): Boolean; overload;
    function Buscar(const ID: Integer): IBizMedicacion;
    function BuscarTodos: IBizMedicacion; overload;
    function BuscarTodos(const ID_Paciente: Integer): IBizMedicacion; overload;

    function Nuevo (withInsert: Boolean = True) : IBizMedicacion;
    procedure Ver(AMedicacion : IBizMedicacion);
    procedure VerTodos(AMedicaciones: IBizMedicacion;
      const AVerModal : Boolean = False; const AWindowCaption: String = '';
      const AHeaderText: String = '');
    function Duplicar(AMedicacion: IBizMedicacion): IBizMedicacion;

    function ExtraerSeleccionados(AMedicacion: IBizMedicacion) : IBizMedicacion;
    function ElegirMedicacion(AMedicacion: IBizMedicacion; AMensaje: String; AMultiSelect: Boolean): IBizMedicacion;

    procedure RecuperarPaciente(AMedicacion : IBizMedicacion);

    function EsModificable(AMedicacion: IBizMedicacion): Boolean;
    function EsEliminable(AMedicacion: IBizMedicacion): Boolean;

    procedure Preview(AMedicacion : IBizMedicacion; AllItems: Boolean = false);
    procedure Print(AMedicacion : IBizMedicacion; AllItems: Boolean = false);
  end;

implementation

uses
  uROTypes, Controls, cxControls, DB, uEditorRegistryUtils, uEditorPreview, DateUtils,
  uIEditorMedicacion, uIEditorElegirMedicacion,
  uDataModuleMedicaciones, Variants, uBizDetallesMedicacion,
  uBizContactos, uDataTableUtils, uDataModuleUsuarios, uFactuGES_App,
  schMedicacionClient_Intf, uDAInterfaces, uDateUtils, uIEditorMedicaciones,

  schContactosClient_Intf, uMedicacionReportController, uControllerDetallesBase,

  uDialogUtils, Windows, Forms, Dialogs, uGUIBase, uIntegerListUtils,
  uSistemaFunc, uEMailUtils, uDialogElegirEMail, uStringsUtils;



{ TMedicacionesController }

function TMedicacionesController.Anadir(AMedicacion: IBizMedicacion): Boolean;
begin
  if not Assigned(AMedicacion) then
    raise Exception.Create ('Medicación no asignada (Anadir)');

  if not AMedicacion.DataTable.Active then
    AMedicacion.DataTable.Active := True;

  AMedicacion.Insert;
  Result := True;
end;

procedure TMedicacionesController.AsignarDataModule;
begin
  FDataModule := TDataModuleMedicacion.Create(Nil);
end;

function TMedicacionesController.Buscar(const ID: Integer): IBizMedicacion;
begin
  Result := FDataModule.GetItem(ID);
end;

function TMedicacionesController.BuscarTodos: IBizMedicacion;
begin
  Result := FDataModule.GetItems;
end;

function TMedicacionesController.BuscarTodos(
  const ID_Paciente: Integer): IBizMedicacion;
var
  Condicion: TDAWhereExpression;
begin
  ShowHourglassCursor;
  try
    Result := BuscarTodos;

    with Result.DataTable.DynamicWhere do
    begin
      // ID_PACIENTE
      Condicion := NewBinaryExpression(NewField('', fld_MedicacionID_PACIENTE), NewConstant(ID_Paciente, datInteger), dboEqual);

      if IsEmpty then
         Expression := Condicion
      else
         Expression := NewBinaryExpression(Expression, Condicion, dboAnd);
    end;
  finally
    HideHourglassCursor;
  end;
end;

constructor TMedicacionesController.Create;
begin
  inherited;
  AsignarDataModule;
  
  FPacienteController := TPacientesController.Create;
  FDetallesController := TDetallesMedicacionController.Create;
  FDetallesController.addObservador(Self);
end;

function TMedicacionesController.CreateEditor(const AName: String;
  const IID: TGUID; out Intf): Boolean;
begin
  Result := Supports(EditorRegistry.CreateEditor(AName), IID, Intf);
end;

procedure TMedicacionesController.DescartarCambios(AMedicacion: IBizMedicacion);
begin
  if not Assigned(AMedicacion) then
    raise Exception.Create ('Medicación no asignada');

  ShowHourglassCursor;
  try
    if (AMedicacion.State in dsEditModes) then
      AMedicacion.Cancel;

    AMedicacion.DataTable.CancelUpdates;
  finally
    HideHourglassCursor;
  end;
end;

destructor TMedicacionesController.Destroy;
begin
  FDataModule := Nil;
  FPacienteController := Nil;
  FDetallesController := Nil;
  inherited;
end;

function TMedicacionesController.Duplicar(AMedicacion: IBizMedicacion): IBizMedicacion;
begin
  Result := Self._Vacio;
  ShowHourglassCursor;
  try
    DuplicarRegistros(AMedicacion.DataTable, Result.DataTable, mdrActual);
    DuplicarRegistros(AMedicacion.Detalles.DataTable, Result.Detalles.DataTable, mdrTodos);

    // Hay que dejar algunos campos como si fuera un presupuesto nuevo
    Result.Edit;
    with Result do
    begin
      FECHA_DESDE := DateOf(Now);
      FECHA_HASTA := DateOf(Now) + 6;
      REFERENCIA := '';
    end;
    Result.Post;
  finally
    HideHourglassCursor;
  end;
end;

function TMedicacionesController.ValidarMedicacion(
  AMedicacion: IBizMedicacion): Boolean;
begin
  if not Assigned(AMedicacion) then
     raise Exception.Create ('Medicacion no asignada');

  if (AMedicacion.DataTable.State in dsEditModes) then
      AMedicacion.DataTable.Post;

  //Tambien hacemos post de sus tablas hija
  if (AMedicacion.Detalles.DataTable.State in dsEditModes) then
      AMedicacion.Detalles.DataTable.Post;

  if (AMedicacion.ID_PACIENTE <= 0) then
  // Si hay altas automáticas no hay objeto Paciente pero sí hay ID_PACIENTE
{     (not Assigned(AMedicacion.Paciente)) or
     (AMedicacion.Paciente.IsEmpty) then}
    raise Exception.Create('Debe indicar el paciente de esta medicación');

  if (EsFechaVacia(AMedicacion.FECHA_DESDE)) then
    raise Exception.Create('Debe indicar la fecha inicial de esta medicación');

  if (EsFechaVacia(AMedicacion.FECHA_HASTA)) then
    raise Exception.Create('Debe indicar la fecha final de esta medicación');

  if (AMedicacion.Detalles.DataTable.RecordCount = 0) then
    raise Exception.Create('La medicación debe tener en su contenido al menos un concepto');

   if AMedicacion.FECHA_HASTA < AMedicacion.FECHA_DESDE then
      raise Exception.Create('La fecha final debe ser posterior a la fecha inicial');

  { Asegurarse de valores en campos "automáticos" tanto
    en MODIFICACIÓN como en INSERCIÓN. }
  AMedicacion.Edit;
  try
    Result := True;
  finally
    AMedicacion.Post;
  end;
end;

procedure TMedicacionesController.Ver(AMedicacion: IBizMedicacion);
var
  AEditor : IEditorMedicacion;
begin
  AEditor := NIL;
  RecuperarObjetos(AMedicacion);

  CreateEditor('EditorMedicacion', IEditorMedicacion, AEditor);

  if Assigned(AEditor) then
    try
      //MODO CONSULTAR
      AEditor.Controller := Self; //OJO ORDEN MUY IMPORTANTE
      AEditor.Medicacion := AMedicacion;

      if not EsModificable(AMedicacion) then
      begin
         SetDataTableReadOnly(AMedicacion.DataTable, True);
         AEditor.ReadOnly := True;
      end;

      AEditor.ShowModal;

      //MODO CONSULTAR (Se deja la tabla como estaba)
      if AEditor.ReadOnly then
         SetDataTableReadOnly(AMedicacion.DataTable, False);
    finally
      AEditor.Release;
      AEditor := NIL;
    end;
end;

procedure TMedicacionesController.VerTodos(AMedicaciones: IBizMedicacion;
      const AVerModal : Boolean = False; const AWindowCaption: String = '';
      const AHeaderText: String = '');
var
  AEditor : IEditorMedicaciones;
begin
  AEditor := NIL;
  CreateEditor('EditorMedicaciones', IEditorMedicaciones, AEditor);
  if Assigned(AEditor) then
    try
      if not EsCadenaVacia(AWindowCaption) then
        AEditor.WindowCaption := AWindowCaption;

      if not EsCadenaVacia(AHeaderText) then
        AEditor.HeaderText := AHeaderText;

       AEditor.Controller := Self; //OJO ORDEN MUY IMPORTANTE
       AEditor.Medicaciones := AMedicaciones;
       AEditor.MultiSelect := True;

       if AVerModal then
          AEditor.ShowModal
       else
          AEditor.ShowEmbedded;
    finally
      if AVerModal then
        AEditor.Release;
      AEditor := NIL;
    end;
end;

function TMedicacionesController._Vacio: IBizMedicacion;
begin
  Result := Buscar(ID_NULO);
end;

function TMedicacionesController.Eliminar(const ID: Integer): Boolean;
var
  AMedicacion : IBizMedicacion;
begin
  AMedicacion := Buscar(ID);

  if not Assigned(AMedicacion) then
    raise Exception.Create(Format('No se ha encontrado la medicación con ID = %d', [ID]));

  Result := Eliminar(AMedicacion);
  AMedicacion := NIL;
end;

function TMedicacionesController.ElegirMedicacion(AMedicacion: IBizMedicacion; AMensaje: String; AMultiSelect: Boolean): IBizMedicacion;
var
  AEditor : IEditorElegirMedicacion;
begin
  Result := NIL;
  CreateEditor('EditorElegirMedicacion', IEditorElegirMedicacion, AEditor);
  if Assigned(AEditor) then
    try
      AEditor.Controller := Self;
      AEditor.Medicaciones := AMedicacion;
      AEditor.MultiSelect := AMultiSelect;
      AEditor.Mensaje := AMensaje;
      if IsPositiveResult(AEditor.ShowModal) then
        Result := AEditor.MedicacionesSeleccionadas;
    finally
      AEditor.Release;
      AEditor := NIL;
    end;
end;

function TMedicacionesController.Eliminar(AMedicacion: IBizMedicacion; AllItems: Boolean = false): Boolean;
//En el caso de eliminar almenos un elemento del conjunto se devuelve true
var
  bEliminado: Boolean;

begin
  bEliminado := False;

  if not Assigned(AMedicacion) then
    raise Exception.Create ('Medicación no asignada');

  ShowHourglassCursor;
  try
    if (AMedicacion.State in dsEditModes) then
      AMedicacion.Cancel;

    //Siempre eliminaremos el seleccionado
    if EsEliminable(AMedicacion) then
    begin
      AMedicacion.Delete;
      bEliminado := True;
    end;

    //En el caso de querer eliminar todos los items del objeto AMedicacion
    if AllItems then
    begin
       with AMedicacion.DataTable do
       begin
         First;
         while not EOF do
         begin
           if EsEliminable(AMedicacion) then
           begin
              AMedicacion.Delete;
              bEliminado := True
           end
           else Next;
         end;
       end;
    end;

    if bEliminado then
    begin
       AMedicacion.DataTable.ApplyUpdates;
       Result := True;
    end
    else
       Result := False;

  finally
    HideHourglassCursor;
  end;
end;

function TMedicacionesController.EsEliminable(AMedicacion: IBizMedicacion): Boolean;
begin
  if not Assigned(AMedicacion) then
     raise Exception.Create ('Medicación no asignado: EsModificable');

  Result := EsModificable(AMedicacion);
end;

function TMedicacionesController.EsModificable(AMedicacion: IBizMedicacion): Boolean;
begin
  Result := True;
end;

procedure TMedicacionesController.RecibirAviso(ASujeto: ISujeto; ADataTable: IDAStronglyTypedDataTable);
var
  AMedicacion : IBizMedicacion;
  ADetalles : IBizDetallesMedicacion;
begin
  inherited;

  if Supports(ADataTable, IBizDetallesMedicacion, ADetalles) and
     Supports(ADetalles.DataTable.MasterSource.DataTable, IBizMedicacion, AMedicacion) then
  begin
    //RecalcularImportes(AMedicacion);
  end;
end;

procedure TMedicacionesController.RecuperarObjetos(AMedicacion: IBizMedicacion);
begin
  RecuperarPaciente(AMedicacion);
end;

procedure TMedicacionesController.RecuperarPaciente(
  AMedicacion: IBizMedicacion);
begin
  AMedicacion._Paciente := (FPacienteController.Buscar(AMedicacion.ID_Paciente) as IBizPaciente);
end;

function TMedicacionesController.Existe(const ID: Integer): Boolean;
var
  AMedicacion : IBizMedicacion;
begin
  try
    AMedicacion := Buscar(ID);
    Result := Assigned(AMedicacion) and (AMedicacion.ID = ID);
  finally
    AMedicacion := NIL;
  end;
end;

function TMedicacionesController.ExtraerSeleccionados(AMedicacion: IBizMedicacion): IBizMedicacion;
var
  ASeleccionados : IBizMedicacion;
begin
  ASeleccionados := (Self.Buscar(ID_NULO) as IBizMedicacion);
  CopyDataTableDA5(AMedicacion.DataTable, ASeleccionados.DataTable, True);
  Result := ASeleccionados;
end;

procedure TMedicacionesController.SetPacienteController(const Value: IPacientesController);
begin
  FPacienteController := Value;
end;

procedure TMedicacionesController.SetDetallesController(const Value: IDetallesMedicacionController);
begin
  FDetallesController := Value;
end;

function TMedicacionesController.Guardar(AMedicacion: IBizMedicacion): Boolean;
begin
  Result := False;

  if not Assigned(AMedicacion) then
    raise Exception.Create ('Medicación no asignada');

  if not Assigned(FDetallesController) then
    raise Exception.Create ('Controller detalles no asignado');

  if ValidarMedicacion(AMedicacion) then
  begin
    ShowHourglassCursor;
    try
      AMedicacion.DataTable.ApplyUpdates;
      Result := True;
    finally
      HideHourglassCursor;
    end;
  end;
end;

function TMedicacionesController.Nuevo(withInsert: Boolean = True): IBizMedicacion;
var
  AMedicacion : IBizMedicacion;
begin
  AMedicacion := FDataModule.NewItem;
  AMedicacion.DataTable.Active := True;
  if WithInsert then
     AMedicacion.Insert;
  Result := AMedicacion;
end;

procedure TMedicacionesController.Preview(AMedicacion: IBizMedicacion; AllItems: Boolean = false);
var
  AReportController : IMedicacionesReportController;
  ID_Medicaciones: TIntegerList;

begin
  AReportController := TMedicacionesReportController.Create;
  ID_Medicaciones := TIntegerList.Create;

  try
   //Si deseamos previsualizar todos los items del objeto
   if AllItems then
   begin
     with AMedicacion.DataTable do
     begin
       First;
       while not EOF do
       begin
         ID_Medicaciones.Add(AMedicacion.ID);
         Next;
       end;
     end;
   end
   //Solo previsualizamos el item seleccionado
   else
     ID_Medicaciones.Add(AMedicacion.ID);

    AReportController.Preview(ID_Medicaciones);

  finally
    AReportController := NIL;
    FreeANDNIL(ID_Medicaciones);
  end;
end;

procedure TMedicacionesController.Print(AMedicacion: IBizMedicacion; AllItems: Boolean = false);
var
  AReportController : IMedicacionesReportController;
  ID_Medicaciones: TIntegerList;

begin
  AReportController := TMedicacionesReportController.Create;
  ID_Medicaciones := TIntegerList.Create;
  try
   //Si deseamos previsualizar todos los items del objeto
   if AllItems then
   begin
     with AMedicacion.DataTable do
     begin
       First;
       while not EOF do
       begin
         ID_Medicaciones.Add(AMedicacion.ID);
         Next;
       end;
     end;
   end
   //Solo previsualizamos el item seleccionado
   else
     ID_Medicaciones.Add(AMedicacion.ID);

    AReportController.Print(ID_Medicaciones);

  finally
    AReportController := NIL;
    FreeANDNIL(ID_Medicaciones);
  end;
end;

function TMedicacionesController.GetPacienteController: IPacientesController;
begin
  Result := FPacienteController;
end;

function TMedicacionesController.GetDetallesController: IDetallesMedicacionController;
begin
  Result := FDetallesController;
end;

end.
