with Ada.Integer_Text_IO, Globals, Strings;
use Globals, Strings;

pragma Elaborate_All (Ada.Integer_Text_IO,Globals,Strings);

package body Vectors is

  package Int_IO renames Ada.Integer_Text_IO;

  function EffFirst(V: Vector) return Integer is
  begin
    for N in V'First .. V'Last-1 loop
      if not IsZero(V(N)) then return N; end if;
    end loop;
    return V'Last;
  end EffFirst;

  function EffLast(V: Vector) return Integer is
  begin
    for N in reverse V'First+1 .. V'Last loop
      if not IsZero(V(N)) then return N; end if;
    end loop;
    return V'First;
  end EffLast;

  procedure Trim(F,L: in Integer; V: in out Vector) is
  begin
    for K in V'Range loop
      if (K<F) or (K>L) then SetZero(V(K)); end if;
    end loop;
  end Trim;

  -----------------------

  function "="(V1,V2: Vector) return Boolean is
  begin
    if (V1'First /= V2'First) or else (V1'Last /= V2'Last) then return False; end if;
    for N in V1'Range loop
      if not (V1(N)=V2(N)) then return False; end if;
    end loop;
    return True;
  end "=";

  procedure SetZero(F,L: in Integer; V: in out Vector) is
  begin
    for N in F .. L loop
      SetZero(V(N));
    end loop;
  end SetZero;

  function ZeroVector(F,L: Integer) return Vector is
    V: Vector(F..L);
  begin
    SetZero(V);
    return V;
  end ZeroVector;

  ------------------

  procedure Show1(N: in String; V: in Vector; Hide0: in Boolean := True) is
    W: constant Positive := 5;
    AllZero: Boolean := True;
  begin
    for K in V'Range loop
      if not IsZero(V(K)) then
        Show1(N & Strng(K,W) & " ",V(K));
        AllZero := False;
      end if;
    end loop;
    if not Hide0 then
      if AllZero then Show0(N & "0"); end if;
      Show0;
    end if;
  end Show1;

  procedure Show2(N: in String; V1,V2: in Vector; Hide0: in Boolean := True) is
    W: constant Positive := 5;
    KFirst: constant Integer := Integer'Min(V1'First,V2'First);
    KLast: constant Integer := Integer'Max(V1'Last,V2'Last);
    AllZero: Boolean := True;
  begin
    for K in KFirst .. KLast loop
      if not (IsZero(V1(K)) and then IsZero(V2(K))) then
        Show2(N & Strng(K,W) & " ",V1(K),V2(K));
        AllZero := False;
      end if;
    end loop;
    if not Hide0 then
      if AllZero then Show0(N & "0 0"); end if;
      Show0;
    end if;
  end Show2;

  procedure PutDim(F: in File_Type; L: in Positive) is
  begin
    Int_IO.Put(F,L);
    New_Line(F);
  end PutDim;

  procedure PutCoeffs(F: in File_Type; V: in Vector; Decimal: in Boolean := False) is
  begin
    for I in V'Range loop
       Put(F,V(I),Decimal);
    end loop;
  end PutCoeffs;

  procedure Put(F: in File_Type; V: in Vector; Decimal: in Boolean := False) is
  begin
    PutDim(F,V'Length);
    PutCoeffs(F,V,Decimal);
  end Put;

  function Get(F: File_Type; First: Integer; Decimal: Boolean := False) return Vector is
    L: Integer;
  begin
    Int_IO.Get(F,L);
    declare
      subtype VRange is Integer range First .. First+L-1;
      V: Vector(VRange);
    begin
      for M in VRange loop
        Get(F,V(M),Decimal);
      end loop;
      return V;
    end;
  end Get;

  procedure Get(F: in File_Type; V: in out Vector; Decimal: in Boolean := False) is
    Trunc: Boolean := False;
    L: Integer;
    C: Component;
  begin
    SetZero(V);
    Int_IO.Get(F,L);
    declare
      subtype VRange is Integer range V'First .. V'First+L-1;
    begin
      for M in VRange loop
        if M <= V'Last then
          Get(F,V(M),Decimal);
        else
          Get(F,C,Decimal);
          Trunc := Trunc or else not IsZero(C);
        end if;
      end loop;
    end;
    if Trunc then
      Show0("Vectors.Get Warning: input vector truncated");
    end if;
  end Get;

  procedure Write(FileName: in String; V: in Vector; Decimal: in Boolean := False) is
    F: File_Type;
  begin
    if Verbosity>1 then Show0("Writing " & FileName); end if;
    Create(F,Out_File,FileName);
    Put(F,V,Decimal);
    Close(F);
  end Write;

  function Read(FileName: String; First: Integer; Decimal: Boolean := False) return Vector is
    F: File_Type;
  begin
    if Verbosity>0 then Show0("Reading " & FileName); end if;
    Open(F,In_File,FileName);
    declare
      V: constant Vector := Get(F,First,Decimal);
    begin
      Close(F);
      return V;
    end;
  end Read;

  procedure Read(FileName: in String; V: in out Vector; Decimal: in Boolean := False) is
    F: File_Type;
  begin
    if Verbosity>0 then Show0("Reading " & FileName); end if;
    Open(F,In_File,FileName);
    Get(F,V,Decimal);
    Close(F);
  end Read;

  procedure Append(FileName: in String; V: in Vector; Decimal: in Boolean := False) is
    F: File_Type;
  begin
    if Verbosity>0 then Show0("Appending " & FileName); end if;
    begin
      Open(F,Append_File,FileName);
    exception
      when Name_Error => Create(F,Out_File,FileName);
    end;
    Put(F,V,Decimal);
    Close(F);
  end Append;

end Vectors;
