//====Modificado metodos: CreateDataColumnList y CreateDataConversionList===
//====Micho@25/5==mvarela@adme.com.uy=======================================
unit uGNLProveedor;

interface

uses
  Math, Classes, xMatDefs, uSimplex, uGlobs, uFechas, uEstados,
  uActores, uFichasLPD, uNodos,
  uGeneradores,
  uSuministroCombustible,
  uGNLSumIntermedio,
  uCosa,
  uFuentesAleatorias,
  uconstantesSimSEE, SysUtils;

type

  { TGNLFichaProveedor }

  TGNLFichaProveedor = class(TGNLFichaSumIntermedio)
  public
{
      T_ToP: NInt; // [dias] Tiempo de Take or Pay.
      V_ToP: NReal; // [unidad e Volumen] Volumen comprometido por el contrato Take Or Pay
      P_ToP: NReal; // [U$] Precio por Unidad de Volumen de combustible dentro del comprometido por Take or Pay
      P_ExtraToP: NReal; // [U$] Precio por Unidad de Volumen de combustible consumido por encima del volumen comprometido por Take or Pay
}
    constructor Create(fecha: TFecha; periodicidad: TPeriodicidad; nombrecombustible: string; indicePreciosPorCombustible: TFuenteAleatoria; bornePreciosPorCombustible: string);

     
    constructor Create_ReadFromText(f: TArchiTexto); override;
    procedure WriteToText(f: TArchiTexto); override;
    

    function infoAd_: string; override;
    procedure Free; override;

  end;

type

  { TGNLProveedor }

  TGNLProveedor = class(TGNLSumIntermedio)

  {
  Esta clase representará posibles suministros de combustible intermedio, suministros de
  combustibles simples, que ademas de conocer a su proveedor conocen a sus clientes
  }
  public

    pa: TGNLFichaProveedor;
    //Variables de Estado
    //VDisp_ToP_Ini: NReal;  //Volumen disponible de ToP (varia entre V_ToP y 0
    //Ndisc: NInt; //Cantidad de discretizaciones del volumen

    // El valor de la variable de estado X_V en el paso k y representa
    // el volumen restante (sin consumir) del contrato de ToP
    // vigente al inicio del paso  k.
    //Es lo que Tengo disponible en el tanque al inicio del paso
    //  (Xs_VDisp_ToP  es el estado al final del paso)
    //X_VDisp_ToP: NReal;
    //Xs_VDisp_ToP: NReal;

    // derivada del costo futuro respecto del Volumen Disponible ToP
    //dCFdV: NReal;

    //cvToP: NReal;  //Costo Variable del ToP (dCF/dV)
    //      cvExtraToP: NReal;  //Costo Variable de lo consumido por sobre del ToP
    //      cfToP: NReal;  //Costo Fijo del ToP (VToP * PTop)


    //Variables calculadas en el paso de tiempo durante la simulación
    //Volumen que despacho de combustible por debajo del disponible
    //en el paso de simulación (por lo tanto no aporta un costo extra al paso)
    //VConsumido_ToP: NReal;

    //Volumen que despacho de combustible por sobre el disponible.
    //En este caso aporto al paso un costo P_ExtraToP por cada unidad de combustible
    //VConsumido_Extra_Top :NReal;

    //Este es el volumen de combustible del ToP que se "tiró" al no ser consumido.
    //VSobrante_ToP: NReal;


    //V_ToP_sig: NReal;  //Volumen ToP del proximo embarque;

    fase: integer; // 1 = Inicio del TOP; 0= Dentro del periodo de TOP


    constructor Create(capa: integer; nombre: string; nombreCombustible: string; nacimiento, muerte: TFecha; lpdUnidades, lpd: TFichasLPD; cli: TSuministroCombustible); virtual;

     
    constructor Create_ReadFromText(f: TArchiTexto); override;
    procedure WriteToText(f: TArchiTexto); override;
    

    function get_ires_volumen: NInt; override;
    function get_precio_combustible: NReal; override;
    function get_combustible: TCombustibleSGE; override;
    //      function get_precio_combustible(cli: TSuministroCombustible):NReal; overload;

    class function TipoFichaLPD: TClaseDeFichaLPD; virtual; abstract;
    //      procedure sim_PrintResultados_Encab_PotFirme(var fsal: textfile; kencab: integer ); virtual;
    //      procedure sim_PrintResultados_PotFirme(var fsal: textfile); virtual;
    procedure Free; override;
    class function DescClase: string; override;


    //      procedure setCliente(cli: TSuministroCombustible);

    procedure PrepararMemoria(globs: TGlobs); override;
    procedure RegistrarParametrosDinamicos; override;


    procedure SorteosDelPaso(sortear: boolean); override;
    procedure PrepararPaso_ps; override;

    procedure Sim_Cronica_Inicio; override;

    procedure opt_nvers(var ivar, ivae, ires: integer); override;

    procedure opt_cargue(s: TSimplex); override;

    procedure EvolucionarEstado; override;

    procedure opt_fijarRestriccionesDeCaja(s: TSimplex); override;

    procedure opt_leerSolucion(s: TSimplex); override;

    function getNombreVar(ivar: integer; var nombre: string): boolean; override;
    function getNombreRes(ires: integer; var nombre: string): boolean; override;

    procedure PosicionarseEnEstrellita; override;
    procedure optx_nvxs(var ixr, ixd, iauxr, iauxd: integer); override;

    // imprime tabla de delta costo futuro de la variable de estado..
    procedure opt_PrintResultados_Encab(var fsal: textfile); override;
    procedure opt_PrintResultados(var fsal: textfile); override;

    procedure optx_RegistrarVariablesDeEstado(adminEstados: TAdminEstados); override;

    //      procedure Sim_PrintResultados_Encab(var fsal: textfile; kencab: integer ); override;
    //      procedure Sim_PrintResultados(var fsal: textfile); override;

    procedure PubliVars; override;
    //          function varsPSimRes3PorDefecto: TStringList; override;

    procedure AfterInstantiation; override;

  end;

procedure AlInicio;
procedure AlFinal;
procedure TGNLProveedor_cambioFichaPD(Actor: TCosa);
//procedure TGNLSumIntermedio_cambioFichaPD(Actor : TCosa);

implementation
//------------------------------
// Métodos de TFichaSuministroCombustible_TakeOrPay
//==============================
constructor TGNLFichaProveedor.Create(fecha: TFecha; periodicidad: TPeriodicidad; nombrecombustible: string; indicePreciosPorCombustible: TFuenteAleatoria; bornePreciosPorCombustible: string);

begin
  //  inherited Create(fecha, periodicidad, nombrecombustible, indicePreciosPorCombustible,bornePreciosPorCombustible);

end;

 
constructor TGNLFichaProveedor.Create_ReadFromText(f: TArchiTexto);
begin
  inherited Create_ReadFromText(f);
  f.IniciarLecturaRetrasada;
  f.EjecutarLectura;
end;

procedure TGNLFichaProveedor.WriteToText(f: TArchiTexto);
begin
  inherited WriteToText(f);
  //  f.wr('atrib1', atrib1);
  //  f.wr('V_ToP', V_ToP, uconstantesSimSEE.CF_PRECISION, uconstantesSimSEE.CF_DECIMALES);
end;



function TGNLFichaProveedor.infoAd_: string;
begin
  Result := inherited  infoAd_;
  //  result:= 'atrib1= ' + IntToStr(atrib1);
{
           'V_ToP= ' + FloatToStrF(V_ToP, ffGeneral, 10, 1) + ' ' + combustible.Unidades + ', ' +
           'P_ToP= ' + FloatToStrF(P_ToP, ffGeneral, 10, 1) + ' USD/' + combustible.Unidades + ', ' +
           'P_ExtraToP= ' + FloatToStrF(P_ExtraToP, ffGeneral, 10, 2) + ' USD/' +combustible.Unidades+', ';
}
end;

procedure TGNLFichaProveedor.Free;
begin
  inherited Free;
end;

//------------------------------
// Métodos de TSuministroCombustible_TakeOrPay
//==============================

constructor TGNLProveedor.Create(capa: integer; nombre: string; nombreCombustible: string; nacimiento, muerte: TFecha; lpdUnidades, lpd: TFichasLPD;
  //        VDisp_ToP_Ini : NReal; NDisc:NInt;
  cli: TSuministroCombustible);
begin
  //  inherited Create(nombre, nombreCombustible, nacimiento, muerte, lpdUnidades, lpd, VDisp_ToP_Ini, NDisc, cli);
  inherited Create(capa, nombre, nombreCombustible, nacimiento, muerte, lpdUnidades, lpd, cli);
end;

{
procedure TGNLSumContector.setCliente(cli: TSuministroCombustible);
begin
  inherited setCliente(cli);
end;
}
 
constructor TGNLProveedor.Create_ReadFromText(f: TArchiTexto);
begin
  inherited Create_ReadFromText(f);
  f.EjecutarLectura;
  pa := nil;
end;

procedure TGNLProveedor.WriteToText(f: TArchiTexto);
begin
  inherited WriteToText(f);
  //  f.wr('VDisp_ToP', VDisp_ToP_Ini);
  //  f.wr('NDisc', NDisc);
end;



procedure TGNLProveedor.PrepararMemoria(globs: TGlobs);
begin
  inherited prepararMemoria(globs);
end;


function TGNLProveedor.get_ires_volumen: NInt;
begin
  Result := self.ires;
end;

function TGNLProveedor.get_precio_combustible: NReal;
begin
{
  if (VConsumido_ToP > 0) and (VConsumido_Extra_Top = 0) then
     result := dCFdV
  else
    if (VConsumido_ToP > 0) and (VConsumido_Extra_Top > 0) then
        result := pa.P_ExtraToP
    else
      if (VConsumido_ToP = 0) and (VConsumido_Extra_Top > 0) then
         result := (dCFdV * VConsumido_ToP +  pa.P_ExtraToP * VConsumido_Extra_Top) / (VConsumido_ToP + VConsumido_Extra_Top)
}
  Result := 0;
end;


function TGNLProveedor.get_combustible: TCombustibleSGE;
begin
  Result := self.combustible;
end;

procedure TGNLProveedor.RegistrarParametrosDinamicos;
var
  i: integer;
  ficha: TGNLFichaSumIntermedio;
begin
  inherited registrarParametrosDinamicos;
  lpd.expandirFichas(globs);
  lpd.RegistrarFichasAActualizar(Self, globs.ActualizadorLPD, @pA, nil,
    TGNLProveedor_cambioFichaPD);
  for i := 0 to lpd.Count - 1 do
  begin
    ficha := TGNLFichaSumIntermedio(lpd[i]);
    if ficha.indicePreciosPorCombustible <> nil then
      ficha.nroBornePreciosPorCombustible :=
        ficha.indicePreciosPorCombustible.IdBorne(ficha.bornePreciosPorCombustible);
  end;
end;


procedure TGNLProveedor.Free;
begin
  inherited Free;
end;

class function TGNLProveedor.DescClase: string;
begin
  Result := 'Proveedor Intermedio de Combustible';
end;



procedure TGNLProveedor.SorteosDelPaso(sortear: boolean);
var
  fecha_ToP_ant: TDateTime;  //Fecha del ultimo embarque recibido (anterior al paso)
  fecha_ToP_sig: TDateTime;  //Fecha del siguiente embarque
  i, cntDias: integer;
  ficha: TGNLFichaSumIntermedio;
begin

  //Calculamos cuando fué el último embarque (más reciente) para la fecha de inicio del paso.
  //Esto puede dar la fecha de vigencia de la ficha (cuando comienza a reguir una ficha entra combustible)
  //o una fecha posterior tal que es múltiplo de T_ToP
  cntDias := Trunc(globs.FechaInicioDelpaso.dt) - Trunc(pa.Fecha.dt);
  //  cntDias :=  cntDias mod  pa.T_ToP;
  cntDias := 0;
  fecha_ToP_ant := globs.FechaInicioDelpaso.dt - cntDias;

  //Calculamos la siguiente fecha de ingreso de TakeOrPay y la hacemos igual a la fecha anterior + T dias
  //Si hay un cambio de ficha antes de esa fecha, colocamos como fecha del proximo ingreso la proxima fecha de vigencia
  //  fecha_ToP_sig := fecha_ToP_ant + pa.T_ToP;
  fecha_ToP_sig := fecha_ToP_ant;

  //Las Fechas de TOP corresponden a la hora 00:00:00

  //  V_ToP_sig := pa.V_ToP;

  //Ahora debemos detectar si hay una ficha que comienza a regir en el paso de simulación.
  //En este caso, en el paso no se actualiza el volumen, se consume todo lo que resta
  //y el volumen se actualizará al final del paso de tiempo
  for i := 0 to lpd.Count - 1 do
  begin
    ficha := TGNLFichaSumIntermedio(lpd[i]);
    if (ficha.fecha.dt > globs.FechaInicioDelpaso.dt) and
      (ficha.fecha.dt < globs.FechaFinDelpaso.dt) then
      if (fecha_ToP_sig > ficha.fecha.dt) then
      begin
        fecha_ToP_sig := ficha.fecha.dt;
        //           V_ToP_sig := ficha.V_ToP;
      end;
  end;


  //Ahora determinamos la fase en función de cuando ingreso el cargamento anterior y cuando ingresa el siguiente
  // no utilizo globs.FechaInicioDelpaso.dt porque tiene una hora menos!!!!!
  if (globs.FechaInicioDelpaso.dt <= fecha_ToP_sig) and
    ((globs.FechaInicioDelpaso.dt + globs.dt_DelPaso) >=
    fecha_ToP_sig) then
    //Atención: se pone globs.FechaFinDelPaso.dt > fecha_ToP_sig pues en caso de la igualdad
    //se toma en el inicio del siguiente paso.
    fase := 1     //En este paso de simulación ingresa un volumen T_ToP del contrato
  else
    fase := 0;     //En este paso de simulación no ingresa combustible

  //Si estamos en la fase 1, debemos actualizar el volumen disponible al final del paso
  //y el volumen restante lo ponemos como perdido
  //Si estamos en la fase 0, significa que tenemos un contrato vigente y estamos a la espera de un cargamento ToP

end;


procedure TGNLProveedor.PrepararPaso_ps;
begin

end;

procedure TGNLProveedor.opt_nvers(var ivar, ivae, ires: integer);
begin
  self.ivar := ivar; //CAntidad de variables (columnas)
  self.ires := ires;  //Cantidad de restricciones (filas)


  ivar := ivar + 2; // Columnas de VExtraTop y VConsumido_ToP
  ires := ires + 1;
  // 1 restricción. Luego los generadores deberán completar en sus columnas y en esta fila la restricción de volumen
end;

procedure TGNLProveedor.opt_cargue(s: TSimplex);
begin
{$IFDEF SPXCONLOG}
  spx_NombrarVariables(s);
{$ENDIF}

  //Restricción de balance de volumen (Sumatoria de lo consumido por las maquinas - VExtraTop - VConsumitoTop debe ser igual a 0
  s.pon_e(ires, ivar, -1);
  s.pon_e(ires, ivar + 1, -1);

  //Aporte a la función de Costo
  //s.pon_e( s.nf, ivar , -cvExtraToP);
  //  s.pon_e( s.nf, ivar+1 , -cvToP);

  //Termino independiente (vale o o Vtop*Ptop)
  //s.acum_e( s.nf, s.nc, -cfToP);

  //Cada uno de los generadores conectados debe ser responsable de cargar sus
  //columnas en la restricción de volumen  y en la función de costo objetivo

end;

procedure TGNLProveedor.Sim_Cronica_Inicio;
begin
  inherited Sim_Cronica_Inicio;
end;

procedure TGNLProveedor.opt_fijarRestriccionesDeCaja(s: TSimplex);
var
  iposte: integer;
begin

  s.FijarRestriccionIgualdad(ires);

  //Agregamos la restricción de caja que dice que el  0 <= VConsumidoToP >= VDisponibleTop
  //  s.cota_sup_set( ivar+1, X_VDisp_ToP );
end;

procedure TGNLProveedor.opt_leerSolucion(s: TSimplex);
begin

  //self.VConsumido_Extra_Top :=  s.xval(ivar);
  //self.VConsumido_ToP := s.xval(ivar + 1);
  //Calculo del costo directo del paso y actualizo el estado al final del paso

  //Costo Fijo mas variable. El fijo es 0 si no estoy fecha de renovación de contrato, o VTop*PTop
  //y cvExtraTop es el Volumen Extra por el Precio extra Top (esto ya se calculo al preparar el paso)

  //    CostoDirectoDelPaso:= cfToP + cvExtraToP * self.VConsumido_Extra_Top;
  CostoDirectoDelPaso := 0;

end;

procedure TGNLProveedor.EvolucionarEstado;
begin
end;

function TGNLProveedor.getNombreVar(ivar: integer; var nombre: string): boolean;
begin
  if (ivar = self.ivar) then
  begin
    nombre := self.Nombre + '_V_Extra_ToP[' + pa.combustible.Unidades + ']';
    Result := True;
  end
  else
  if (ivar = self.ivar + 1) then
  begin
    nombre := self.Nombre + '_V_Consumido_ToP[' + pa.combustible.Unidades + ']';
    Result := True;
  end
  else
    Result := False;
end;

function TGNLProveedor.getNombreRes(ires: integer; var nombre: string): boolean;
begin
  if (ires = self.ires) then
  begin
    nombre := self.nombre + '_VolumenDepachado = Consumo de las maquinas';
    Result := True;
  end
  else
    Result := False;
end;

procedure TGNLProveedor.PubliVars;
var
  unidades: string;
  ficha: TGNLFichaSumIntermedio;
  i: NInt;
begin
  inherited PubliVars;

  unidades := self.combustible.Unidades;

  PublicarVariableNR('Costo_Directo_Paso', '[USD]', 6, 1, CostoDirectoDelPaso, True);
  //  PublicarVariableNR('CV_combustible','[USD/'+ unidades +']',6,1,self.dCFdV, true);
{
  PublicarVariableNR('V_Consumido_ToP', '['+unidades+']', 6, 1, self.VConsumido_ToP);
  PublicarVariableNR('V_Consumid_Extra_ToP', '['+unidades+']', 6, 1, self.VConsumido_Extra_Top);
  PublicarVariableNR('V_Sobrante_ToP', '['+unidades+']', 6, 1, self.VSobrante_ToP);
  PublicarVariableNR('V Disponible_ToP', '['+unidades+']', 6, 1, self.X_VDisp_ToP);
 }
  PublicarVariableNI('Fase', '-', fase, True);
end;

procedure TGNLProveedor.AfterInstantiation;
begin
  inherited AfterInstantiation;
  pa := nil;
end;

{
function TGNLProveedor.varsPSimRes3PorDefecto: TStringList;
var
  res: TStringList;
begin
  res:= inherited varsPSimRes3PorDefecto;

  res.Add('Costo_Directo_Paso');
  res.Add('CV_combustible');
  res.Add('V_Consumido_ToP');
  res.Add('V_Consumido_Extra_ToP');
  res.Add('V_Sobrante_ToP');
  res.Add('V_Disponible_ToP');
  res.Add('Fase');

  result:= res;
end;
}

procedure TGNLProveedor.optx_nvxs(var ixr, ixd, iauxr, iauxd: integer);
begin
  self.ixr := ixr;
  ixr := ixr + 1;
end;

procedure TGNLProveedor.PosicionarseEnEstrellita;
begin
end;


procedure TGNLProveedor.optx_RegistrarVariablesDeEstado(adminEstados: TAdminEstados);
begin
end;


procedure TGNLProveedor.opt_PrintResultados_Encab(var fsal: textfile);
begin
  //  write( fsal, #9, FloatToStrF( X_VDisp_ToP,ffgeneral, 6,3 ));
end;

procedure TGNLProveedor.opt_PrintResultados(var fsal: textfile);
begin
  //  write( fsal, #9, FloatToStrF( dCFdV, ffgeneral, 6,3 ) );
end;


procedure TGNLProveedor_cambioFichaPD(Actor: TCosa);
begin
end;

procedure AlInicio;
begin
  registrarClaseDeCosa(TGNLProveedor.ClassName, TGNLProveedor);
  registrarClaseDeCosa(TGNLFichaProveedor.ClassName, TGNLFichaProveedor);
end;

procedure AlFinal;
begin
end;

end.
