unit uGNLBalance;

interface
uses
  ucosaparticipedemercado,
  uCosaConNombre;
type
  //Singleton
  TGNLBalance = class(TObject)

    private
      class procedure InicializarVolumen(CuentaCod:string;Volumen:double);
      class procedure CalculoAlpha(CuentaCod:string);
      class procedure CalculoVolumen(CuentaCod:string);

    public
      class procedure IncializarCronica(VolIni:double);
      class procedure InicializarPaso();
      class procedure CalculoCaudal(CuentaCod:string;SendOut:double);
      class procedure GuardarEmbarque(CuentaCod:string;VEmbarque:double);
      class procedure CalculoBalance();
      class procedure ImprimirBalance(var Impresor: TCosaParticipeDeMercado );
  end;

implementation
uses UGNLManejadorCuentas,Math,SysUtils;



{ TGNLBalance }

class procedure TGNLBalance.CalculoAlpha(CuentaCod: string);
var
   //Alpha que corresponde según la deuda (lo que devuelve es lo mínimo entre el alphaprima,alpha máxima acordada en el tica y 0)
   CuentaComplCod:string;
   VEmbarque,QPedidoEnPrestamo,QDadoEnPrestamo,SaldoPedidoEnPrestamo,SaldoDadoEnPrestamo:double;
   Alpha,AlphaTICA,AlphaPrima:double;
begin
   with TGNLManejadorCuentas.Create do begin

       VEmbarque := get_Item(CuentaCod,k_Concep_VEmb).Total;
       QPedidoEnPrestamo := get_Item(CuentaCod,k_Concep_QPres).Total;

       if VEmbarque=0 then begin //No tiene sentido calcular el alpha si no hay cargamento
          Alpha:=0;
          set_Valor(CuentaCod,k_Concep_Alpha,Alpha,false)
          end
       else begin
         AlphaTICA:= get_CuentaAlphaTica(CuentaCod);


         CuentaComplCod:=get_CuentaCodComplemento(CuentaCod);


         QDadoEnPrestamo := get_Item(CuentaComplCod,k_Concep_QPres).Total;

         SaldoPedidoEnPrestamo := get_Item(CuentaCod,k_Concep_SaldoPres).Total;
         SaldoDadoEnPrestamo := get_Item(CuentaComplCod,k_Concep_SaldoPres).Total;

         //Cálculo del Alpha correspondiente
         AlphaPrima:= (QPedidoEnPrestamo-QDadoEnPrestamo+SaldoPedidoEnPrestamo-SaldoDadoEnPrestamo)/VEmbarque;
         Alpha:=Min(AlphaTICA,AlphaPrima);
         Alpha:=Max(Alpha,0);
         set_Valor(CuentaCod,k_Concep_Alpha,Alpha,false);
       end;

       //Actualiza los saldos para que se sume lo calculado
       set_Valor(CuentaCod,k_Concep_SaldoPres,QPedidoEnPrestamo-(Alpha*VEmbarque),true);
   end;
end;

class procedure TGNLBalance.CalculoBalance;
var
   i:integer;
begin
   //********************************************************************************************************
   //Tomar las cuentas de algún lado no de aca*****************TODO*********CAMBIAR*********PABLO*********++
   //Posiblemente tenga que haber un actor cuenta que maneje las restricciones contractuales
   //*****************************************************************************************************+
   with TGNLManejadorCuentas.Create do begin
       for I := Low(Cuentas) to High(Cuentas) do
          TGNLBalance.CalculoAlpha(Cuentas[i].Codigo);
       for I := Low(Cuentas) to High(Cuentas) do
          TGNLBalance.CalculoVolumen(Cuentas[i].Codigo);
   end;

end;

class procedure TGNLBalance.CalculoCaudal(CuentaCod: string; SendOut: double);
var
   Vol_Ant:double;
begin
    //Según el volúmen anterior y el sendout de la cuenta, Calcula
    with TGNLManejadorCuentas.Create do begin
        Vol_Ant:=get_Item(CuentaCod,k_Concep_Vol).Total;
        set_Valor(CuentaCod,k_Concep_QProp,Min(Vol_Ant,SendOut),false);
        set_Valor(CuentaCod,k_Concep_QPres,-1*Min(0,Vol_Ant-SendOut),false);
    end;
end;

class procedure TGNLBalance.CalculoVolumen(CuentaCod: string);
var
  Vol,VolAnt,EmbProp,AlphaProp,EmbOtro,AlphaOtro,QProp,QOtroPrestamo:double;
begin

  with TGNLManejadorCuentas.Create do begin
      VolAnt:=get_Item(CuentaCod,k_Concep_Vol).Total;
      EmbProp := get_Item(CuentaCod,k_Concep_VEmb).Total;
      AlphaProp := get_Item(CuentaCod,k_Concep_Alpha).Total;
      QProp := get_Item(CuentaCod,k_Concep_QProp).Total;

      EmbOtro := get_Item(get_CuentaCodComplemento(CuentaCod),k_Concep_VEmb).Total;
      AlphaOtro := get_Item(get_CuentaCodComplemento(CuentaCod),k_Concep_Alpha).Total;
      QOtroPrestamo := get_Item(get_CuentaCodComplemento(CuentaCod),k_Concep_QPres).Total;

      Vol:=VolAnt + EmbProp*(1-AlphaProp) + EmbOtro*AlphaOtro -QProp - QOtroPrestamo;
      set_Valor(CuentaCod,k_Concep_Vol,Vol,false);
  end;
end;


class procedure TGNLBalance.GuardarEmbarque(CuentaCod: string;
  VEmbarque: double);
begin
   TGNLManejadorCuentas.Create().set_Valor(CuentaCod,k_Concep_VEmb,VEmbarque,false);
end;

class procedure TGNLBalance.ImprimirBalance(var Impresor: TCosaParticipeDeMercado);
var
   i:integer;
begin
   with TGNLManejadorCuentas.Create do begin
       //Crea los items de todas las cuentas si no existen y no los resetea, simplemente le suma 0
       for I := Low(Cuentas) to High(Cuentas) do begin
           set_Valor(Cuentas[i].Codigo,k_Concep_QProp,0,true);
           set_Valor(Cuentas[i].Codigo,k_Concep_QPres,0,true);
           set_Valor(Cuentas[i].Codigo,k_Concep_Vol,0,true);
           set_Valor(Cuentas[i].Codigo,k_Concep_Alpha,0,true);
           set_Valor(Cuentas[i].Codigo,k_Concep_VEmb,0,true);
           set_Valor(Cuentas[i].Codigo,k_Concep_SaldoPres,0,true);
       end;

       //Registra las variables que se van a imprimir
       ImprimirCuentas(Impresor);
   end;
end;


class procedure TGNLBalance.IncializarCronica(VolIni:double);
var
   i:integer;
begin
   with TGNLManejadorCuentas.Create do begin
       //********************************************************************************************************
       //Tomar las cuentas de algún lado no de aca*****************TODO*********CAMBIAR*********PABLO*********++
       //Posiblemente tenga que haber un actor cuenta que maneje las restricciones contractuales
       //*****************************************************************************************************+
       for I := Low(Cuentas) to High(Cuentas) do begin
           set_Valor(Cuentas[i].Codigo,k_Concep_QProp,0,false);
           set_Valor(Cuentas[i].Codigo,k_Concep_QPres,0,false);
           set_Valor(Cuentas[i].Codigo,k_Concep_Vol,0,false);
           set_Valor(Cuentas[i].Codigo,k_Concep_Alpha,0,false);
           set_Valor(Cuentas[i].Codigo,k_Concep_VEmb,0,false);
           set_Valor(Cuentas[i].Codigo,k_Concep_SaldoPres,0,false);
       end;
   end;
   self.InicializarVolumen('ARG',0);
   self.InicializarVolumen('URU',VolIni);
end;

class procedure TGNLBalance.InicializarPaso;
var
   i:integer;
begin
   with TGNLManejadorCuentas.Create do //resetea todo menos el saldo que volumen embalsado que es el único que no se resetea automaticamente
      for I := Low(Cuentas) to High(Cuentas) do begin
          set_Valor(Cuentas[i].Codigo,k_Concep_VEmb,0,false);
          set_Valor(Cuentas[i].Codigo,k_Concep_QProp,0,false);
          set_Valor(Cuentas[i].Codigo,k_Concep_QPres,0,false);
      end;

end;

class procedure TGNLBalance.InicializarVolumen(CuentaCod: string;
  Volumen: double);
begin
   //Inicializa el volumen anterior de la cuenta
   TGNLManejadorCuentas.Create().set_Valor(CuentaCod,k_Concep_Vol,Volumen,false);
end;

end.
