//Intento de Modificado metodos: CreateDataColumnList y CreateDataConversionList
(*se deja para terminar más adelante, la forma de lectura actual de la agenda
lee un parametro 'AgendasActivas' que setea agCount que es el largo de otra lectura*)
//====Micho@29/5==mvarela@adme.com.uy=======================================
unit uGNLSumComb_TakeOrPay_Spot;

interface

uses
  ucosaparticipedemercado,
  Math, xMatDefs, uSimplex, uGlobs, uFechas, uEstados, Classes,
  uActores, uFichasLPD, uNodos,
  uGeneradores,
  uSuministroCombustible,
  uCosa,
  uFuentesAleatorias,
  uFuncionesRealesExtra,
  uconstantesSimSEE, SysUtils,
  uConversions,
  uAgenda;

const
  k_TiempoViaje = 15;

const
  K_TotHorasDescarga = 48;

const
  K_Resto = 21000;
//Es el resto de gas que puede quedar en el tanque que se ventea cuando llega un cargamento y no entra.

type

  { TGNLFichaSumComb_TakeOrPay_Spot }

  TGNLFichaSumComb_TakeOrPay_Spot = class(TFichaSuministroCombustible)
  public
    T_ToP: NInt; // [dias] Tiempo de Take or Pay.
    //      DiasIngresoEmbarques : TDAOfNInt; //En el caso de que los embarques no sean periódicos,
    //indica los días desde el comienzo de la ficha en que ingresan embarques.
    //      CuentasEmbarques : TDAOfNInt; //Cuentas que pertenecen a cada embarque
    //      sCuentasEmbarques : TDAofString; //Cuentas que pertenecen a cada embarque URU;ARG; etc.


    EmbarquesPeriodicos: boolean; //Indica si los embarques son periódicos o no.

    V_ToP: NReal; // [unidad e Volumen] Volumen comprometido por el contrato Take Or Pay
    V_Efectivo: NReal; // [unidad e Volumen] Volumen efectivo que me pertenece

    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
    //V_Spot: TDAOfNReal; // Volumenes posibles en los cargo de compra SPOT (120, 140, etc)
    C_Min: NReal; // [unidad e Volumen/h] Caudal mínimo del suministro
    C_Max: NReal; // [unidad de Caudal] Caudal máximo del suministro

    T_Max_Espera: NInt;
    //[dias] Tiempo máximo de espera de un cargamento luego de su arribo.

    P_Spot: NReal;
    // [U$] Precio por Unidad de Volumen de combustible dentro del comprometido por Spot
    P_Venta: NReal;
    // [U$] Precio por Unidad de Volumen de combustible dentro del cargamento que es Vendido
    P_Espera: NReal; // [U$] Costo por día de barco en espera


    indicePreciosSpotPorCombustible: TFuenteAleatoria;
    //Para ajustar los precios de combustible en los períodos Spot
    bornePreciosSpotPorCombustible: string;
    nroBorneSpotPreciosPorCombustible: integer;

    indicePreciosVentaPorCombustible: TFuenteAleatoria;
    //Para ajustar los precios de combustible en los períodos Spot
    bornePreciosVentaPorCombustible: string;
    nroBorneVentaPreciosPorCombustible: integer;

    operatividadRegasificacion: TFuenteAleatoria;
    //Para calcular la operatividad de regasificación
    borneOperatividadRegasificacion: string;
    nroBorneOperatividadRegasificacion: integer;

    operatividadDescarga: TFuenteAleatoria;
    //Para calcular la operatividad de regasificación
    borneOperatividadDescarga: string;
    nroBorneOperatividadDescarga: integer;
    limites_postizados: boolean;
    manejoBOG: boolean;
    K_BOG: NReal; // K_BOG: Porcentaje de volumen del tanque que se evapora en BOG
    K_GSS: NReal;
    // K_GSS: Volumen de GN en m3 requerido por la planta para operar, incluso si no esta emitiendo gas
    K_RG: NReal;
    // K_RG: Porcentaje de GN que se debe utilizar para regasificar una unidad de GNL
    K_RC: NReal;
    // K_RC: Porcentaje de BOG que se puede recondensar cuando la planta emite gas una unidad de GN
    K_RL: NReal;
    // K_RL: Ratio de BOG que se puede relicuar sobre BOG que se utiliza en el proceso de relicuado (relicuado + utilizado para dar energía al proceso)
    Relicuado: boolean; // indica si se tiene una planta de relicuado

    CanonAnual: NReal;
    //Canon anual que incluye los gastos fijos de la planta de regasificación

    opRegasAsig: boolean;
    bornesPorcOpRegasificacion: TDAOfNInt;
    // Vector de valores de 0 a 1 Porcentaje del tiempo del paso que estuvo disponible por operabilidad la planta para regasificar

    agendas: TListaDeCosas;
    fechasCambioAgenda: array of TDateTime;
    currCambioFecha: integer;
    FechaAntPCA: TDateTime;

    //      agenda: TAgendaEmbarque;

    agPerturbacionDias: TFuenteAleatoria;
    agBornePerturbacionDias: string;
    agNroBornePerturbacionDias: integer;


    constructor Create(fecha: TFecha; periodicidad: TPeriodicidad; nombrecombustible: string; T_ToP: NInt; V_ToP: NReal; P_ToP: NReal; P_Espera: NReal;
    //                  V_Spot: TDAOfNReal;
      P_Spot: NReal; C_Min: NReal; C_Max: NReal; limitePorPoste: boolean; P_Venta: NReal; T_Max_Espera: NInt; EmbarquesPeriodicos: boolean; strDiasIngresoEmbarques: string; lstStrAgendas: array of string; strCuentasEmbarques: string; indicePreciosPorCombustible: TFuenteAleatoria; bornePreciosPorCombustible: string; indicePreciosSpotPorCombustible: TFuenteAleatoria; bornePreciosSpotPorCombustible: string; indicePreciosVentaPorCombustible: TFuenteAleatoria; bornePreciosVentaPorCombustible: string; operatividadRegasificacion: TFuenteAleatoria; borneOperatividadRegasificacion: string; operatividadDescarga: TFuenteAleatoria; borneoperatividadDescarga: string; manejoBOG: boolean; K_BOG: NReal; K_GSS: NReal; K_RG: NReal; K_RC: NReal; K_RL: NReal; Relicuado: boolean; CanonAnual: NReal; agPerturbacionDias: TFuenteAleatoria; agBornePerturbacionDias: string; fechasCambioAgenda: string);
    constructor Create_ReadFromText(f: TArchiTexto); override;
    procedure WriteToText(f: TArchiTexto); override;

    //      function GetStrDiasIngresoEmbarques(): String;

    function GetStrDiasIngresoEmbarques_i(i: integer): string;


    function hayCuentasEmbarques(): boolean;
    function getFechaCambioAgenda(): string;
    function validArrayCambioFechas(fechasCambioAgenda: string): boolean;

    function GetFechaSiguienteToP(fechaActual: TDateTime; agActiva: integer; var sCuenta: string; globs: TGlobs): TDateTime;

    function GetSiguienteCambioAgenda(fechaActual: TDateTime): TDateTime;


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

    class function CreateDataColumnList(xVersion: integer = -2): TDataColumnListOfCosa; override;
  end;

type

  { TGNLSumComb_TakeOrPay_Spot }

  TGNLSumComb_TakeOrPay_Spot = class(TSuministroCombustible)

  (*
  Esta clase representará posibles suministros de combustible para
  los generadores termicos
  *)
  private
    //f : textfile;
    CostoEspera: double; //Costo espera incurrido cuando llega un cargamento
    Venta: double; //Ganancia por venta de cargamento cuando es desviado
    CostoCompra: double; //Costo por compra de combustible
    DiasEspera: double; //Horas de espera
    bLlegadaSpot: integer; //Indica si llego un spot
    bVentaSpot: integer; //Indica si se vendio un spot
    bEntradaSpot: integer; //Indica que entro un cargamento de Spot
    bVentaTop: integer; //Indica si se vendio un ToP
    bEntradaTop: integer; //Indica que entro un cargamento de ToP
    CuentaSiguienteTop: string;
    //si llega un cargamento en el paso de tiempo tiene el nro de cuenta de ese cargamento
    PrecioSpot: NReal;
    PrecioTOP: NReal;
    VolumenSpot: NReal;
    VolumenTOP: NReal;
    VolFaltaAncap: NReal;
    VolQuemado: NReal;
    bQuemo: integer;


    ixd_rechazoEmbarques: integer;

    saltearCargamento: boolean;


    function CantVCons: integer;
    class function CreateDataConversionList: TListDataConversion;
    //Indica la cantidad de variables de control que pone para VConsumido sin contar VTotal
    function MaxEstadoSpot: NInt; //Último estado de
    function NDiscDiasSpot: NInt;
    procedure ArriboDeCargamentoSpot;
    function CalculoCostoEsperaParcial(FechaArribo: TDateTime; Volumen: NReal; var Vender: boolean): double;
    function InterpolacionLineal(x, x1, x2, y1, y2: double): double;
    function AjusteCostoVariableXArribo(CostoVariable: double; V_Cargamento: double; FechaProxArribo: TDateTime): double;
    function CalculoFechaArriboSpot: TDateTime;
    function IncSpot: double;
    function PasoTiempoSpotHoras: double;
    function VentaSpot: double;
    function VentaCombustible(Volumen: double; cvCargamento: double): double;
    function VentaToP: double;

    function k_ResFVConsTot: integer;
    //Devuelve el indice de la fila con la restricción de -VConsPoste1-..-VConsPosteN+VConsTotal=0
    function k_VarCVConsTot: integer; //Devuelve el indice de la columna de VConsTotal;
    function k_VarCCompra: integer;
    //Devuelve el indice de la columna de SuministroCompra;
    function k_VarCRetraso: integer;
    function MaxSendOut(poste: integer): double;
    //Devuelve el indice de la columna de SuministroRetraso;

    function maxAgendas: integer;

  



















  public

     
    CV_Fijado: NReal;
    B_FavorecerDescarga: boolean;
    //Indica si se debe bajar el costo a 0 si el cargamento está llegando y no hay espacio en el tanque
    B_CostoVariableCero: boolean;
    //Indica si tiene que ponerle costo 0 al combuistible o el variable (derivada del CF respecto al volumen en el tanque)
    hayRechazoEmbarques: boolean; //Indica si se considera el rechazo de embarques ToP
    V_Max: NReal; // [unidad e Volumen] Volumen máximo del tanque
    V_Spot: TDAOfNReal;
    // Volumenes posibles en los cargo de compra SPOT (120, 140, etc)
    T_Ini_Spot: TDAofNInt; // Días de Arribo SPOT (120, 140, etc)
    T_Arribo: NInt; //[días] días necesarios para encargar un cargamento al Spot
    //Variables de Estado
    VDisp_Ini: NReal;  //Volumen disponible de ToP (varia entre V_ToP y 0
    NDisc: NInt; //Cantidad de discretizaciones del volumen
    //Variable de estado que indica que dentro de n dias arriba un cargamento.
    NDiscSpot: NInt;
    

    agendaActiva: integer;
    pa: TGNLFichaSumComb_TakeOrPay_Spot;
    CostoDelSuministro: NReal;
    //OpeRegasifPrint: TDAOfNReal; // Variable para imprimir la operabilidad de regasificaqcion
    OpeDescargaPrint: NReal; //Variable para imprimir la operabilidad de descarga




    //Variable de estado que indica que dentro de n dias arriba un cargamento.
    VCnt_Next_Spot_Ini: NReal;  //Inicialización


    X_VCnt_Next_Spot: NReal;    //Cantidad de Días para el próximo cargamento
    Xs_VCnt_Next_Spot: NReal;

    // 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;

    BOG_T, BOG_GSS, BOG_RG, BOG_RC, BOG_RL, BOG_GRL, BOG_Vent, BSO: NReal;


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

    //POR PABLO
    //cvExtraToP: NReal;  //Costo Variable de lo consumido por sobre del ToP

    //POR PABLO
    cvSpot: NReal;
    cvVenta: NReal;


    cvToP: NReal;  //Costo Variable del ToP (dCF/dV)
    cfToP: NReal;  //Costo Fijo del ToP (VToP * PTop)

    EmbarquesPeriodicos: boolean;

    //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;

    //La anterior ya no se utiliza mas....
    ComprarCargamento: NReal;
    RetrasarCargamento: 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;
    V_Efectivo_sig: NReal; // [unidad e Volumen] Volumen efectivo que me pertenece

    fecha_ToP_sig: TDateTime;  //Fecha del siguiente embarque

    fecha_Spot_sig: TDateTime;
    //fecha del próximo spot o si no se espera devuelve la fecha máxima

    fase: integer; // 1 = Inicio del TOP; 0= Dentro del periodo de TOP
    entrada: integer;
    Espera: integer;
    CanonFijoXPaso: double; // Canon fijo calculado para el paso

    V_ProxCargamento: NReal; //Volumen del próximo cargamento;
    F_Arribo: TDateTime;     //Fecha del próximo arribo;

    OpTiempoDescarga: integer;
    //Tiempo en horas que tarda en descargar un barco teniendo en cuenta la operabilidad

    //      opRegasAsig: boolean;
    PorcOpRegasificacion: TDAOfNReal;
    // Vector de valores de 0 a 1 Porcentaje del tiempo del paso que estuvo disponible por operabilidad la planta para regasificar




    constructor Create(nombre: string; nombreCombustible: string; nacimiento, muerte: TFecha; lpdUnidades, lpd: TFichasLPD; VDisp_Ini: NReal; NDisc: NInt; V_Spot: TDAOfNReal; NDiscSpot: NInt; T_Ini_Spot: TDAOfNInt; TArribo: NInt; V_Max: NReal; B_FavorecerDescarga: boolean; B_CostoVariableCero: boolean; CV_Fijado: NReal; B_HayRechazoEmbarque: boolean); virtual;



    constructor Create_ReadFromText(f: TArchiTexto); override;
    function get_VolCombustibleDisponible: NReal; override;
    procedure InicializarVariables;
    procedure WriteToText(f: TArchiTexto); override;

    function get_ires_volumen: NInt; override;
    function get_precio_combustible: NReal; override;
    function get_combustible: TCombustibleSGE; override;

    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 PrepararMemoria(globs: TGlobs); override;

    function restricciones_postizadas: boolean; 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 Sim_Paso_Fin; 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 ActualizarEstadoGlobal; 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;

    class function CreateDataColumnList(xVersion: integer = -2): TDataColumnListOfCosa; override;
    procedure AfterInstantiation; override;

  














  end;

procedure AlInicio;
procedure AlFinal;
procedure TGNLSumComb_TakeOrPay_Spot_cambioFichaPD(Actor: TCosa);

implementation

uses DateUtils, UCosaConNombre, UGNLBalance;

//------------------------------
// Métodos de TGNLFichaSumComb_TakeOrPay_Spot
//==============================
constructor TGNLFichaSumComb_TakeOrPay_Spot.Create(fecha: TFecha; periodicidad: TPeriodicidad; nombrecombustible: string; T_ToP: NInt; V_ToP: NReal; P_ToP: NReal; P_Espera: NReal;
  //                                                V_Spot: TDAOfNReal;
  P_Spot: NReal; C_Min: NReal; C_Max: NReal; limitePorPoste: boolean; P_Venta: NReal; T_Max_Espera: NInt; EmbarquesPeriodicos: boolean; strDiasIngresoEmbarques: string; lstStrAgendas: array of string; strCuentasEmbarques: string; indicePreciosPorCombustible: TFuenteAleatoria; bornePreciosPorCombustible: string; indicePreciosSpotPorCombustible: TFuenteAleatoria; bornePreciosSpotPorCombustible: string; indicePreciosVentaPorCombustible: TFuenteAleatoria; bornePreciosVentaPorCombustible: string; operatividadRegasificacion: TFuenteAleatoria; borneOperatividadRegasificacion: string; operatividadDescarga: TFuenteAleatoria; borneoperatividadDescarga: string; manejoBOG: boolean; K_BOG: NReal; K_GSS: NReal; K_RG: NReal; K_RC: NReal; K_RL: NReal; Relicuado: boolean; CanonAnual: NReal; agPerturbacionDias: TFuenteAleatoria; agBornePerturbacionDias: string; fechasCambioAgenda: string);

var
  i: integer;
  s: string;
  strLstFCAg: TStringList;
begin
  inherited Create(fecha, periodicidad, nombrecombustible,
    indicePreciosPorCombustible, bornePreciosPorCombustible);

  self.T_ToP := T_ToP;
  self.V_ToP := V_ToP;
  self.P_ToP := P_ToP;
  self.P_Espera := P_Espera;
  self.P_Venta := P_Venta;
  self.T_Max_Espera := T_Max_Espera;
  // self.V_Spot:=V_Spot;
  self.P_Spot := P_Spot;
  self.C_Min := C_Min;
  self.C_Max := C_Max;
  self.limites_postizados := limitePorPoste;
  self.EmbarquesPeriodicos := EmbarquesPeriodicos;
  //  self.DiasIngresoEmbarques := StrToDAOfNInt_(strDiasIngresoEmbarques, ';');
  //self.CuentasEmbarques := StrToDAOfNInt_(strCuentasEmbarques,';');
  //  self.sCuentasEmbarques := StrToDAOfStr_(strCuentasEmbarques,';');
  self.indicePreciosSpotPorCombustible := indicePreciosSpotPorCombustible;
  self.bornePreciosSpotPorCombustible := bornePreciosSpotPorCombustible;
  self.indicePreciosVentaPorCombustible := indicePreciosVentaPorCombustible;
  self.bornePreciosVentaPorCombustible := bornePreciosVentaPorCombustible;
  self.operatividadRegasificacion := operatividadRegasificacion;
  self.borneoperatividadRegasificacion := borneoperatividadRegasificacion;
  self.operatividadDescarga := operatividadDescarga;
  self.borneoperatividadDescarga := borneoperatividadDescarga;
  self.manejoBOG := manejoBOG;
  self.K_BOG := K_BOG;
  self.K_GSS := K_GSS;
  self.K_RG := K_RG;
  self.K_RC := K_RC;
  self.K_RL := K_RL;
  self.Relicuado := Relicuado;
  self.CanonAnual := CanonAnual;
  self.opRegasAsig := False;

  //  self.agenda:= TAgendaEmbarque.Create(fecha, self.T_ToP, self.V_ToP, self.P_ToP, self.EmbarquesPeriodicos, strDiasIngresoEmbarques);

  self.agendas := TListaDeCosas.Create('agendas');

  for i := 0 to length(lstStrAgendas) - 1 do
  begin
    s := lstStrAgendas[i];
    self.agendas.Add(TAgendaEmbarque.Create(fecha, self.T_ToP,
      self.V_ToP, self.P_ToP, self.EmbarquesPeriodicos, s));
  end;

  self.agPerturbacionDias := agPerturbacionDias;
  self.agBornePerturbacionDias := agBornePerturbacionDias;

  //  setLength(self.fechasCambioAgenda, length(fechasCambioAgenda));

  strLstFCAg := TStringList.Create;
  strLstFCAg.Delimiter := ';';
  strLstFCAg.DelimitedText := fechasCambioAgenda;
  setlength(self.fechasCambioAgenda, strLstFCAg.Count);

  for i := 0 to strLstFCAg.Count - 1 do
  begin
    self.fechasCambioAgenda[i] := strToDate(strLstFCAg[i]);
  end;
  currCambioFecha := 0;
  FechaAntPCA := self.fecha.dt;
end;

constructor TGNLFichaSumComb_TakeOrPay_Spot.Create_ReadFromText(f: TArchiTexto);
var
  strDiasIngresoEmbarques, strFechaCambioAgenda, strCuentasEmbarques: string;
  i, agCount: integer;
  ag: TAgendaEmbarque;
  strLstFCAg: TStringList;
begin
  if f.version < 44 then
  begin
    inherited Create_ReadFromText(f);
    f.IniciarLecturaRetrasada;
    f.rd('T_ToP', T_ToP);
    f.rd('V_ToP', V_ToP);
    f.rd('P_ToP', P_ToP);
    f.rd('P_Espera', P_Espera);
    f.rd('P_Spot', P_Spot);
    f.rdReferencia('indicePreciosSpotPorCombustible',
      TCosa(indicePreciosSpotPorCombustible), self);
    f.rd('bornePreciosSpotPorCombustible', bornePreciosSpotPorCombustible);
    f.EjecutarLectura;

    EmbarquesPeriodicos := True;
    //    setlength(DiasIngresoEmbarques, 0);
    //setlength(CuentasEmbarques,0);
    //    setlength(sCuentasEmbarques,0);
    self.C_Min := -1;
    self.C_Max := -1;
    self.limites_postizados := False;
    self.manejoBOG := False;
    self.K_BOG := 0;
    self.K_GSS := 0;
    self.K_RG := 0;
    self.K_RC := 0;
    self.K_RL := 0;
    self.Relicuado := False;
    self.opRegasAsig := False;
    //    self.agenda:= TAgendaEmbarque.Create(fecha, self.T_ToP, self.V_ToP, self.P_ToP, self.EmbarquesPeriodicos, '');
    ag := TAgendaEmbarque.Create(fecha, self.T_ToP, self.V_ToP, self.P_ToP,
      self.EmbarquesPeriodicos, '');
    //      agendas.insert(i-1, ag);
    agendas := TListaDeCosas.Create('agendas');
    agendas.insert(0, ag);

    self.agPerturbacionDias := nil;
    self.agBornePerturbacionDias := '';

  end
  else if f.version < 45 then
  begin
    inherited Create_ReadFromText(f);
    f.IniciarLecturaRetrasada;
    f.rd('T_ToP', T_ToP);
    f.rd('V_ToP', V_ToP);
    f.rd('P_ToP', P_ToP);
    f.rd('P_Espera', P_Espera);
    f.rd('P_Spot', P_Spot);
    f.rdReferencia('indicePreciosSpotPorCombustible',
      TCosa(indicePreciosSpotPorCombustible), self);
    f.rd('bornePreciosSpotPorCombustible', bornePreciosSpotPorCombustible);
    f.rd('EmbarquesPeriodicos', EmbarquesPeriodicos);
    f.rd('DiasIngresoEmbarques', strDiasIngresoEmbarques);
    f.rd('CuentasEmbarques', strCuentasEmbarques);
    f.EjecutarLectura;

    //    self.DiasIngresoEmbarques := StrToDAOfNInt_(strDiasIngresoEmbarques, ';');
    //    self.agenda:= TAgendaEmbarque.Create(fecha, self.T_ToP, self.V_ToP, self.P_ToP, self.EmbarquesPeriodicos, strDiasIngresoEmbarques);
    ag := TAgendaEmbarque.Create(fecha, self.T_ToP, self.V_ToP, self.P_ToP,
      self.EmbarquesPeriodicos, strDiasIngresoEmbarques);
    //      agendas.insert(i-1, ag);
    agendas := TListaDeCosas.Create('agendas');
    agendas.insert(0, ag);
    //self.CuentasEmbarques := StrToDAOfNInt_(strCuentasEmbarques,';');
    //    self.sCuentasEmbarques := StrToDAOfStr_(strCuentasEmbarques,';');
    self.C_Min := -1;
    self.C_Max := -1;
    self.limites_postizados := False;
    self.manejoBOG := False;
    self.K_BOG := 0;
    self.K_GSS := 0;
    self.K_RG := 0;
    self.K_RC := 0;
    self.K_RL := 0;
    self.Relicuado := False;
    self.opRegasAsig := False;
    self.agPerturbacionDias := nil;
    self.agBornePerturbacionDias := '';
  end
  else
  begin
    inherited Create_ReadFromText(f);
    f.IniciarLecturaRetrasada;
    f.rd('T_ToP', T_ToP);
    f.rd('V_ToP', V_ToP);
    f.rd('P_ToP', P_ToP);
    f.rd('P_Espera', P_Espera);
    f.rd('P_Spot', P_Spot);
    f.rdReferencia('indicePreciosSpotPorCombustible',
      TCosa(indicePreciosSpotPorCombustible), self);
    f.rd('bornePreciosSpotPorCombustible', bornePreciosSpotPorCombustible);
    f.rdReferencia('indicePreciosVentaPorCombustible',
      TCosa(indicePreciosVentaPorCombustible), self);
    f.rd('bornePreciosVentaPorCombustible', bornePreciosVentaPorCombustible);
    f.rdReferencia('operatividadRegasificacion',
      TCosa(operatividadRegasificacion), self);
    f.rd('borneOperatividadRegasificacion', borneOperatividadRegasificacion);
    f.rdReferencia('operatividadDescarga', TCosa(operatividadDescarga), self);
    f.rd('borneOperatividadDescarga', borneOperatividadDescarga);
    f.rd('EmbarquesPeriodicos', EmbarquesPeriodicos);

    begin
      agCount := 0;
      agendas := TListaDeCosas.Create('agendas');
      f.rd('AgendasActivas', agCount);

      f.EjecutarLectura;

      for i := 0 to agCount - 1 do
      begin
        strDiasIngresoEmbarques := '';
        f.rd('DiasIngresoEmbarques_' + IntToStr(i), strDiasIngresoEmbarques);
        f.EjecutarLectura;
        ag := TAgendaEmbarque.Create(fecha, self.T_ToP, self.V_ToP,
          self.P_ToP, self.EmbarquesPeriodicos, strDiasIngresoEmbarques);
        //      agendas.insert(i-1, ag);
        agendas.insert(i, ag);
      end;

      strFechaCambioAgenda := '';
      f.rd('FechasCambioAgenda', strFechaCambioAgenda);
      f.EjecutarLectura;
      strLstFCAg := TStringList.Create;
      strLstFCAg.Delimiter := ';';
      strLstFCAg.DelimitedText := strFechaCambioAgenda;
      setlength(fechasCambioAgenda, strLstFCAg.Count);

      for i := 0 to strLstFCAg.Count - 1 do
      begin
        self.fechasCambioAgenda[i] := strToDate(strLstFCAg[i]);
      end;
    end;

    f.rd('C_Min', C_Min);
    f.rd('C_Max', C_Max);
    f.rd('P_Venta', P_Venta);
    f.rd('T_Max_Espera', T_Max_Espera);

    f.rd('Limites_Postizados', limites_postizados);
    f.rd('Manejo_BOG', manejoBOG);
    f.rd('BOG_hora', K_BOG);
    f.rd('Servicios_generales', K_GSS);
    f.rd('RG_por_emision', K_RG);
    f.rd('BOG_Recondensado', K_RC);
    f.rd('Ratio_RL', K_RL);
    f.rd('Hay_Relicuado', Relicuado);
    f.rd('CanonAnual', CanonAnual);
    f.rdReferencia('agPerturbacionDias', TCosa(agPerturbacionDias), self);
    f.rd('agBornePerturbacionDias', agBornePerturbacionDias);
    f.EjecutarLectura;

    //    self.DiasIngresoEmbarques := StrToDAOfNInt_(strDiasIngresoEmbarques, ';');
    //self.CuentasEmbarques := StrToDAOfNInt_(strCuentasEmbarques,';');
    //    self.agenda:= TAgendaEmbarque.Create(fecha, self.T_ToP, self.V_ToP, self.P_ToP, self.EmbarquesPeriodicos, strDiasIngresoEmbarques);
    //    self.sCuentasEmbarques := StrToDAOfStr_(strCuentasEmbarques,';');
    self.opRegasAsig := False;
  end;
  currCambioFecha := 0;
  FechaAntPCA := self.fecha.dt;
end;

procedure TGNLFichaSumComb_TakeOrPay_Spot.WriteToText(f: TArchiTexto);
var
  i: integer;
  ag: TAgendaEmbarque;
  strFechasCambioAgenda: string;
begin
  inherited WriteToText(f);
  f.wr('T_ToP', T_ToP);
  f.wr('V_ToP', V_ToP, uconstantesSimSEE.CF_PRECISION, uconstantesSimSEE.CF_DECIMALES);
  f.wr('P_ToP', P_ToP, uconstantesSimSEE.CF_PRECISION, uconstantesSimSEE.CF_DECIMALES);
  f.wr('P_Espera', P_Espera, uconstantesSimSEE.CF_PRECISION,
    uconstantesSimSEE.CF_DECIMALES);
  //  f.wr('P_ExtraToP', P_ExtraToP, uconstantesSimSEE.CF_PRECISION, uconstantesSimSEE.CF_DECIMALES);
  //  f.wr('V_Spot', V_Spot, uconstantesSimSEE.CF_PRECISION, uconstantesSimSEE.CF_DECIMALES);
  f.wr('P_Spot', P_Spot, uconstantesSimSEE.CF_PRECISION, uconstantesSimSEE.CF_DECIMALES);
  f.wrReferencia('indicePreciosSpotPorCombustible', indicePreciosSpotPorCombustible);
  f.wr('bornePreciosSpotPorCombustible', bornePreciosSpotPorCombustible);
  f.wrReferencia('indicePreciosVentaPorCombustible', indicePreciosVentaPorCombustible);
  f.wr('bornePreciosVentaPorCombustible', bornePreciosVentaPorCombustible);
  f.wrReferencia('operatividadRegasificacion', operatividadRegasificacion);
  f.wr('borneOperatividadRegasificacion', borneOperatividadRegasificacion);
  f.wrReferencia('operatividadDescarga', operatividadDescarga);
  f.wr('borneOperatividadDescarga', borneOperatividadDescarga);
  f.wr('EmbarquesPeriodicos', EmbarquesPeriodicos);
  //  f.wr('DiasIngresoEmbarques', GetStrDiasIngresoEmbarques());
  //  f.wr('DiasIngresoEmbarques', agenda.ToString());
  f.wr('AgendasActivas', agendas.Count);
  for i := 0 to agendas.Count - 1 do
  begin
    ag := agendas.items[i] as TAgendaEmbarque;
    f.wr('DiasIngresoEmbarques_' + IntToStr(i), ag.ToString());
  end;

  f.wr('FechasCambioAgenda', getFechaCambioAgenda());


  f.wr('C_Min', C_Min, uconstantesSimSEE.CF_PRECISION, uconstantesSimSEE.CF_DECIMALES);
  f.wr('C_Max', C_Max, uconstantesSimSEE.CF_PRECISION, uconstantesSimSEE.CF_DECIMALES);
  f.wr('P_Venta', P_Venta, uconstantesSimSEE.CF_PRECISION,
    uconstantesSimSEE.CF_DECIMALES);
  f.wr('T_Max_Espera', T_Max_Espera);
  f.wr('Limites_Postizados', limites_postizados);
  f.wr('Manejo_BOG', manejoBOG);
  f.wr('BOG_hora', K_BOG);
  f.wr('Servicios_generales', K_GSS);
  f.wr('RG_por_emision', K_RG);
  f.wr('BOG_Recondensado', K_RC);
  f.wr('Ratio_RL', K_RL);
  f.wr('Hay_Relicuado', Relicuado);
  f.wr('CanonAnual', CanonAnual, uconstantesSimSEE.CF_PRECISION,
    uconstantesSimSEE.CF_DECIMALES);
  f.wrReferencia('agPerturbacionDias', agPerturbacionDias);
  f.wr('agBornePerturbacionDias', agBornePerturbacionDias);

  //  f.wr('CuentasEmbarques',GetStrCuentasEmbarques());
end;




//function TGNLFichaSumComb_TakeOrPay_Spot.GetStrDiasIngresoEmbarques(): String;
//begin
////  Result := DAOfNIntToStr_(self.DiasIngresoEmbarques, ';');
//  Result := agenda.ToString();
//end;

function TGNLFichaSumComb_TakeOrPay_Spot.GetStrDiasIngresoEmbarques_i(i: integer): string;
var
  ag: TAgendaEmbarque;
begin
  //  Result := DAOfNIntToStr_(self.DiasIngresoEmbarques, ';');
  ag := agendas.items[i] as TAgendaEmbarque;
  Result := ag.ToString();
end;

function TGNLFichaSumComb_TakeOrPay_Spot.hayCuentasEmbarques(): boolean;
var
  ag: TAgendaEmbarque;
  i: integer;
  hay_cuenta: boolean;
begin
  hay_cuenta := False;
  i := 0;
  while (i < agendas.Count) and (not hay_cuenta) do
  begin
    ag := agendas.items[i] as TAgendaEmbarque;
    hay_cuenta := length(ag.GetStrCuentasEmbarques()) > 0;
    i := i + 1;
  end;
  Result := hay_cuenta;
end;

function TGNLFichaSumComb_TakeOrPay_Spot.getFechaCambioAgenda(): string;
var
  i: integer;
  strFechasCambioAgenda: string;
begin
  strFechasCambioAgenda := '';
  for i := 0 to length(fechasCambioAgenda) - 1 do
  begin
    strFechasCambioAgenda := strFechasCambioAgenda +
      dateToStr(fechasCambioAgenda[i]) + '; ';
  end;
  Result := strFechasCambioAgenda;

end;

function TGNLFichaSumComb_TakeOrPay_Spot.validArrayCambioFechas(fechasCambioAgenda: string): boolean;
var
  i: integer;
  strLstFCAg: TStringList;
  res: boolean;
  fCA: array of TDateTime;
begin

  res := True;

  strLstFCAg := TStringList.Create;
  strLstFCAg.Delimiter := ';';
  strLstFCAg.DelimitedText := fechasCambioAgenda;
  setlength(fCA, strLstFCAg.Count);

  try
    begin
      for i := 0 to strLstFCAg.Count - 1 do
      begin
        fCA[i] := strToDate(strLstFCAg[i]);
      end;
    end
  except
    on EConvertError do
    begin
      res := False;
    end;
  end;

  i := 1;
  while (i < Length(fCA)) and (res = True) do
  begin
    res := fCA[i - 1] < fCA[i];
    i := i + 1;
  end;

  Result := res;

end;

function TGNLFichaSumComb_TakeOrPay_Spot.GetFechaSiguienteToP(fechaActual: TDateTime; agActiva: integer; var sCuenta: string; globs: TGlobs): TDateTime;
var
  cntDias, diasAux, i, diasSiguienteEmbarque, cantidadEmbarques: integer;
  fecha_ToP_ant: TDateTime;
  fecha_ToP_sig: TDateTime;
  ag: TAgendaEmbarque;

begin
  if self.EmbarquesPeriodicos then
  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 regir una ficha entra combustible)
    //o una fecha posterior tal que es múltiplo de T_ToP
    cntDias := Trunc(fechaActual) - Trunc(self.Fecha.dt);
    cntDias := cntDias mod self.T_ToP;
    fecha_ToP_ant := fechaActual - cntDias;

    //Calculamos la siguiente fecha de ingreso de TakeOrPay y la hacemos igual a la fecha anterior + T dias
    if fecha_ToP_ant = Trunc(fechaActual) then
      fecha_ToP_sig := Trunc(fechaActual)
    else
      fecha_ToP_sig := fecha_ToP_ant + self.T_ToP;
  end
  else
  begin

    if agendas.Count > 0 then
    begin
      ag := agendas.items[agActiva] as TAgendaEmbarque;
      ag.GetFechaSiguienteToP(fechaActual, self.P_ToP, self.V_ToP, self.V_Efectivo,
        fecha_ToP_sig, sCuenta, globs);
      //    end
      //    else
      //    begin
      //      agenda.GetFechaSiguienteToP(fechaActual, self.P_ToP, self.V_ToP,self.V_Efectivo, fecha_ToP_sig, sCuenta, globs);
    end;

    //    //Dado que los embarques no son periódicos, debo buscar en el array de dias de llegada de embarques
    //    //el próximo embarque.
    //    diasSiguienteEmbarque := MaxInt;
    //    cntDias :=  Trunc(fechaActual) - Trunc(self.Fecha.dt);

    //    cantidadEmbarques := length(DiasIngresoEmbarques);
    //    //Se asume que el vector esta ordenado de forma ascendente.
    //    i := 0;
    //    while (diasSiguienteEmbarque = MaxInt) and (i < cantidadEmbarques - 1) do
    //    begin
    //      diasAux := DiasIngresoEmbarques[i];
    //      if diasAux >= cntDias then begin
    //        diasSiguienteEmbarque := diasAux;
    //        if length(DiasIngresoEmbarques)=length(sCuentasEmbarques) then  //Si hay cuentas para cada embarque
    //           sCuenta:=sCuentasEmbarques[i] //Cuenta correspondiente al embarque que llega
    //        else
    //           sCuenta:='';
    //      end;

    //      i := i + 1;
    //    end;
    //    fecha_ToP_sig := Trunc(self.Fecha.dt) + diasSiguienteEmbarque;

  end;
  Result := fecha_ToP_sig;
end;

function TGNLFichaSumComb_TakeOrPay_Spot.GetSiguienteCambioAgenda(fechaActual: TDateTime): TDateTime;
var
{   cntDias, diasAux, i, diasSiguienteEmbarque, cantidadEmbarques : Integer;
  fecha_ToP_ant : TDateTime;
  currF: TDateTime;
   currLista: TListaDeCosas;
 }
  cntDias, i, diasSiguienteCambio, cantCambiosAgenda: integer;
  currF: TDateTime;
  //  currLista: TListaDeCosas;

begin

{   if globs.EstadoDeLaSala = CES_SIMULANDO then
    currLista := ListaEmbarquesMod
  else
    currLista := ListaEmbarques;
 }
  cantCambiosAgenda := length(fechasCambioAgenda);
  if cantCambiosAgenda > 0 then
  begin
    //    diasSiguienteCambio := MaxInt;
    //  cntDias :=  Trunc(fechaActual) - Trunc(self.FechaInicio.dt);
    //    cntDias :=  Trunc(fechaActual) - Trunc(self.fecha.dt);
    //    i := cantCambiosAgenda;
    currF := fechasCambioAgenda[currCambioFecha];

    if FechaAntPCA < FechaActual then
    begin
      while (fechaActual > currF) and (currCambioFecha < cantCambiosAgenda - 1) do
      begin
        currCambioFecha := currCambioFecha + 1;
        currF := fechasCambioAgenda[currCambioFecha];
      end;
    end
    else
    begin
      while (fechaActual < currF) and (currCambioFecha > 0) do
      begin
        currCambioFecha := currCambioFecha - 1;
        currF := fechasCambioAgenda[currCambioFecha];
      end;
    end;

  {     result := Trunc(self.FechaInicio.dt) + currF;
  }
  end
  else
  begin
    currF := FechaActual;
  end;
  FechaAntPCA := FechaActual;
  Result := currF;
end;


function TGNLFichaSumComb_TakeOrPay_Spot.infoAd_: string;
begin
  Result := inherited  infoAd_;
  Result := 'T_ToP= ' + IntToStr(T_ToP) + 'dias,' + 'V_ToP= ' +
    FloatToStrF(V_ToP, ffGeneral, 10, 1) + ' ' + combustible.Unidades +
    ', ' + 'P_ToP= ' + FloatToStrF(P_ToP, ffGeneral, 10, 1) +
    ' USD/' + combustible.Unidades + ', ' + 'P_Espera= ' +
    FloatToStrF(P_Espera, ffGeneral, 10, 1) + ' USD, ' +
    //         'P_ExtraToP= ' + FloatToStrF(P_ExtraToP, ffGeneral, 10, 2) + ' USD/' +combustible.Unidades+', ' +
    'C_Max= ' + FloatToStrF(C_Max, ffGeneral, 10, 1) + ' ' +
    combustible.Unidades + '/hora, ' + 'P_Spot= ' +
    FloatToStrF(P_Spot, ffGeneral, 10, 1) + ' USD/' + combustible.Unidades + ', ';

end;

procedure TGNLFichaSumComb_TakeOrPay_Spot.Free;
begin
  inherited Free;
end;

class function TGNLFichaSumComb_TakeOrPay_Spot.CreateDataColumnList(xVersion: integer): TDataColumnListOfCosa;
var
  list: TDataColumnListOfCosa;

begin
  list := TDataColumnListOfCosa.Create(TGNLFichaSumComb_TakeOrPay_Spot, xVersion);
  list.AddList(inherited CreateDataColumnList(xVersion));
  list.AddDataColumn('T_ToP', TGNLFichaSumComb_TakeOrPay_Spot(nil).T_ToP, TDataTypeIntegerOfCosa, 1, -1);
  list.AddDataColumn('V_ToP', TGNLFichaSumComb_TakeOrPay_Spot(nil).V_ToP, TDataTypeDoubleOfCosa, 1, -1);
  list.AddDataColumn('P_ToP', TGNLFichaSumComb_TakeOrPay_Spot(nil).P_ToP, TDataTypeDoubleOfCosa, 1, -1);
  list.AddDataColumn('P_Espera', TGNLFichaSumComb_TakeOrPay_Spot(nil).P_Espera, TDataTypeDoubleOfCosa, 1, -1);
  list.AddDataColumn('P_Spot', TGNLFichaSumComb_TakeOrPay_Spot(nil).P_Spot, TDataTypeDoubleOfCosa, 1, -1);
  list.AddDataColumn('indicePreciosSpotPorCombustible', TGNLFichaSumComb_TakeOrPay_Spot(nil).indicePreciosSpotPorCombustible, TDataTypeReferenciaOfCosa, 1, -1);
  list.AddDataColumn('bornePreciosSpotPorCombustible', TGNLFichaSumComb_TakeOrPay_Spot(nil).bornePreciosSpotPorCombustible, TDataTypeStringOfCosa, 1, -1);
  list.AddDataColumn('indicePreciosVentaPorCombustible', TGNLFichaSumComb_TakeOrPay_Spot(nil).indicePreciosVentaPorCombustible, TDataTypeReferenciaOfCosa, 1, -1);
  list.AddDataColumn('bornePreciosVentaPorCombustible', TGNLFichaSumComb_TakeOrPay_Spot(nil).bornePreciosVentaPorCombustible, TDataTypeStringOfCosa, 1, -1);
  list.AddDataColumn('operatividadRegasificacion', TGNLFichaSumComb_TakeOrPay_Spot(nil).operatividadRegasificacion, TDataTypeReferenciaOfCosa, 1, -1);
  list.AddDataColumn('borneOperatividadRegasificacion', TGNLFichaSumComb_TakeOrPay_Spot(nil).borneOperatividadRegasificacion, TDataTypeStringOfCosa, 1, -1);
  list.AddDataColumn('operatividadDescarga', TGNLFichaSumComb_TakeOrPay_Spot(nil).operatividadDescarga, TDataTypeReferenciaOfCosa, 1, -1);
  list.AddDataColumn('borneOperatividadDescarga', TGNLFichaSumComb_TakeOrPay_Spot(nil).borneOperatividadDescarga, TDataTypeStringOfCosa, 1, -1);
  list.AddDataColumn('EmbarquesPeriodicos', TGNLFichaSumComb_TakeOrPay_Spot(nil).EmbarquesPeriodicos, TDataTypeBooleanOfCosa, 1, -1);
  list.AddDataColumn('AgendasActivas', TGNLFichaSumComb_TakeOrPay_Spot(nil).agendas, TDataTypeDataRowOfCosa, 1, -1);
  list.AddDataColumn('C_Min', TGNLFichaSumComb_TakeOrPay_Spot(nil).C_Min, TDataTypeDoubleOfCosa, 1, -1);
  list.AddDataColumn('C_Max', TGNLFichaSumComb_TakeOrPay_Spot(nil).C_Max, TDataTypeDoubleOfCosa, 1, -1);
  list.AddDataColumn('P_Venta', TGNLFichaSumComb_TakeOrPay_Spot(nil).P_Venta, TDataTypeDoubleOfCosa, 1, -1);
  list.AddDataColumn('T_Max_Espera', TGNLFichaSumComb_TakeOrPay_Spot(nil).K_RL, TDataTypeDoubleOfCosa, 1, -1);
  list.AddDataColumn('Limites_Postizados', TGNLFichaSumComb_TakeOrPay_Spot(nil).limites_postizados, TDataTypeBooleanOfCosa, 1, -1);
  list.AddDataColumn('Manejo_BOG', TGNLFichaSumComb_TakeOrPay_Spot(nil).manejoBOG, TDataTypeBooleanOfCosa, 1, -1);
  list.AddDataColumn('BOG_hora', TGNLFichaSumComb_TakeOrPay_Spot(nil).T_Max_Espera, TDataTypeIntegerOfCosa, 1, -1);
  list.AddDataColumn('Servicios_generales', TGNLFichaSumComb_TakeOrPay_Spot(nil).K_GSS, TDataTypeDoubleOfCosa, 1, -1);
  list.AddDataColumn('RG_por_emision', TGNLFichaSumComb_TakeOrPay_Spot(nil).K_RG, TDataTypeDoubleOfCosa, 1, -1);
  list.AddDataColumn('BOG_Recondensado', TGNLFichaSumComb_TakeOrPay_Spot(nil).K_RC, TDataTypeDoubleOfCosa, 1, -1);
  list.AddDataColumn('Ratio_RL', TGNLFichaSumComb_TakeOrPay_Spot(nil).K_RL, TDataTypeDoubleOfCosa, 1, -1);
  list.AddDataColumn('Hay_Relicuado', TGNLFichaSumComb_TakeOrPay_Spot(nil).Relicuado, TDataTypeBooleanOfCosa, 1, -1);
  list.AddDataColumn('CanonAnual', TGNLFichaSumComb_TakeOrPay_Spot(nil).CanonAnual, TDataTypeDoubleOfCosa, 1, -1);
  list.AddDataColumn('agPerturbacionDias', TGNLFichaSumComb_TakeOrPay_Spot(nil).agPerturbacionDias, TDataTypeReferenciaOfCosa, 1, -1);
  list.AddDataColumn('agBornePerturbacionDias', TGNLFichaSumComb_TakeOrPay_Spot(nil).agBornePerturbacionDias, TDataTypeStringOfCosa, 1, -1);

  Result := list;

end;


//------------------------------
// Métodos de TGNLSumComb_TakeOrPay_Spot
//==============================
constructor TGNLSumComb_TakeOrPay_Spot.Create(nombre: string; nombreCombustible: string; nacimiento, muerte: TFecha; lpdUnidades, lpd: TFichasLPD; VDisp_Ini: NReal; NDisc: NInt; V_Spot: TDAOfNReal; NDiscSpot: NInt; T_Ini_Spot: TDAOfNInt; TArribo: NInt; V_Max: NReal; B_FavorecerDescarga: boolean; B_CostoVariableCero: boolean; CV_Fijado: NReal; B_HayRechazoEmbarque: boolean);
begin
  inherited Create(nombre, nombreCombustible, nacimiento, muerte, lpdUnidades, lpd);
  self.VDisp_Ini := VDisp_Ini;
  self.NDisc := NDisc;
  self.V_Spot := V_Spot;
  self.NDiscSpot := NDiscSpot;
  self.T_Ini_Spot := T_Ini_Spot;
  self.T_Arribo := T_Arribo;
  self.V_Max := V_Max;
  self.B_FavorecerDescarga := B_FavorecerDescarga;
  self.B_CostoVariableCero := B_CostoVariableCero;
  self.CV_Fijado := CV_Fijado;
  InicializarVariables;

  agendaActiva := 0;

  hayRechazoEmbarques := B_HayRechazoEmbarque;
end;


constructor TGNLSumComb_TakeOrPay_Spot.Create_ReadFromText(f: TArchiTexto);
begin
  inherited Create_ReadFromText(f);
  InicializarVariables;
  f.IniciarLecturaRetrasada;
  f.rd('VDisp_Ini', VDisp_Ini);
  f.rd('NDisc', NDisc);
  f.rd('T_Arribo', T_Arribo);
  f.rd('V_Max', V_Max);
  f.rd('V_Spot', V_Spot);
  f.rd('NDiscSpot', NDiscSpot);
  f.rd('T_Ini_Spot', T_Ini_Spot);
  f.rd('B_FavorecerDescarga', B_FavorecerDescarga);
  f.rd('B_CostoVariableCero', B_CostoVariableCero);
  f.rd('CV_Fijado', CV_Fijado);
  f.rd('B_HayRechazoEmbarque', hayRechazoEmbarques);
  f.EjecutarLectura;
  pa := nil;

  agendaActiva := 0;

end;

procedure TGNLSumComb_TakeOrPay_Spot.PrepararMemoria(globs: TGlobs);
var
  iposte, f: integer;
  auxfp: TFf_promedioSalto_N_poste;
  auxf: TFf_promedioSalto_N;
  f_a: TGNLFichaSumComb_TakeOrPay_Spot;

begin
  inherited prepararMemoria(globs);
  setlength(PorcOpRegasificacion, globs.NPostes);

  for  f := 0 to lpd.Count - 1 do
  begin
    f_a := TGNLFichaSumComb_TakeOrPay_Spot(lpd.f[f]);
    if f_a.operatividadRegasificacion <> nil then
    begin
      if f_a.limites_postizados then
      begin
        //todo preguntar si la fuente se piensa cambiar y por eso esta en la ficha
        //en tal caso hay que attachear las funciones a la fuente de la ficha cuando se cambia de ficha
        setlength(f_a.bornesPorcOpRegasificacion, globs.NPostes);
        for iposte := 0 to high(f_a.bornesPorcOpRegasificacion) do
        begin
          auxfp := TFf_promedioSalto_N_poste.Create(
            f_a.operatividadRegasificacion, iposte, globs);
          f_a.bornesPorcOpRegasificacion[iposte] :=
            f_a.operatividadRegasificacion.registrarFuncion(auxfp,
            f_a.borneOperatividadRegasificacion, -1);
        end;
      end
      else
      begin
        setlength(f_a.bornesPorcOpRegasificacion, 1);
        auxf := TFf_promedioSalto_N.Create(
          f_a.operatividadRegasificacion, globs);
        f_a.bornesPorcOpRegasificacion[0] :=
          f_a.operatividadRegasificacion.registrarFuncion(auxf,
          f_a.borneOperatividadRegasificacion, -1);
      end;
    end;
  end;
  saltearCargamento := False;
end;


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

function TGNLSumComb_TakeOrPay_Spot.get_precio_combustible: NReal;
begin
  Result := dCFdV; //***********++ESTO Puede ESTAr MAL Revisar*******************++
end;


function TGNLSumComb_TakeOrPay_Spot.get_VolCombustibleDisponible: NReal;
begin
  Result := X_VDisp_ToP;
end;

procedure TGNLSumComb_TakeOrPay_Spot.InicializarVariables;
begin
  self.VCnt_Next_Spot_Ini := 0;
end;

function TGNLSumComb_TakeOrPay_Spot.MaxEstadoSpot: NInt;
begin
  Result := NDiscDiasSpot - 1;
end;

function TGNLSumComb_TakeOrPay_Spot.NDiscDiasSpot: NInt;
var
  PasoEnDias: double;
  disc: NInt;
  resto: integer;
begin
  Result := self.NDiscSpot + 2;
end;

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

function TGNLSumComb_TakeOrPay_Spot.restricciones_postizadas: boolean;
begin
  Result := ((pa.C_Max <> -1) and pa.limites_postizados);
end;



procedure TGNLSumComb_TakeOrPay_Spot.RegistrarParametrosDinamicos;
var
  i, j: integer;
  ficha: TGNLFichaSumComb_TakeOrPay_Spot;
  ag: TAgendaEmbarque;
  fechaUltimoCargo: TFecha;
begin
  inherited registrarParametrosDinamicos;
  lpd.expandirFichas(globs);
  lpd.RegistrarFichasAActualizar(Self, globs.ActualizadorLPD, @pA, nil,
    TGNLSumComb_TakeOrPay_Spot_cambioFichaPD);
  for i := 0 to lpd.Count - 1 do
  begin
    ficha := TGNLFichaSumComb_TakeOrPay_Spot(lpd[i]);
    if ficha.indicePreciosPorCombustible <> nil then
      ficha.nroBornePreciosPorCombustible :=
        ficha.indicePreciosPorCombustible.IdBorne(ficha.bornePreciosPorCombustible);
    if ficha.indicePreciosVentaPorCombustible <> nil then
      ficha.nroBorneVentaPreciosPorCombustible :=
        ficha.indicePreciosVentaPorCombustible.IdBorne(ficha.bornePreciosVentaPorCombustible);
    if ficha.indicePreciosSpotPorCombustible <> nil then
      ficha.nroBorneSpotPreciosPorCombustible :=
        ficha.indicePreciosSpotPorCombustible.IdBorne(ficha.bornePreciosSpotPorCombustible);

    if ficha.operatividadDescarga <> nil then
      ficha.nroBorneOperatividadDescarga :=
        ficha.operatividadDescarga.IdBorne(ficha.borneOperatividadDescarga);
    if ficha.agPerturbacionDias <> nil then
    begin
      ficha.agNroBornePerturbacionDias :=
        ficha.agPerturbacionDias.IdBorne(ficha.agBornePerturbacionDias);
      fechaUltimoCargo := TFecha.Create_Clone(globs.fechaFinOpt);
      fechaUltimoCargo.dt := fechaUltimoCargo.dt + 3650;
      //      ficha.agenda.registrarPerturbacionDias(ficha.agPerturbacionDias, ficha.agNroBornePerturbacionDias);
      for j := 0 to ficha.agendas.Count - 1 do
      begin
        ag := ficha.agendas.items[j] as TAgendaEmbarque;
        ag.registrarPerturbacionDias(ficha.agPerturbacionDias,
          ficha.agNroBornePerturbacionDias);
        ag.ultimoCargamento(fechaUltimoCargo);
      end;
    end;
    fechaUltimoCargo := TFecha.Create_Clone(globs.fechaFinOpt);
    fechaUltimoCargo.dt := fechaUltimoCargo.dt + 3650;
    for j := 0 to ficha.agendas.Count - 1 do
    begin
      ag := ficha.agendas.items[j] as TAgendaEmbarque;
      ag.ultimoCargamento(fechaUltimoCargo);
    end;

  end;
end;


procedure TGNLSumComb_TakeOrPay_Spot.WriteToText(f: TArchiTexto);
begin
  inherited WriteToText(f);
  f.wr('VDisp_Ini', VDisp_Ini);
  f.wr('NDisc', NDisc);
  f.wr('T_Arribo', T_Arribo);
  f.wr('V_Max', V_Max, uconstantesSimSEE.CF_PRECISION, uconstantesSimSEE.CF_DECIMALES);
  f.wr('V_Spot', V_Spot, uconstantesSimSEE.CF_PRECISION, uconstantesSimSEE.CF_DECIMALES);
  f.wr('NDiscSpot', NDiscSpot, uconstantesSimSEE.CF_PRECISION,
    uconstantesSimSEE.CF_DECIMALES);
  f.wr('T_Ini_Spot', T_Ini_Spot);
  f.wr('B_FavorecerDescarga', B_FavorecerDescarga);
  f.wr('B_CostoVariableCero', B_CostoVariableCero);
  f.wr('CV_Fijado', CV_Fijado, uconstantesSimSEE.CF_PRECISION,
    uconstantesSimSEE.CF_DECIMALES);
  f.wr('B_HayRechazoEmbarque', hayRechazoEmbarques);
end;

procedure TGNLSumComb_TakeOrPay_Spot.Free;
begin
  inherited Free;
  //  closefile(f);
end;

class function TGNLSumComb_TakeOrPay_Spot.DescClase: string;
begin
  Result := 'Contrato Take Or Pay con Spot Pago al Inicio del Período';
end;


procedure TGNLSumComb_TakeOrPay_Spot.SorteosDelPaso(sortear: boolean);
var
  fTsig: TDateTime;  //Fecha del ultimo embarque recibido (anterior al paso)

  i, cntDias: integer;
  ficha: TGNLFichaSumComb_TakeOrPay_Spot;
  fichaActiva: TGNLFichaSumComb_TakeOrPay_Spot;
  ValorHoraPa: double;
  ValorHoraPaIni: double;
  ValorHoraPaFin: double;
  HorasHastaFinAnio: integer;
  //  myFile : TextFile;

begin
  V_ToP_sig := 0;
  V_Efectivo_sig := 0;
  self.ComprarCargamento := 0;
  self.RetrasarCargamento := 0;
  entrada := 0;
  espera := 0;

  fichaActiva := pa;

  //  AssignFile(myFile, '_salida.txt');
  //  Append(myFile);


  //  writeln(myFile, 'SorteosDelPaso'#9, dateToStr(globs.FechaInicioDelpaso.dt), #9'Estado (r,d): (', formatFloat('#####', globs.CF.xr[0]), #9, globs.CF.xd[0], ')'#9'agendaActiva'#9, agendaActiva);


  //  CloseFile(myFile);

  fTsig := pa.GetFechaSiguienteToP(globs.FechaInicioDelpaso.dt,
    agendaActiva, CuentaSiguienteTop, globs);
  V_ToP_sig := pa.V_ToP;
  V_Efectivo_Sig := pa.V_Efectivo;


  //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 := TGNLFichaSumComb_TakeOrPay_Spot(lpd[i]);
    if (ficha.fecha.dt > globs.FechaInicioDelpaso.dt) and
      (ficha.fecha.dt < globs.FechaFinDelpaso.dt) then
      if (fTsig > ficha.fecha.dt) then
      begin
        fichaActiva := ficha;
        if self.EmbarquesPeriodicos then
        begin
          fecha_ToP_sig := ficha.fecha.dt;
          V_ToP_sig := ficha.V_ToP;
          V_Efectivo_sig := ficha.V_Efectivo;
        end;
      end;
  end;

  if yearof(globs.FechaInicioDelpaso.dt) <> yearof(globs.FechaFinDelPaso.dt) then
    //si en el paso hay cambio de año
  begin
    ValorHoraPaIni := pa.CanonAnual / (DaysInYear(globs.FechaInicioDelpaso.dt) * 24);
    ValorHoraPaFin := pa.CanonAnual / (DaysInYear(globs.FechaFinDelPaso.dt) * 24);
    HorasHastaFinAnio := HoursBetween(globs.FechaInicioDelpaso.dt,
      EndOfTheYear(globs.FechaInicioDelpaso.dt));
    CanonFijoXPaso := ValorHoraPaIni * HorasHastaFinAnio + ValorHoraPaFin *
      (globs.HorasDelPaso - HorasHastaFinAnio);
  end
  else
  begin
    ValorHoraPa := pa.CanonAnual / (DaysInYear(globs.FechaInicioDelpaso.dt) * 24);
    CanonFijoXPaso := ValorHoraPa * globs.HorasDelPaso;
  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
    (TFecha.Create_OffsetHoras(globs.FechaInicioDelpaso, globs.HorasDelPaso).dt >
    fecha_ToP_sig) then
    //  begin
    //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
    pa := fichaActiva;
  //  end
  //  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

  //Determina cual es el próximo cargamento que llega
  fecha_Spot_sig := self.CalculoFechaArriboSpot;
  if fecha_ToP_sig <= fecha_Spot_sig then //si llega primero el de top
  begin
    F_Arribo := fecha_ToP_sig;
    V_ProxCargamento := V_Efectivo_sig;
  end
  else
  begin //si llega primero el de spot
    F_Arribo := fecha_Spot_sig;
    V_ProxCargamento := self.V_Spot[0];
  end;

end;


//Calcula la fecha del próximo spot o devuelve la fecha máxima si todavía no se espera un cargamento
function TGNLSumComb_TakeOrPay_Spot.CalculoFechaArriboSpot(): TDateTime;
var
  FechaProxArribo: TDateTime;
begin
  if (X_VCnt_Next_Spot > 0) and (X_VCnt_Next_Spot < self.MaxEstadoSpot - 1) then
  begin
    FechaProxArribo := globs.FechaInicioDelpaso.dt;
    FechaProxArribo := IncHour(FechaProxArribo, Round(
      (X_VCnt_Next_Spot - 1 - Self.IncSpot) * PasoTiempoSpotHoras));
    Result := FechaProxArribo;
  end
  else //no hay cargamento de spot previsto
    Result := globs.fechaFinOpt.dt;
end;



function TGNLSumComb_TakeOrPay_Spot.CantVCons: integer;
begin
  if pa.limites_postizados then
    Result := globs.NPostes
  else
    Result := 1;
end;

function TGNLSumComb_TakeOrPay_Spot.PasoTiempoSpotHoras(): double;
begin
  Result := (T_Arribo * 24) / (self.MaxEstadoSpot - 2);
end;

procedure TGNLSumComb_TakeOrPay_Spot.PrepararPaso_ps;
var
  dCFdV_Inc, dCFdV_Dec, X_VolTanqueAnt: NReal;
  rescod, iposte: integer;
  xrpos: double;
  i: integer;
  //  myFile: TextFile;
begin

  //  AssignFile(myFile, '_salida.txt');
  //  Append(myFile);


  //  writeln(myFile, 'prepararPaso_ps'#9, dateToStr(globs.FechaInicioDelpaso.dt), #9'Estado (r,d):'#9, formatFloat('#####', globs.CF.xr[0]), #9, globs.CF.xd[0], ''#9'agendaActiva'#9, agendaActiva);


  //  CloseFile(myFile);

  V_ToP_sig := 0;
  V_Efectivo_sig := 0;

  fecha_ToP_sig := pa.GetFechaSiguienteToP(globs.FechaInicioDelpaso.dt,
    agendaActiva, CuentaSiguienteTop, globs);
  V_ToP_sig := pa.V_ToP;
  V_Efectivo_Sig := pa.V_Efectivo;

  if (globs.FechaInicioDelpaso.dt <= fecha_ToP_sig) and
    (TFecha.Create_OffsetHoras(globs.FechaInicioDelpaso, globs.HorasDelPaso).dt >
    fecha_ToP_sig) then
    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


  TGNLBalance.InicializarPaso;

  self.VConsumido_ToP := 0;
  self.VConsumido_Extra_Top := 0;
  self.VSobrante_ToP := 0;
  //Los suministros de combustible se preparan antes que los generadores. Esto permite que
  //el generador tenga las cosas que necesita del suministro de combustible.
  cvToP := 0;
  if self.T_Arribo <> 0 then
  begin
    if fase = 1 then
    begin
      if X_VCnt_Next_Spot = 0 then
        dCFdCn := globs.CF.deltaCosto_vxr_continuo_DosEstados_UTE(
          ixr + 1, ixr, globs.kPaso_ + 1, MaxEstadoSpot, Min(self.V_Max,
          pa.V_Efectivo + X_VDisp_ToP)) * globs.fActPaso
      else
        dCFdCn := 0;
      if X_VCnt_Next_Spot = MaxEstadoSpot then
        delta := globs.CF.deltaCosto_vxr_continuo_DosEstados_UTE(
          ixr + 1, ixr, globs.kPaso_ + 1, -1, Min(self.V_Max, X_VDisp_ToP + pa.V_Efectivo)) *
          globs.fActPaso
      else
        delta := 0;
    end
    else
    begin
      if X_VCnt_Next_Spot = 0 then
        dCFdCn := globs.CF.deltaCosto_vxr_continuo(
          ixr + 1, globs.kPaso_ + 1, MaxEstadoSpot) * globs.fActPaso
      else
        dCFdCn := 0;
      if X_VCnt_Next_Spot = MaxEstadoSpot then
        delta := globs.CF.deltaCosto_vxr_continuo(ixr + 1, globs.kPaso_ + 1, -1) *
          globs.fActPaso
      else
        delta := 0;
    end;
  end
  else
  begin //si no hay spot no se calcula nada
    dCFdCn := 0;
    delta := 0;
  end;


  X_VolTanqueAnt := globs.CF.xr[ixr];  //Guarda el estado para volver al mimso luego

  if self.T_Arribo <> 0 then
  begin
    //Si está viniendo el cargamento o esta en el penúltimo estado y decide no retrasar
    if ((X_VCnt_Next_Spot = MaxEstadoSpot - 1) and (delta > 0)) or
      ((X_VCnt_Next_Spot < MaxEstadoSpot - 1) and (X_VCnt_Next_Spot > 0)) then
    begin
      //Si llega un cargamento en el paso siguiente o está en espera
      if (X_VCnt_Next_Spot - self.IncSpot <= 1) then
      begin
        globs.CF.xr[ixr] := min(self.V_Max, X_VDisp_ToP + self.V_Spot[0]);
        //le suma parte del combustible que entro para que cambie el precio
      end;
    end;
  end;

  if fase = 1 then
  begin  //si hay una entrada de combustible por ToP también se considera en el precio
    globs.CF.xr[ixr] := min(self.V_Max, globs.CF.xr[ixr] + V_Efectivo_sig);
  end;



  if B_CostoVariableCero then
  begin
    cvToP := CV_Fijado;
  end
  else
  begin
    if globs.EstadoDeLaSala = CES_OPTIMIZANDO then
      globs.CF.devxr_estrella(ixr, globs.kPaso_ + 1, dCFdV_Inc, dCFdV_Dec, rescod)
    else
      globs.CF.devxr_continuo(ixr, globs.kPaso_ + 1, dCFdV_Inc, dCFdV_Dec,
        rescod, xrpos);

    globs.CF.xr[ixr] := X_VolTanqueAnt; //Vuelve el estado a lo que estaba antes

    if B_FavorecerDescarga then
      //Si hay que favorecer la descarga del tanque cuando llega un cargamento y no hay espacio
    begin
      dCFdV := AjusteCostoVariableXArribo(dCFdV_Dec, V_ProxCargamento, F_Arribo);
    end
    else
    begin
      dCFdV := dCFdV_Dec;
    end;
    //Fija el costo variable
    cvToP := -dCFdV * globs.fActPaso;
  end;

  globs.CF.xr[ixr] := X_VolTanqueAnt; //Vuelve el estado a lo que estaba antes

  if fase = 1 then
  begin
    if pa.indicePreciosPorCombustible <> nil then
    begin
      cfToP := pa.P_ToP * pa.V_Efectivo *
        pa.indicePreciosPorCombustible.bornera[pa.nroBornePreciosPorCombustible];
    end
    else
    begin
      cfToP := pa.P_ToP * pa.V_Efectivo;
    end;
  end
  else
  begin
    cfToP := 0;         //No ingresa combustible en esta etapa
  end;


  if pa.indicePreciosSpotPorCombustible <> nil then
    cvSpot := pa.P_Spot * pa.indicePreciosSpotPorCombustible.bornera[
      pa.nroBorneSpotPreciosPorCombustible]
  else
    cvSpot := pa.P_Spot;

  if pa.indicePreciosVentaPorCombustible <> nil then
    cvVenta := pa.P_Venta * pa.indicePreciosVentaPorCombustible.bornera
      [pa.nroBorneVentaPreciosPorCombustible]
  else
    cvVenta := pa.P_Venta;

  //Bornera para la operatividad de descarga
  if pa.operatividadDescarga <> nil then
    OpTiempoDescarga := Round(pa.operatividadDescarga.bornera[
      pa.nroBorneOperatividadDescarga])
  else
    OpTiempoDescarga := K_TotHorasDescarga;

  //Bornera para la operatividad de regasificación
  if pa.operatividadRegasificacion <> nil then
  begin
    if restricciones_postizadas() then
    begin
      for iposte := 0 to globs.Npostes - 1 do
      begin
        PorcOpRegasificacion[iposte] :=
          pa.operatividadRegasificacion.Bornera[pa.bornesPorcOpRegasificacion[iposte]];
      end;
    end
    else
    begin
      PorcOpRegasificacion[0] :=
        pa.operatividadRegasificacion.Bornera[pa.bornesPorcOpRegasificacion[0]];
    end;
  end
  else //Si no hay operabilidad de regasificación
    PorcOpRegasificacion[0] := 1;

end;

//Función que ajusta el cv del combustible para evitar que entre en espera algunos pasos antes
function TGNLSumComb_TakeOrPay_Spot.AjusteCostoVariableXArribo(CostoVariable: double; V_Cargamento: double; FechaProxArribo: TDateTime): double;
var
  T_Restante: integer; //Tiempo restante en horas para la llegada del cargamento
  V_MaxConsumo: double;
  V_Restante: double;
begin
  if pa.C_Max > 0 then
  begin
    T_Restante := HoursBetween(FechaProxArribo, globs.FechaInicioDelpaso.dt);
    //tiempo restante en horas para la llegada del cargamento
    V_MaxConsumo := T_Restante * pa.C_Max;
    V_Restante := self.V_Max - X_VDisp_ToP + V_MaxConsumo;
    if V_Restante <= V_Cargamento then
      //Si no va a tener espacio si no empieza a consumir a pleno desde ya
      Result := 0 //Pone el costo variable como
    else
      Result := CostoVariable;
  end
  else //si no hay sendout máximo no se puede ajustar el costo variable de acuerdo al arribo
    Result := CostoVariable;
end;


function TGNLSumComb_TakeOrPay_Spot.k_ResFVConsTot: integer;
begin
  Result := ires + CantVCons();
end;

function TGNLSumComb_TakeOrPay_Spot.k_VarCCompra: integer;
begin
  Result := k_VarCVConsTot + 1;
end;

function TGNLSumComb_TakeOrPay_Spot.k_VarCRetraso: integer;
begin
  Result := k_VarCCompra + 1;
end;

function TGNLSumComb_TakeOrPay_Spot.k_VarCVConsTot: integer;
begin
  Result := ivar + CantVCons();
end;

procedure TGNLSumComb_TakeOrPay_Spot.opt_nvers(var ivar, ivae, ires: integer);
begin
  if X_VDisp_ToP = 0 then
    exit; //Si no hay combustible no tiene sentido estar en la matríz

  self.ivar := ivar; //CAntidad de variables (columnas)
  self.ires := ires;  //Cantidad de restricciones (filas)

  ivar := ivar + CantVCons() + 1;
  //+ 3;  Columnas de VConsumido_poste VminCons_poste VConsumido_T BComprarCargamento y BRetrasarCargamento

  ires := ires + CantVCons() + 1;
  // 1 restricción. Luego los generadores deberán completar en sus columnas y en esta fila la restricción de volumen

end;

procedure TGNLSumComb_TakeOrPay_Spot.opt_cargue(s: TSimplex);
var
  dCF: NReal;
  iposte: integer;
  MaxSendOut: double;

begin
  if X_VDisp_ToP = 0 then
    exit; //Si no hay combustible no tiene sentido estar en la matríz

  {$IFDEF SPXCONLOG}
  spx_NombrarVariables(s);
  {$ENDIF}

  //Restricción de balance de volumen (Sumatoria de lo consumido por las maquinas - VExtraTop - VConsumidoTop debe ser igual a 0
  //Solo consume de lo disponible....

  for iposte := 0 to CantVCons() - 1 do //Depende si es postizado o no
  begin
    //restriccion de volumen por poste
    s.pon_e(ires + iposte, ivar + iposte, -1); //VConsumido_poste para los generadores
    //restriccion de balance de volumen
    s.pon_e(k_ResFVConsTot, ivar + iposte, -1); //VConsumido_poste para el VConsumido_T
    //Costo
    s.pon_e(s.nf, ivar + iposte, 0); //VConsumido_poste
  end;

  //restriccion de balance de volumen
  s.pon_e(k_ResFVConsTot, k_VarCVConsTot, 1); //VConsumido_T

  //Costo
  s.pon_e(s.nf, k_VarCVConsTot, -cvToP); //VConsumido_T

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

end;

procedure TGNLSumComb_TakeOrPay_Spot.Sim_Cronica_Inicio;
var
  f, i: integer;
  ficha: TGNLFichaSumComb_TakeOrPay_Spot;
  ag: TAgendaEmbarque;
  nuevoEstado, deltaEstado, maxAg: integer;
  maxDelta, delta: NReal;
begin
  inherited Sim_Cronica_Inicio;
  TGNLBalance.IncializarCronica(self.VDisp_Ini);
  X_VDisp_ToP := self.VDisp_Ini;   //Inicializo la variable de estado.
  X_VCnt_Next_Spot := self.VCnt_Next_Spot_Ini;

  globs.CF.xr[ixr] := X_VDisp_ToP;
  if self.T_Arribo <> 0 then //si hay spot, sino no existe la variable de estado
    globs.CF.xr[ixr + 1] := X_VCnt_Next_Spot;



  if (pa.agendas.Count > 1) then
  begin
    agendaActiva := 0;
    globs.CF.xd[ixd] := agendaActiva;
    maxDelta := 0;
    maxAg := agendaActiva;
    for i := 0 to pa.agendas.Count - 1 do
    begin
      nuevoEstado := i;
      deltaEstado := nuevoEstado - agendaActiva;
      delta := globs.CF.deltaCosto_vxd_continuo(ixd, globs.kPaso_ + 1, deltaEstado);
      if delta < maxDelta then
      begin
        maxDelta := delta;
        maxAg := nuevoEstado;
      end;
    end;
    agendaActiva := maxAg;
  end
  else
    agendaActiva := 0;


  if (hayRechazoEmbarques) then
  begin
    globs.CF.xd[ixd_rechazoEmbarques] := 0;
    self.saltearCargamento := False;
  end;



  for  f := 0 to lpd.Count - 1 do
  begin
    ficha := TGNLFichaSumComb_TakeOrPay_Spot(lpd.f[f]);
    //    ficha.agenda.perturbacionAgenda();
    for i := 0 to ficha.agendas.Count - 1 do
    begin
      ag := ficha.agendas.items[i] as TAgendaEmbarque;
      ag.perturbacionAgenda();
    end;
  end;
end;


procedure TGNLSumComb_TakeOrPay_Spot.Sim_Paso_Fin;
begin
  inherited;
  if PA.hayCuentasEmbarques() then
    TGNLBalance.CalculoBalance;
end;

function TGNLSumComb_TakeOrPay_Spot.MaxSendOut(poste: integer): double;
begin
  if (pa.operatividadRegasificacion <> nil) then
  begin//si hay operabilidad de regasificación
    if (pa.limites_postizados) then
      Result := pa.C_Max * PorcOpRegasificacion[poste] * globs.DurPos[poste]
    else //si los límites son por paso
      Result := pa.C_Max * PorcOpRegasificacion[0] * globs.HorasDelPaso;
  end
  else
  begin //si no hay operabilidad de regasificación
    if (pa.limites_postizados) then
      Result := pa.C_Max * globs.DurPos[poste]
    else //si los límites son por paso
      Result := pa.C_Max * globs.HorasDelPaso;
  end;
end;

function TGNLSumComb_TakeOrPay_Spot.maxAgendas: integer;
var
  f, mA: integer;
  f_a: TGNLFichaSumComb_TakeOrPay_Spot;
begin
  mA := 0;
  for  f := 0 to lpd.Count - 1 do
  begin
    f_a := TGNLFichaSumComb_TakeOrPay_Spot(lpd.f[f]);
    if mA < f_a.agendas.Count then
      mA := f_a.agendas.Count;
  end;
  Result := mA;
end;


procedure TGNLSumComb_TakeOrPay_Spot.opt_fijarRestriccionesDeCaja(s: TSimplex);
var
  iposte: integer;
  MaxSendOut: double;
begin
  if X_VDisp_ToP = 0 then
    exit; //Si no hay combustible no tiene sentido estar en la matríz

  for iposte := 0 to CantVCons() - 1 do
  begin
    //restriccion de volumen consumido
    s.FijarRestriccionIgualdad(ires + iposte);
    // Puesta por pablo a pedido de Sebastian, está de mas es para que se pueda llevar al solver
    //Agregamos la restricción de caja que dice que el  0 <= VConsumidoToP <= VDisponibleTop
    if (pa.C_Max <> -1) then //Calcula el máximo que puede consumir
      s.cota_sup_set(ivar + iposte, self.MaxSendOut(iposte))
    else
      s.cota_sup_set(ivar + iposte, X_VDisp_ToP);
  end;

  //restriccion de balance de volumen
  s.FijarRestriccionIgualdad(k_ResFVConsTot);
  //Agregamos la restricción de caja que dice que el  0 <= VConsumidoToP <= VDisponibleTop
  s.cota_sup_set(k_VarCVConsTot, X_VDisp_ToP);

end;

procedure TGNLSumComb_TakeOrPay_Spot.opt_leerSolucion(s: TSimplex);
var
  VDisp_ToP_, VolAnt: NReal;
  iposte: integer;
  BOG_T_aux, BOG_GSS_aux, BOG_RG_aux, BOG_RC_aux, BOG_RL_aux, BOG_GRL_aux, BOG_Vent_aux, BSO_aux: NReal;
  Vender: boolean;
  DiasEspera: double;
  //  myFile: TextFile;
begin

  //  AssignFile(myFile, '_salida.txt');
  //  Append(myFile);


  //  writeln(myFile, 'opt_leerSolucion'#9, dateToStr(globs.FechaInicioDelpaso.dt), #9'Estado (r,d):'#9, formatFloat('#####', globs.CF.xr[0]), #9, globs.CF.xd[0], ''#9'agendaActiva'#9, agendaActiva);


  //  CloseFile(myFile);


  CostoDirectoDelPaso := 0;
  self.Entrada := 0;
  self.Espera := 0;
  self.CostoEspera := 0;
  self.Venta := 0;
  self.CostoCompra := 0;
  self.DiasEspera := 0;

  self.bLlegadaSpot := 0;
  self.bEntradaTop := 0;
  self.bEntradaSpot := 0;
  self.bVentaTop := 0;
  self.bVentaSpot := 0;
  self.VolumenSpot := 0;
  self.VolumenTOP := 0;
  self.PrecioSpot := 0;
  self.PrecioTOP := 0;
  self.VolFaltaAncap := 0;



  if X_VDisp_ToP = 0 then  //Si no hay combustible no tiene sentido estar en la matríz
    self.VConsumido_ToP := 0
  else
    self.VConsumido_ToP := s.xval(k_VarCVConsTot);

  //self.ComprarCargamento := s.xval(k_VarCCompra);
  if -(dCFdCn) > 0 then
    self.ComprarCargamento := 1
  else
    self.ComprarCargamento := 0;


  //self.RetrasarCargamento := s.xval(k_VarCRetraso);
  if delta > 0 then
    self.RetrasarCargamento := 1
  else
    self.RetrasarCargamento := 0;


  CostoDirectoDelPaso := CostoDirectoDelPaso + CanonFijoXPaso;

  VSobrante_ToP := 0;

  //Lo primero que se hace es actualizar el combustible del tanque de acuerdo a lo consumido
  Xs_VDisp_ToP := X_VDisp_ToP - self.VConsumido_ToP;
  //No importa si entra o no combustible siempre se resta primero lo que se consume
  if Xs_VDisp_ToP < 0 then
    Xs_VDisp_ToP := 0;




  //Calculo del costo directo del paso y actualizo el estado al final del paso

  //********* Comienzo compras ToPay *************+
  if fase = 1 then //Llego un TOP
  begin
    CostoDirectoDelPaso := CostoDirectoDelPaso + cfToP;
    self.CostoCompra := self.CostoCompra + cfToP;
    if self.saltearCargamento then
    begin
      //Atención: Se saltea el cargamento
      //Costo Directo del Paso = Costo del Cargamento TOP - Ganancia por la venta en otro mercado a otro precio menor
      CostoDirectoDelPaso := CostoDirectoDelPaso - self.VentaTop;
    end
    else
    begin
      //se fija si hay lugar para el TOP
      if (Xs_VDisp_ToP + V_ToP_sig - self.V_Max > K_Resto) then
      begin // (Xs_VDisp_ToP + V_ToP_sig > self.V_Max) //no hubo espacio para el TOP ni aunque se tire el resto
        //Atención: No hubo lugar en el tanque pero podría pasar que el TOP caiga hacia final del paso
        //Costo Directo del Paso = Costo del Cargamento TOP + Costo de Espera por el tiempo máximo - Ganancia por la venta en otro mercado a otro precio menor
        CostoDirectoDelPaso := CostoDirectoDelPaso + (pa.P_Espera * pa.T_Max_Espera) -
          self.VentaTop;
        self.CostoEspera := self.CostoEspera + pa.P_Espera * pa.T_Max_Espera;
        self.DiasEspera := self.DiasEspera + pa.T_Max_Espera;
      end //si hay espacio en el tanque para descargar, se fija si pagó espera
      else
      begin
        //if (Xs_VDisp_ToP + V_ToP_sig - self.V_Max > 0) then //si está dentro de error
        //   Xs_VDisp_ToP = self.V_Max; //Ventea lo que excede el tanque y es menor a K_Resto
        DiasEspera := CalculoCostoEsperaParcial(fecha_ToP_sig, V_ToP_sig, Vender);
        //Esto afecta cuando se hace espacio en el paso, si al principio del paso ya existía espacio no afecta en nada ya que no vende y no tiene tiempo de espera.
        //Vender:=false; //*******Se anulo la venta cuando hay lugar en el paso para relajar el problema ****************
        if Vender then
        begin//si tuvo que vender porque espero mucho dentro del paso
          CostoDirectoDelPaso :=
            CostoDirectoDelPaso + (pa.P_Espera * pa.T_Max_Espera) - self.VentaTop;
          self.CostoEspera := self.CostoEspera + pa.P_Espera * pa.T_Max_Espera;
          self.DiasEspera := self.DiasEspera + pa.T_Max_Espera;
        end
        else
        begin //si espero en el paso pero no tuvo que vender o no espero
          VSobrante_ToP := Max(0, X_VDisp_ToP - self.VConsumido_ToP +
            V_Efectivo_sig - self.V_Max);
          //Lo que quedó disponible en el tanque es sobrante (sin consumir)
          VolAnt := Xs_VDisp_ToP;
          Xs_VDisp_ToP := Min(self.V_Max, V_Efectivo_sig + X_VDisp_ToP -
            self.VConsumido_ToP);
          //Actualizo el estado, ingreso el combustible
          self.VolumenTop := V_Efectivo_sig;
          self.PrecioTOP := cfToP;
          //**************************************************************************************************************************************
          //No esta bien controlado que no haya cuentas para el caso de borde de no haber embarques y comprar todo al spot **********************++
          //**************************************PABLO************+TODO*****************************************************************
          if (globs.EstadoDeLaSala = CES_SIMULANDO) and (Self.pa.hayCuentasEmbarques()) then //Las cuentas corrientes se tienen en cuenta sólo en la simulación
            TGNLBalance.GuardarEmbarque(CuentaSiguienteTop, Xs_VDisp_ToP - VolAnt);

          //CostoDirectoDelPaso := CostoDirectoDelPaso +  VSobrante_ToP* (cfToP/V_ToP_sig) + cfToP;
          CostoDirectoDelPaso := CostoDirectoDelPaso + (pa.P_Espera * DiasEspera);
          self.CostoEspera := self.CostoEspera + (pa.P_Espera * DiasEspera);
          self.DiasEspera := self.DiasEspera + DiasEspera;
          self.Entrada := self.Entrada + 1;
          self.bEntradaTop := 1;
        end;
      end;
    end;

  end;
  //********* Fin compras ToPay *************+


  //*************Comienzo cargamento Spot ****************+
  Xs_VCnt_Next_Spot := X_VCnt_Next_Spot;

  if X_VCnt_Next_Spot = 0 then
  begin //Puede comprar y no hay cargamento en camino no puedo retrasar
    //Hay que comprar un cargamento?
    if (self.ComprarCargamento > 0.8) then
    begin
      Xs_VCnt_Next_Spot := MaxEstadoSpot;
    end;
  end
  else if X_VCnt_Next_Spot = 1 then
    //Hay un cargamento esperando para descargar no puede comprar ni retrasar
  begin
    self.ArriboDeCargamentoSpot;
  end
  else if (X_VCnt_Next_Spot > 1) and (X_VCnt_Next_Spot < MaxEstadoSpot) then
  begin //Hay un cargamento en camino no puede comprar ni retrasar
    if (X_VCnt_Next_Spot - self.IncSpot) <= 1 then
      //Entonces estoy esperando un embarque, no puedo pedir otro
    begin
      self.ArriboDeCargamentoSpot;
    end
    else  //Todavía no llego el cargamento
    begin
      Xs_VCnt_Next_Spot := X_VCnt_Next_Spot - (self.IncSpot);
    end;
  end
  else
  begin //if X_VCnt_Next_Spot=k_MaxEstadoSpot then begin //Se tomo la desición de compra en el paso anterior, no se puede comprar, pero se puede retrasar
    if Self.RetrasarCargamento > 0.8 then
    begin //Si toma la desición de retrasar queda en el estado en que está
      Xs_VCnt_Next_Spot := X_VCnt_Next_Spot;
    end
    else //No hay que retrasar el embarque
    begin
      Xs_VCnt_Next_Spot := X_VCnt_Next_Spot - 1 - (self.IncSpot);
      CostoDirectoDelPaso := CostoDirectoDelPaso + cvSpot * self.V_Spot[0];
      //Cambiarlo por el costo y volúmen de spot
      self.CostoCompra := self.CostoCompra + cvSpot * self.V_Spot[0];
      //Comienza agregado nuevo para cuando el tiempo entre la compra y la llegada es un paso
      if Xs_VCnt_Next_Spot <= 1 then
        //Entonces estoy esperando un embarque, no puedo pedir otro
      begin
        self.ArriboDeCargamentoSpot;
      end;
      //Fin Spot al paso siguiente
    end;
  end;
  //***********++Fin Cargamento Spot

  BOG_T := 0;
  BOG_GSS := 0;
  BOG_RG := 0;
  BOG_RC := 0;
  BOG_RL := 0;
  BOG_GRL := 0;
  BOG_Vent := 0;
  BSO := 0;


  if pa.manejoBOG then
  begin
    if pa.limites_postizados then
    begin
      for iposte := 0 to globs.NPostes - 1 do
      begin
        if X_VDisp_ToP = 0 then
          BOG_Calc.BOG_poste(BOG_T_aux, BOG_GSS_aux, BOG_RG_aux,
            BOG_RC_aux, BOG_RL_aux, BOG_GRL_aux, BOG_Vent_aux, BSO_aux,
            0, X_VDisp_ToP, pa.K_BOG, pa.K_GSS, pa.K_RG, pa.K_RC,
            pa.K_RL, pa.Relicuado, globs.DurPos[iposte])
        else
          BOG_Calc.BOG_poste(BOG_T_aux, BOG_GSS_aux, BOG_RG_aux,
            BOG_RC_aux, BOG_RL_aux, BOG_GRL_aux, BOG_Vent_aux, BSO_aux,
            s.xval(ivar + iposte), X_VDisp_ToP, pa.K_BOG, pa.K_GSS,
            pa.K_RG, pa.K_RC, pa.K_RL, pa.Relicuado, globs.DurPos[iposte]);

        //        BOG_Calc.BOG_poste(BOG_T_aux, BOG_GSS_aux, BOG_RG_aux, BOG_RC_aux, BOG_RL_aux, BOG_GRL_aux, BOG_Vent_aux, BSO_aux,
        //        s.xval(ivar + iposte), X_VDisp_ToP, 0, 0, 0, 0, 0, false, globs.DurPos[iposte+1]);

        BOG_T := BOG_T + BOG_T_aux;
        BOG_GSS := BOG_GSS + BOG_GSS_aux;
        BOG_RG := BOG_RG + BOG_RG_aux;
        BOG_RC := BOG_RC + BOG_RC_aux;
        BOG_RL := BOG_RL + BOG_RL_aux;
        BOG_GRL := BOG_GRL + BOG_GRL_aux;
        BOG_Vent := BOG_Vent + BOG_Vent_aux;
        BSO := BSO + BSO_aux;

      end;

    end
    else
    begin
      BOG_Calc.BOG_poste(BOG_T_aux, BOG_GSS_aux, BOG_RG_aux,
        BOG_RC_aux, BOG_RL_aux, BOG_GRL_aux, BOG_Vent_aux, BSO_aux,
        //        s.xval(ivar + iposte), X_VDisp_ToP, 0.01/24, 0, 0.2/24, 0.1/24, 1/12, true, globs.DurPos[iposte+1]);
        self.VConsumido_ToP, X_VDisp_ToP, pa.K_BOG, pa.K_GSS, pa.K_RG,
        pa.K_RC, pa.K_RL, pa.Relicuado, globs.HorasDelPaso);

      //        BOG_Calc.BOG_poste(BOG_T_aux, BOG_GSS_aux, BOG_RG_aux, BOG_RC_aux, BOG_RL_aux, BOG_GRL_aux, BOG_Vent_aux, BSO_aux,
      //        self.VConsumido_ToP, X_VDisp_ToP, 0, 0, 0, 0, 0, false, globs.HorasDelPaso);

      BOG_T := BOG_T + BOG_T_aux;
      BOG_GSS := BOG_GSS + BOG_GSS_aux;
      BOG_RG := BOG_RG + BOG_RG_aux;
      BOG_RC := BOG_RC + BOG_RC_aux;
      BOG_RL := BOG_RL + BOG_RL_aux;
      BOG_GRL := BOG_GRL + BOG_GRL_aux;
      BOG_Vent := BOG_Vent + BOG_Vent_aux;
      BSO := BSO + BSO_aux;
    end;
  end;



  if (globs.cntIteracionesDelPaso > 1) then
    bQuemo := 0;

  //    Xs_VDisp_ToP := Xs_VDisp_ToP - BOG_GSS - BOG_RG + BOG_RC + BOG_RL - BOG_GRL - BOG_Vent - BSO;
  Xs_VDisp_ToP := Xs_VDisp_ToP - BOG_T + BOG_RC + BOG_RL - BSO;

  volQuemado := 0;
  bQuemo := 0;
  //Barco de UTE que trae el cargo ****IMPORTANTE NO CORRER SALAS NORMALES CON ESTO***********
  //  if (fecha_top_sig-globs.FechaInicioDelpaso.dt=k_TiempoViaje) then begin
  //     volQuemado := max(0,Xs_VDisp_ToP -(self.V_Max - V_ToP_sig));
  //     if VolQuemado>0 then
  //        bQuemo:=1;
  //     Xs_VDisp_ToP := min(self.V_Max - V_ToP_sig, Xs_VDisp_ToP);
  //     costoDirectoDelPaso := costoDirectoDelPaso + volQuemado * cvSpot;
  //  end;
  //fIN bARCO DE ute TRAE CARGO


  CostoDelSuministro := costoDirectoDelPaso;
  //Tiene que tener todo lo del costo directo del paso - la falla de ANCAP
  if (self.bVentaTop = 1) then
  begin //Si hay una venta top y sólo parte del cargamento es de UTE, UTE hace frente del rechazo dando lo que necesitaba ANCAP de lo que tiene en el tanque
    self.VolFaltaAncap := min(0, Xs_VDisp_ToP - (V_ToP_sig - V_Efectivo_sig));
    //TODO : Pasar los números a ficha y a constantes
    //costoDirectoDelPaso := costoDirectoDelPaso + (-1*self.VolFaltaAncap)* 0.0097692 * (0.35*6400+0.65*800);
    Xs_VDisp_ToP := max(0, Xs_VDisp_ToP - (V_ToP_sig - V_Efectivo_sig));
  end;

end;



//Devuelve en cuantas horas se incrementa el arribo del spot por paso de tiempo
function TGNLSumComb_TakeOrPay_Spot.IncSpot(): double;
begin
  Result := ((MaxEstadoSpot - 2) / (T_Arribo * 24)) * (globs.HorasDelPaso);
end;


procedure TGNLSumComb_TakeOrPay_Spot.ArriboDeCargamentoSpot;
var
  Venta: boolean;
  DiasEsperaTotal: double;
  VolAnt: NReal;
begin
  self.bLlegadaSpot := 1;
  //Arribo un cargamento
  if V_Max - Xs_VDisp_ToP + k_Resto <= self.V_Spot[0] then
    //Si no hay espacio en el tanque al final del paso
  begin
{          //No hay espacio en el tanque, entonces una penalizacion y sigue esperando
          CostoDirectoDelPaso:= CostoDirectoDelPaso + pa.P_Espera*globs.HorasDelPaso/24;
           Xs_VCnt_Next_Spot := 1;
          //Dejo el estado tal cual....
          Entrada := 0;
          Espera:=3;
 }
    //No hay espacio en el tanque se devía el cargamento para ser vendido
    CostoDirectoDelPaso :=
      CostoDirectoDelPaso + pa.P_Espera * pa.T_Max_Espera - VentaSpot;
    self.CostoEspera := self.CostoEspera + pa.P_Espera * pa.T_Max_Espera;
    self.DiasEspera := self.DiasEspera + pa.T_Max_Espera;
    Xs_VCnt_Next_Spot := 0;
  end
  else //Hay lugar en el tanque
  begin
    DiasEsperaTotal := CalculoCostoEsperaParcial(
      self.fecha_Spot_sig, self.V_Spot[0], Venta);
    Xs_VCnt_Next_Spot := 0; //Llego el cargamento
    CostoDirectoDelPaso := CostoDirectoDelPaso + pa.P_Espera * DiasEsperaTotal;
    self.CostoEspera := self.CostoEspera + pa.P_Espera * DiasEsperaTotal;
    self.DiasEspera := self.DiasEspera + DiasEsperaTotal;
    //Venta:=false; //*******Se anulo la venta cuando hay lugar en el paso para relajar el problema ****************
    if Venta then
    begin
      CostoDirectoDelPaso := CostoDirectoDelPaso - VentaSpot; //Venta del Cargamento
    end
    else
    begin //si no tuvo que vender, descarga el cargamento
      VSobrante_ToP := Max(0, (Xs_VDisp_ToP + self.V_Spot[0]) - self.V_Max);
      VolAnt := Xs_VDisp_ToP;
      Xs_VDisp_ToP := Min(Xs_VDisp_ToP + self.V_Spot[0], self.V_Max);
      //Actualizo el estado, ingreso el combustible
      self.VolumenSpot := self.V_Spot[0];
      self.PrecioSpot := cvSpot * self.V_Spot[0];
      if (globs.EstadoDeLaSala = CES_SIMULANDO) and (Self.pa.hayCuentasEmbarques()) then //Las cuentas corrientes se tienen en cuenta sólo en la simulación
        TGNLBalance.GuardarEmbarque('URU', Xs_VDisp_ToP - VolAnt);
      self.Entrada := self.Entrada + 1;
      self.bEntradaSpot := 1;

    end;
  end;
end;


function TGNLSumComb_TakeOrPay_Spot.VentaSpot: double;
begin
  self.bVentaSpot := 1;
  Result := VentaCombustible(self.V_Spot[0], cvSpot);
end;

function TGNLSumComb_TakeOrPay_Spot.VentaToP: double;
begin
  self.bVentaTop := 1;
  Result := VentaCombustible(self.V_Efectivo_sig, pa.P_ToP);
end;

function TGNLSumComb_TakeOrPay_Spot.VentaCombustible(Volumen: double; cvCargamento: double): double;
var
  GananciaXVenta: double;
begin
  //Precio de compra (Ex - ship) +transporte a URU - (85% del precio de Henry Hub - Costo de transporte al GDM)* 94%
  GananciaXVenta := (0.85 * cvVenta - 0.036905381) * 0.94 * Volumen;
  self.Venta := self.Venta + GananciaXVenta;
  Result := GananciaXVenta;
end;



function TGNLSumComb_TakeOrPay_Spot.CalculoCostoEsperaParcial(FechaArribo: TDateTime; Volumen: NReal; var Vender: boolean): double;
var
  x, y1, y2, x1, x2: NReal;
  HoraEntrada: double;
  DiasEsperaTotal: double;
  OpHorasEspera: integer;
begin
  //Demora por operabilidad
  OpHorasEspera := OpTiempoDescarga - K_TotHorasDescarga;
  Vender := False;
  //***Cuando entra en esta rutina seguro tiene que haber al final del paso lugar para el cargamento***
  if self.V_Max >= (X_VDisp_ToP + Volumen - K_Resto) then
  begin //si ya existía capacidad para el volumen antes de empezar el paso no espero nada
    Result := 0;
    DiasEsperaTotal := 0;
    //la espera para este caso es la de operabilidad por eso no se calcula nada aca
  end
  else
  begin //Si el lugar se hizo dentro del paso
    x1 := X_VDisp_ToP;
    if Fase = 1 then
    begin
      x2 := x1 - self.VConsumido_ToP - k_Resto;
      x := self.V_Max - Volumen + K_Resto;
    end
    else
    begin
      x2 := x1 - self.VConsumido_ToP;
      x := self.V_Max - Volumen;
    end;

    y1 := 0;
    y2 := globs.HorasDelPaso;

    HoraEntrada := InterpolacionLineal(x, x1, x2, y1, y2);
    DiasEsperaTotal := Round(HoraEntrada / 24) -
      (FechaArribo - globs.FechaInicioDelpaso.AsDt);
  end;

  DiasEsperaTotal := Max(DiasEsperaTotal, OpHorasEspera / 24);
  OpeDescargaPrint := OpHorasEspera;
  if DiasEsperaTotal > pa.T_Max_Espera then
  begin //Si la espera es mayor que el tiempo máximo de espera tiene que vender
    DiasEsperaTotal := pa.T_Max_Espera;
    Vender := True;
  end;
  Result := DiasEsperaTotal; //Devuelve la espera en días con decimales
end;


function TGNLSumComb_TakeOrPay_Spot.InterpolacionLineal(x, x1, x2, y1, y2: double): double;
begin
  if x2 <> x1 then
    Result := (((x - x1) / (x2 - x1)) * (y2 - y1)) + y1
  else
    Result := y1;
end;

procedure TGNLSumComb_TakeOrPay_Spot.EvolucionarEstado;
var
  nuevoEstadoAg, nuevoEstadoRCarg, deltaEstadoAg, deltaEstadoRCarg, maxAg, i: integer;
  maxDelta, delta: NReal;
  fechaNextCambioAg, fechaNextCambioCarg: TDateTime;
  ag: TAgendaEmbarque;
begin
  X_VDisp_ToP := max(Xs_VDisp_ToP, 0);
  X_VCnt_Next_Spot := Xs_VCnt_Next_Spot;

  fechaNextCambioAg := pa.GetSiguienteCambioAgenda(globs.FechaInicioDelpaso.dt);
  if (pa.agendas.Count > 1) and (fechaNextCambioAg >= globs.FechaInicioDelpaso.dt) and
    (fechaNextCambioAg <= globs.FechaFinDelpaso.dt) then
  begin
    maxDelta := 0;
    maxAg := agendaActiva;
    for i := 0 to pa.agendas.Count - 1 do
    begin
      //      nuevoEstado := (i + agendaActiva) mod (pa.agendas.count);
      nuevoEstadoAg := i;
      deltaEstadoAg := nuevoEstadoAg - agendaActiva;
      if globs.EstadoDeLaSala = CES_OPTIMIZANDO then
        delta := globs.CF.deltaCosto_vxd_estrella(ixd, globs.kPaso_ + 1, deltaEstadoAg)
      else
        delta := globs.CF.deltaCosto_vxd_continuo(ixd, globs.kPaso_ + 1, deltaEstadoAg);
      //      delta := globs.CF.deltaCosto_vxd_estrella( ixd , globs.kPaso_+1, nuevoEstado );
      if delta < maxDelta then
      begin
        maxDelta := delta;
        maxAg := nuevoEstadoAg;
      end;
    end;

    agendaActiva := maxAg;
  end;
  //  globs.CF.xd[ixd] := agendaActiva

  // cambiar el estado a la nueva agenda activa
  if hayRechazoEmbarques then
  begin
    if globs.CF.xd[ixd_rechazoEmbarques] = 0 then
    begin
      ag := pa.agendas.items[agendaActiva] as TAgendaEmbarque;
      ag.GetFechaIntermediaSiguienteToP(globs.FechaInicioDelpaso.dt,
        fechaNextCambioCarg, globs);
      fechaNextCambioCarg := fechaNextCambioCarg;
      if (self.hayRechazoEmbarques) and (fechaNextCambioCarg >=
        globs.FechaInicioDelpaso.dt) and (fechaNextCambioCarg <= globs.FechaFinDelpaso.dt) then
      begin
        deltaEstadoRCarg := 1;
        if globs.EstadoDeLaSala = CES_OPTIMIZANDO then
          delta := globs.CF.deltaCosto_vxd_estrella(
            ixd_rechazoEmbarques, globs.kPaso_ + 1, deltaEstadoRCarg)
        else
          delta := globs.CF.deltaCosto_vxd_continuo(
            ixd_rechazoEmbarques, globs.kPaso_ + 1, deltaEstadoRCarg);
        if delta < 0 then
        begin
          saltearCargamento := True;
        end;
      end;
    end
    else
    begin
      saltearCargamento := True;
    end;
  end;
end;

function TGNLSumComb_TakeOrPay_Spot.getNombreVar(ivar: integer; var nombre: string): boolean;
var
  iposte: integer;
begin

  if X_VDisp_ToP = 0 then
    exit(False); //Si no hay combustible no tiene sentido estar en la matríz

  if ((ivar >= self.ivar) and (ivar <= k_VarCVConsTot - 1)) then
  begin
    iposte := ivar - self.ivar;
    nombre := self.Nombre + '_VCons_' + IntToStr(iposte + 1);
    Result := True;
  end
  else

  if (ivar = k_VarCVConsTot) then
  begin
    nombre := self.Nombre + '_VCons_Top';
    Result := True;
  end
  else
{      if (ivar = k_VarCCompra) then
         begin
          nombre:= self.Nombre + '_Comprar';
          result:= true;
         end
      else
        if (ivar = k_VarCRetraso) then
           begin
            nombre:= self.Nombre + '_Retraso';
            result:= true;
           end
        else}
    Result := False;
end;

function TGNLSumComb_TakeOrPay_Spot.getNombreRes(ires: integer; var nombre: string): boolean;
var
  iposte: integer;
begin
  if X_VDisp_ToP = 0 then
    exit(False); //Si no hay combustible no tiene sentido estar en la matríz


  if ((ires >= self.ires) and (ires <= k_ResFVConsTot - 1)) then
  begin
    iposte := ires - self.ires;
    nombre := self.Nombre + '_Consumido_' + IntToStr(iposte + 1);
    Result := True;
  end
  else
  if ires = k_ResFVConsTot then
  begin
    nombre := self.Nombre + '_Consumido_Total';
    Result := True;
  end;


  Result := False;
end;

procedure TGNLSumComb_TakeOrPay_Spot.PubliVars;
var
  unidades: string;
  i: NInt;
begin
  inherited PubliVars;

  unidades := self.combustible.Unidades;

  PublicarVariableNR('VConsumido_ToP', 'm3', 6, 1, VConsumido_ToP, True);
  PublicarVariableNR('VDisponible_ToPAux', 'm3', 6, 1, X_VDisp_ToP, True);
  PublicarVariableNR('VSobrante_ToP', 'm3', 6, 1, VSobrante_ToP, True);
  PublicarVariableNR('CostoVariableCombustible', 'USD/m3', 6, 6, cvToP, True);
  PublicarVariableNR('CostoDirectoDelPaso', 'USD', 6, 1, CostoDelSuministro, True);
  PublicarVariableNI('Fase', '-', fase, True);
  PublicarVariableNR('Compra', '-', 6, 1, ComprarCargamento, True);
  PublicarVariableNI('LlegadaSpot', '-', bLlegadaSpot, True);
  PublicarVariableNR('Retraso', '-', 6, 1, RetrasarCargamento, True);
  PublicarVariableNI('Entrada', '-', Entrada, True);
  PublicarVariableNI('EntradaTop', '-', bEntradaTop, True);
  PublicarVariableNI('EntradaSpot', '-', bEntradaSpot, True);
  PublicarVariableNI('Espera', '-', Espera, True);
  PublicarVariableNR('DiasEspera', 'Dias', 6, 1, DiasEspera, True);
  PublicarVariableNI('VentaTop', '-', bVentaTop, True);
  PublicarVariableNI('VentaSpot', '-', bVentaSpot, True);
  PublicarVariableNR('CostoCompra', 'USD', 6, 1, CostoCompra, True);
  PublicarVariableNR('CostoEspera', 'USD', 6, 1, CostoEspera, True);
  PublicarVariableNR('ImporteVenta', 'USD', 6, 1, Venta, True);
  PublicarVariableNR('PrecioSpot', 'USD', 6, 1, PrecioSpot, True);
  PublicarVariableNR('PrecioTOP', 'USD', 6, 1, PrecioTOP, True);
  PublicarVariableNR('VolumenSpot', 'm3', 6, 1, VolumenSpot, True);
  PublicarVariableNR('VolumenTOP', 'm3', 6, 1, VolumenTOP, True);
  PublicarVariableNR('BOG_T', 'm3', 6, 1, BOG_T, True);
  PublicarVariableNR('BOG_GSS', 'm3', 6, 1, BOG_GSS, True);
  PublicarVariableNR('BOG_RG', 'm3', 6, 1, BOG_RG, True);
  PublicarVariableNR('BOG_RC', 'm3', 6, 1, BOG_RC, True);
  PublicarVariableNR('BOG_RL', 'm3', 6, 1, BOG_RL, True);
  PublicarVariableNR('BOG_GRL', 'm3', 6, 1, BOG_GRL, True);
  PublicarVariableNR('BOG_Vent', 'm3', 6, 1, BOG_Vent, True);
  PublicarVariableNR('BSO', 'm3', 6, 1, BSO, True);
  PublicarVariableNR('FaltanteAncap', 'm3', 6, 1, self.VolFaltaAncap, True);
  PublicarVariableNR('VolQuemado', 'm3', 16, 2, self.volQuemado, True);
  PublicarVariableNI('Quemo', '-', bQuemo, True);
  PublicarVariableNI('AgendaActiva', '-', self.agendaActiva, True);
  //   PublicarVariableNR('Dfdc', '-', 6, 1, dCFdCn, true);
  //   PublicarVariableNR('delta', '-', 6, 1, delta, true);
  //   PublicarVariableS('F_ProxArribo', '-', DateToStr(F_Arribo), true);
  //   PublicarVariableNR('V_ProxArribo', 'm3', 6, 1, V_ProxCargamento, true);
  //   PublicarVariableNR('X_Vcnt_Next_Spot', '-', 6, 1, X_VCnt_Next_Spot, true);
  PublicarVariableNR('CanonFijoXPaso', 'USD', 6, 1, CanonFijoXPaso, True);
  //   PublicarVariableNR('OperatividadDescarga', 'días', 6, 2, OpeDescargaPrint, true);
  //   if length(PorcOpRegasificacion)>1 then
  //      PublicarVariableVR('OperatividadRegasificación', '%', 4, 2, PorcOpRegasificacion,true, true)
  //   else
  //      PublicarVariableNR('OperatividadRegasificación', '%', 4, 2, PorcOpRegasificacion[0], true);

  TGNLBalance.ImprimirBalance(TCosaParticipeDeMercado(self));

end;

class function TGNLSumComb_TakeOrPay_Spot.CreateDataColumnList(xVersion: integer): TDataColumnListOfCosa;
begin
  
















end;

procedure TGNLSumComb_TakeOrPay_Spot.AfterInstantiation;
begin
  inherited AfterInstantiation;
  pa := nil;
  agendaActiva := 0;
end;

class function TGNLSumComb_TakeOrPay_Spot.CreateDataConversionList: TListDataConversion;
begin
  Result := inherited CreateDataConversionList;
  Result.Add(uConversions.VERSION_MIGRACION_PERSISTENCIA, ['B_HayRechazoEmbarque'], ['hayRechazoEmbarques'], Result.ConversionNAMECHANGE);
end;

procedure TGNLSumComb_TakeOrPay_Spot.optx_nvxs(var ixr, ixd, iauxr, iauxd: integer);
var
  f, maxAgenda: integer;
  f_a: TGNLFichaSumComb_TakeOrPay_Spot;
begin
  self.ixr := ixr;
  if self.T_Arribo = 0 then //Si no hay spot
    ixr := ixr + 1
  else //si hay spot
    ixr := ixr + 2;


  self.ixd := ixd;
  if maxAgendas > 1 then
  begin
    ixd := ixd + 1; //variable de estado de la agenda
  end;
  if hayRechazoEmbarques then
  begin
    self.ixd_rechazoEmbarques := ixd;
    ixd := ixd + 1; //variable de estado de la agenda
  end;

end;

procedure TGNLSumComb_TakeOrPay_Spot.PosicionarseEnEstrellita;
//var
//  myFile: TextFile;
begin
  X_VDisp_ToP := globs.CF.xr[ixr];
  if self.T_Arribo <> 0 then //si hay spot
    X_VCnt_Next_Spot := globs.CF.xr[ixr + 1]
  else
    X_VCnt_Next_Spot := 0;

  if maxAgendas > 1 then
  begin
    if pa.agendas.Count > 1 then
      agendaActiva := globs.CF.xd[ixd]
    else
    begin
      agendaActiva := 0;
      globs.CF.xd[ixd] := 0;
    end;
  end;

  if hayRechazoEmbarques then
  begin
    if globs.CF.xd[ixd_rechazoEmbarques] = 1 then
      saltearCargamento := True
    else
      saltearCargamento := False;
  end;
  //  AssignFile(myFile, '_salida.txt');
  //  Append(myFile);


  //  writeln(myFile, 'PosicionarseEnEstrellita'#9, dateToStr(globs.FechaInicioDelpaso.dt), #9'Estado (r,d):'#9, formatFloat('#####', globs.CF.xr[0]), #9, globs.CF.xd[0], ''#9'agendaActiva'#9, agendaActiva);


  //  CloseFile(myFile);
end;

procedure TGNLSumComb_TakeOrPay_Spot.ActualizarEstadoGlobal;
begin
  globs.CF.xr[ixr] := X_VDisp_ToP;
  if self.T_Arribo <> 0 then //si hay spot, sino no existe la variable de estado
    globs.CF.xr[ixr + 1] := X_VCnt_Next_Spot;

  if maxAgendas > 1 then
  begin
    if pa.agendas.Count > 1 then
      globs.CF.xd[ixd] := agendaActiva
    else
    begin
      agendaActiva := 0;
      globs.CF.xd[ixd] := 0;
    end;
  end;

  if hayRechazoEmbarques then
  begin
    if (fase = 1) then
    begin
      globs.CF.xd[ixd_rechazoEmbarques] := 0;
      self.saltearCargamento := False;
    end
    else if self.saltearCargamento then
      globs.CF.xd[ixd_rechazoEmbarques] := 1;
  end;
end;

procedure TGNLSumComb_TakeOrPay_Spot.optx_RegistrarVariablesDeEstado(adminEstados: TAdminEstados);
begin
  adminEstados.Registrar_Continua(
    ixr,
    0.0,
    V_Max,
    NDisc,
    nombre + '_V_Disponible_ToP', // nombre de la variable
    combustible.Unidades // unidades
    );

  //adminEstados.Registrar_Discreta( ixd, 2, Self.Nombre + '_V_Proximo_Spot', 'bool')

  if self.T_Arribo <> 0 then //si hay spot
    adminEstados.Registrar_Continua(
      ixr + 1,
      0.0,
      MaxEstadoSpot,
      NDiscDiasSpot, // Número de dicretizaciones tiene que ser = 2*n+3
      nombre + '_V_Proximo_Spot', // nombre de la variable
      'Dias' // unidades
      );

  if pa.agendas.Count > 1 then
    adminEstados.Registrar_Discreta(
      ixd,
      pa.agendas.Count,
      nombre + '_Agendas_Utilizadas',
      '-'
      );

  if (self.hayRechazoEmbarques) then
    adminEstados.Registrar_Discreta(
      self.ixd_rechazoEmbarques,
      2,
      nombre + '_Rechazo_Embarque_ToP',
      '-'
      );

end;


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

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

procedure TGNLSumComb_TakeOrPay_Spot_cambioFichaPD(Actor: TCosa);
begin
end;


procedure AlInicio;
begin
  registrarClaseDeCosa(TGNLSumComb_TakeOrPay_Spot.ClassName,
    TGNLSumComb_TakeOrPay_Spot);
  registrarClaseDeCosa(TGNLFichaSumComb_TakeOrPay_Spot.ClassName,
    TGNLFichaSumComb_TakeOrPay_Spot);
end;

procedure AlFinal;
begin
end;


end.
