with Strings, Globals;
use Strings, Globals;

pragma Elaborate_All (Globals,Strings);

package body Taylors1.Cheb is

   use SVT;

   procedure Center(F: in out Traj) is
   begin
      for I in Index loop
         Center(F(I));
      end loop;
   end Center;

   procedure Mult(S: in TScalar; F: in out Traj) is
   begin
      for I in Index loop
         Mult(S,F(I));
      end loop;
   end Mult;

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

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

   function MaxNorm(F: Traj) return Radius is
      R: Radius := Zero;
   begin
      for I in Index loop
         R := R+MaxNorm(F(I));
      end loop;
      return R;
   end MaxNorm;

   procedure AddBall(R: in Radius; F: in out Traj) is
      B: constant TayCheb := BallAt0(R);
      C: constant TScalar := BallAt0(R);
   begin
      for I in Index loop
         Add(B,F(I));
      end loop;
   end AddBall;

   procedure Norm(M: in TrajMode; S: in out Scalar) is
      J: EFreq renames M.J;
   begin
      if M.Err then
         Copy(SOne,S);  --- error modes have norm 1
      else
         declare
            W,Tmp: Scalar;
         begin
            Assign(M.R,W);
            IPower(J,W,S,Tmp);
         end;
      end if;
   end Norm;

   procedure MaxNorm(M: in TrajMode; S: out Radius) is
      J: EFreq renames M.J;
   begin
      if M.Err then
         S := One;      --- error modes have norm 1
      else
         S := M.R**J;
      end if;
   end MaxNorm;

   procedure Assign(M: in TrajMode; Q: in out Traj) is
      --- assuming that M is fine
      I: Index renames M.I;
      J: EFreq renames M.J;
      L: Power renames M.L;
   begin
      SetZero(Q);
      for I in Index loop
         Q(I).R := M.R;
      end loop;
      if M.Err then
         Q(I).E(J) := One;
      else
         Add_Coeff(L,SOne,Q(I).C(J));
      end if;
   end Assign;

   procedure AddProd(M: in TrajMode; S: in Scalar; Q: in out Traj; Check: in Boolean) is
      I: Index renames M.I;
      J: EFreq renames M.J;
      L: Power renames M.L;
      pragma Unreferenced(Check);
   begin
      if IsZero(S) then return; end if;
      if M.Err then
         raise Not_Implemented;
      else
         Add_Coeff(L,S,Q(I).C(J));
      end if;
   end AddProd;

   procedure Extract_Coeff(M: in TrajMode; Q: in out Traj; S: in out Scalar) is
      --- assuming M.Err=False
      --- S encloses the coefficient
      I: Index renames M.I;
      J: EFreq renames M.J;
      L: Power renames M.L;
   begin
      if M.Simple then
         SetZero(S);
         Swap(Q(I).C(J).C(L),S);
      else
         raise Not_Implemented;
      end if;
   end Extract_Coeff;

   procedure Fail(M: in TrajMode; Q: in out Traj; S: in out Scalar) is
      pragma Unreferenced(M);
      pragma Unreferenced(Q);
      pragma Unreferenced(S);
   begin
      raise Not_Implemented;
   end Fail;

   procedure Extract(M: in TrajMode; Q: in out Traj; S: in out Scalar; Check: in Boolean) is
      --- assuming M is consistent
      pragma Unreferenced(Check);
   begin
      if M.Err then
         Extract_ErrorF(M,Q,S);
      else
         Extract_Coeff(M,Q,S);
      end if;
   end Extract;

   procedure Show(M: in TrajMode) is
   begin
      Show1(" Err = ",M.Err);
      Show1("    I =",M.I);
      Show1("    J =",M.J);
      Show1("    L =",M.L);
   end Show;

   function SameType(M1,M2: TrajMode) return Boolean is
   begin
      return (M1.Simple=M2.Simple);
   end SameType;

   function Make(RP: Radius; Siz: Positive; Simple,Trunc: Boolean) return TrajModes is
      Exclude_Errs: constant Boolean := Trunc or STrunc;
      Include_Errs: constant Boolean := not Exclude_Errs;
      S: constant Boolean := Simple or Exclude_Errs;
      Size2: constant Positive  := Siz/2;
      Size: constant Positive  := 2*Size2; --- even
      MaxJ,MaxL: Natural;

      procedure Build(M: out TrajModes; Count: out Natural) is

         procedure Set_Mode(I,J,L: in Natural; Err: in Boolean) is
            Tmp: constant TrajMode := (RP,I,J,L,Err,S);
         begin
            Count := Count+1;
            if Count <= M'Last then M(Count) := Tmp; end if;
         end Set_Mode;

      begin
         Count := 0;
         if Exclude_Errs then MaxL := PDeg; else MaxL := 0; end if;
         for I in Index loop
            if I=2 then MaxJ := Size; else MaxJ := Size2; end if;
            for J in 0..MaxJ loop
               if J<MaxJ/2 and Exclude_Errs then
                  MaxL := PDeg;
               else
                  MaxL := 0;
               end if;
               for L in 0 .. MaxL loop
                  Set_Mode(I,J,L,False);   --- coefficient
               end loop;
            end loop;
         end loop;
         if Include_Errs then
            for I in Index loop
               Set_Mode(I,Size+1,0,True);
            end loop;
         end if;
      end Build;

      Count: Natural;
   begin
      declare
         M: TrajModes(1..1);
      begin
         Build(M,Count);
      end;
      declare
         M: TrajModes(1..Count);
      begin
         Build(M,Count);
         return M;
      end;
   end Make;

end Taylors1.Cheb;
