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

interface

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

type

  { TGNLFichaSumIntermedio }

  TGNLFichaSumIntermedio = class(TFichaSuministroCombustible)

  protected
    









  public
{
      T_ToP: NInt; // [dias] Tiempo de Take or Pay.
      V_ToP: NReal; // [unidad e Volumen] Volumen comprometido por el contrato Take Or Pay
      P_ToP: NReal; // [U$] Precio por Unidad de Volumen de combustible dentro del comprometido por Take or Pay
      P_ExtraToP: NReal; // [U$] Precio por Unidad de Volumen de combustible consumido por encima del volumen comprometido por Take or Pay
}

     
    indicePreciosPorCombustibleMayorSO: TFuenteAleatoria;
    //Para ajustar los precios de combustible en los períodos T_ToP
    bornePreciosPorCombustibleMayorSO: string;
    CanonFijo: TFuenteAleatoria;
    //Para ajustar los precios de combustible en los períodos T_ToP
    borneCanonFijo: string;
    CuentaCorriente: string;
  

    nroBornePreciosPorCombustibleMayorSO: integer;
    nroBorneCanonFijo: integer;


    constructor Create(capa: integer; fecha: TFecha; periodicidad: TPeriodicidad; nombrecombustible: string; indicePreciosPorCombustible: TFuenteAleatoria; bornePreciosPorCombustible: string; indicePreciosPorCombustibleMayorSO: TFuenteAleatoria; bornePreciosPorCombustibleMayorSO: string; CanonFijo: TFuenteAleatoria; borneCanonFijo: string; CuentaCorriente: string);


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

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

    




  published
    







  end;

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

  { TGNLSumIntermedio }

  TGNLSumIntermedio = class(TSuministroCombustible)
  protected
    CV_Peaje: NReal;            //Costo variable de circulación de gas
    CV_MayorSO: NReal;          //Costo variable por encima del S.O.Máximo
    CanonFijo: NReal;           //Canon Fijo
    ConsumoXPoste: TDAofNReal; //Caudal por poste por debajo del Sendout Máximo
    ConsumoXPosteMayorSO: TDAofNReal; //Caudal por poste por encima del Sendout Máximo

  public

    (**************************************************************************)
    (*               A T R I B U T O S   P E R S I S T E N T E S              *)
    (**************************************************************************)

    cliente: TSuministroCombustible;

    (**************************************************************************)

    pa: TGNLFichaSumIntermedio;

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


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

    function CantVCons: integer;
    function get_ires_volumen: NInt; override;
    function get_precio_combustible: NReal; override;
    function get_combustible: TCombustibleSGE; override;
    function get_VolCombustibleDisponible: NReal; override;

    class function TipoFichaLPD: TClaseDeFichaLPD; virtual; abstract;
    procedure Free; override;
    class function DescClase: string; override;


    procedure setCliente(cli: TSuministroCombustible);

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


    procedure Sim_Cronica_Inicio; override;

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

    procedure opt_cargue(s: TSimplex); 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;


    // 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 PubliVars; override;
    function restricciones_postizadas: boolean; override;

    


    procedure AfterInstantiation; override;

  published
    



  end;

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

implementation
//------------------------------
// Métodos de TFichaSuministroCombustible_TakeOrPay
//==============================
constructor TGNLFichaSumIntermedio.Create(capa: integer; fecha: TFecha; periodicidad: TPeriodicidad; nombrecombustible: string; indicePreciosPorCombustible: TFuenteAleatoria; bornePreciosPorCombustible: string; indicePreciosPorCombustibleMayorSO: TFuenteAleatoria; bornePreciosPorCombustibleMayorSO: string; CanonFijo: TFuenteAleatoria; borneCanonFijo: string; CuentaCorriente: string);

begin
  inherited Create(capa, fecha, periodicidad, nombrecombustible,
    indicePreciosPorCombustible, bornePreciosPorCombustible);
  self.indicePreciosPorCombustibleMayorSO := indicePreciosPorCombustibleMayorSO;
  self.bornePreciosPorCombustibleMayorSO := bornePreciosPorCombustibleMayorSO;
  self.CanonFijo := CanonFijo;
  self.borneCanonFijo := borneCanonFijo;
  self.CuentaCorriente := CuentaCorriente;
end;

 
constructor TGNLFichaSumIntermedio.Create_ReadFromText(f: TArchiTexto);
begin
  inherited Create_ReadFromText(f);
  f.IniciarLecturaRetrasada;
  f.rdReferencia('indicePreciosPorCombustibleMayorSO',
    TCosa(indicePreciosPorCombustibleMayorSO), self);
  f.rd('bornePreciosPorCombustibleMayorSO', bornePreciosPorCombustibleMayorSO);
  f.rdReferencia('CanonFijo', TCosa(CanonFijo), self);
  f.rd('borneCanonFijo', borneCanonFijo);
  f.rd('CuentaGN', CuentaCorriente);
  f.EjecutarLectura;
end;

procedure TGNLFichaSumIntermedio.WriteToText(f: TArchiTexto);
begin
  inherited WriteToText(f);
  f.wrReferencia('indicePreciosPorCombustibleMayorSO',
    indicePreciosPorCombustibleMayorSO);
  f.wr('bornePreciosPorCombustibleMayorSO', bornePreciosPorCombustibleMayorSO);
  f.wrReferencia('CanonFijo', CanonFijo);
  f.wr('borneCanonFijo', borneCanonFijo);
  f.wr('CuentaGN', CuentaCorriente);
end;



function TGNLFichaSumIntermedio.infoAd_: string;
begin
  Result := inherited  infoAd_;
end;

procedure TGNLFichaSumIntermedio.Free;
begin
  inherited Free;
end;





















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

constructor TGNLSumIntermedio.Create(capa: integer; nombre: string; nombreCombustible: string; nacimiento, muerte: TFecha; lpdUnidades, lpd: TFichasLPD; cli: TSuministroCombustible);
begin
  inherited Create(capa, nombre, nombreCombustible, nacimiento, muerte, lpdUnidades, lpd);
  self.setCliente(cli);
end;

procedure TGNLSumIntermedio.setCliente(cli: TSuministroCombustible);
begin
  self.cliente := cli;
end;

 
constructor TGNLSumIntermedio.Create_ReadFromText(f: TArchiTexto);
begin
  inherited Create_ReadFromText(f);
  f.IniciarLecturaRetrasada;
  f.rdReferencia('cliente', TCosa(cliente), self);
  f.EjecutarLectura;
  pa := nil;
end;

procedure TGNLSumIntermedio.WriteToText(f: TArchiTexto);
begin
  inherited WriteToText(f);
  f.wrReferencia('cliente', TCosa(cliente));
end;


procedure TGNLSumIntermedio.PrepararMemoria(globs: TGlobs);
begin
  inherited prepararMemoria(globs);
  setlength(ConsumoXPoste, globs.NPostes);
  setlength(ConsumoXPosteMayorSO, globs.NPostes);
end;


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

function TGNLSumIntermedio.get_precio_combustible: NReal;
begin
  Result := cliente.get_precio_combustible;
end;


function TGNLSumIntermedio.get_VolCombustibleDisponible: NReal;
begin
  Result := self.cliente.get_VolCombustibleDisponible;
end;

function TGNLSumIntermedio.get_combustible: TCombustibleSGE;
begin
  Result := cliente.get_combustible;
end;

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

    if ficha.indicePreciosPorCombustibleMayorSO <> nil then
      ficha.nroBornePreciosPorCombustibleMayorSO :=
        ficha.indicePreciosPorCombustibleMayorSO.IdBorne(
        ficha.bornePreciosPorCombustibleMayorSO);

    if ficha.CanonFijo <> nil then
      ficha.nroBorneCanonFijo := ficha.CanonFijo.IdBorne(ficha.borneCanonFijo);

  end;
end;


function TGNLSumIntermedio.restricciones_postizadas: boolean;
begin
  Result := cliente.restricciones_postizadas;
end;









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

procedure TGNLSumIntermedio.Free;
begin
  inherited Free;
end;

class function TGNLSumIntermedio.DescClase: string;
begin
  Result := 'Suministro Intermedio';
end;


procedure TGNLSumIntermedio.opt_nvers(var ivar, ivae, ires: integer);
begin
  //si no hay combustible no va al simplex
  if (self.cliente.get_VolCombustibleDisponible = 0) then
    exit;
  self.ivar := ivar; //CAntidad de variables (columnas)
  self.ires := ires;  //Cantidad de restricciones (filas)


  ivar := ivar + CantVCons * 2; // Columnas de VEntrada y VSalida
  ires := ires + CantVCons;  // 1 restricción. de salida de combustible
end;

function TGNLSumIntermedio.CantVCons: integer;
  //Varía los indices si es un suministro postizado o no
begin
  if restricciones_postizadas then
    Result := globs.NPostes
  else
    Result := 1;
end;


procedure TGNLSumIntermedio.opt_cargue(s: TSimplex);
var
  ires_volumen_cliente: integer;
  iposte: integer;
begin
  if pa.indicePreciosPorCombustible <> nil then
    CV_Peaje := pa.indicePreciosPorCombustible.bornera[
      pa.nroBornePreciosPorCombustible]
  else
    CV_Peaje := 0;

  if pa.indicePreciosPorCombustibleMayorSO <> nil then
    CV_MayorSO := pa.indicePreciosPorCombustibleMayorSO.bornera[
      pa.nroBornePreciosPorCombustibleMayorSO]
  else
    CV_MayorSO := 0;

  if pa.CanonFijo <> nil then
    CanonFijo := pa.CanonFijo.bornera[pa.nroBorneCanonFijo] * (globs.HorasDelPaso / 24)
  else
    CanonFijo := 0;

  //si no hay combustible no va al simplex
  if (self.cliente.get_VolCombustibleDisponible = 0) then
    exit;


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



  //Indice donde arranca el que me brinda combustible
  ires_volumen_cliente := cliente.get_ires_volumen;

  for iposte := 0 to CantVCons() - 1 do
  begin
    s.pon_e(ires_volumen_cliente + iposte, ivar + iposte, 1);
    //Restricción de entrada de volumen por debajo del sendout max
    s.pon_e(self.ires + iposte, ivar + iposte, -1);
    //Restricció de salida por debajo del sendout max
    s.pon_e(s.nf, ivar + iposte, -1 * CV_Peaje);
    //Aca va el costo variable del gasoducto por debajo del sendout máximo
    s.pon_e(ires_volumen_cliente + iposte, ivar + iposte + CantVCons(), 1);
    //Restricción de entrada de volumen por encima del sendout max
    s.pon_e(self.ires + iposte, ivar + iposte + CantVCons(), -1);
    //Restricció de salida por encima del sendout max
    s.pon_e(s.nf, ivar + iposte + CantVCons(), -1 * CV_MayorSO);
    //Aca va el costo variable del gasoducto por encima del sendout máximo
  end;
end;

procedure TGNLSumIntermedio.Sim_Cronica_Inicio;
begin
  inherited Sim_Cronica_Inicio;
end;

procedure TGNLSumIntermedio.opt_fijarRestriccionesDeCaja(s: TSimplex);
var
  iposte: integer;
begin
  //si no hay combustible no va al simplex
  if (self.cliente.get_VolCombustibleDisponible = 0) then
    exit;
  for iposte := 0 to CantVCons() - 1 do
  begin
    //restriccion de volumen consumido
    s.FijarRestriccionIgualdad(ires + iposte);
    //Si no hay precio para el volumen consumido por encima del somax, no deja consumir el mismo
    if pa.indicePreciosPorCombustibleMayorSO = nil then
      s.FijarVariable(ivar + CantVCons + iposte, 0);
  end;

end;

procedure TGNLSumIntermedio.opt_leerSolucion(s: TSimplex);
var
  iposte: integer;
  ConsumoTotal: double;
begin
  costoDirectoDelPaso := 0;
  if (self.get_VolCombustibleDisponible = 0) then
  begin
    vclear(ConsumoXPoste);
    vclear(ConsumoXPosteMayorSO);
    exit;
  end;

  for iposte := 0 to CantVCons - 1 do
  begin
    ConsumoXPoste[iposte] := s.xval(ivar + iposte);
    ConsumoXPosteMayorSO[iposte] := s.xval(ivar + iposte + CantVCons);
    costoDirectoDelPaso := costoDirectoDelPaso + ConsumoXPoste[iposte] *
      CV_Peaje + ConsumoXPosteMayorSO[iposte] * CV_MayorSO;
    ConsumoTotal := (ConsumoXPoste[iposte] + ConsumoXPosteMayorSO[iposte]);
  end;
  if (globs.EstadoDeLaSala = CES_SIMULANDO) and (pa.CuentaCorriente <> '') then
    TGNLBalance.CalculoCaudal(pa.CuentaCorriente, ConsumoTotal);

end;


function TGNLSumIntermedio.getNombreVar(ivar: integer; var nombre: string): boolean;
begin
  //si no hay combustible no va al simplex
  if (self.cliente.get_VolCombustibleDisponible = 0) then
  begin
    Result := False;
    exit;
  end;

  if (ivar < self.ivar + CantVCons) and (ivar >= self.ivar) then
  begin
    nombre := self.Nombre + 'SumIntermedio';
    Result := True;
  end
  else
  if (ivar < self.ivar + CantVCons * 2) and (ivar >= self.ivar + CantVCons) then
  begin
    nombre := self.Nombre + 'SumIntermedioMaySO';
    Result := True;
  end
  else
    Result := False;

end;

function TGNLSumIntermedio.getNombreRes(ires: integer; var nombre: string): boolean;
begin
  if (self.cliente.get_VolCombustibleDisponible = 0) then
  begin
    Result := False;
    exit;
  end;

  if (ires < self.ires + CantVCons) and (ires >= self.ires) then
  begin
    nombre := self.nombre + '_VolumenDespachado';
    Result := True;
  end
  else
    Result := False;
end;

procedure TGNLSumIntermedio.PubliVars;
var
  unidades: string;
  ficha: TGNLFichaSumIntermedio;
  i: NInt;
  CostoTotal: NReal;
begin
  inherited PubliVars;

  unidades := self.combustible.Unidades;

  PublicarVariableVR('Caudal', '[' + cliente.combustible.Unidades +
    ']', 6, 1, ConsumoXPoste, True, True);
  PublicarVariableVR('CaudalMaySO', '[' + cliente.combustible.Unidades +
    ']', 6, 1, ConsumoXPosteMayorSO, True, True);
  PublicarVariableNR('Costo_Fijo', '', 6, 1, CanonFijo, True);
  PublicarVariableNR('Costo_Variable', '', 6, 1, costoDirectoDelPaso, True);
end;


procedure TGNLSumIntermedio.opt_PrintResultados_Encab(var fsal: textfile);
begin
end;

procedure TGNLSumIntermedio.opt_PrintResultados(var fsal: textfile);
begin
end;

procedure TGNLSumIntermedio_cambioFichaPD(Actor: TCosa);
begin
end;

procedure AlInicio;
begin
  registrarClaseDeCosa(TGNLSumIntermedio.ClassName, TGNLSumIntermedio);
  registrarClaseDeCosa(TGNLFichaSumIntermedio.ClassName, TGNLFichaSumIntermedio);
end;

procedure AlFinal;
begin
end;

end.
