with Ints, Quick_Sort;
use Ints;

package body Vectors.Sorting is

  function GT_MaxNorm(A,B: Component) return Boolean is
  begin
    return MaxNorm(A)>MaxNorm(B);
  end GT_MaxNorm;

  procedure Dec_MaxNorm_Sort(W: in out Vector) is
    procedure QSort is new Quick_Sort (Item => Component, Item_Vector => Vector, "<" => GT_MaxNorm);
  begin
    QSort(W'First,W'Last,W);
  end Dec_MaxNorm_Sort;

  function GT_MaxNorm(Eps: Radius; Wr,Wi: Vector; I,J: Integer) return Boolean is
    OneMinusEps: constant Radius := One-Eps;
    NrI: constant Flt := MaxNorm(Wr(I));
    AiI: constant Flt := Approx(Wi(I));
    NI: constant Flt := NrI*NrI+AiI*AiI;
    NrJ: constant Flt := MaxNorm(Wr(J));
    AiJ: constant Flt := Approx(Wi(J));
    NJ: constant Flt := NrJ*NrJ+AiJ*AiJ;
  begin
    if OneMinusEps*NI > NJ then return  True; end if;
    if OneMinusEps*NJ > NI then return  False; end if;
    if OneMinusEps*NrI > NrJ then return  True; end if;
    if OneMinusEps*NrJ > NrI then return  False; end if;
    return AiI>AiJ;
  end GT_MaxNorm;

  procedure Dec_MaxNorm_Sort(Eps: in Radius; Wr,Wi: in out Vector) is
    K: Integer;
    procedure Swap(I,J: in out Integer) is begin K := I; I := J; J := K; end Swap;
    function GT(I,J: Integer) return Boolean is begin return GT_MaxNorm(Eps,Wr,Wi,I,J); end GT;
    procedure QSort is new Quick_Sort (Item => Integer, Item_Vector => Int_Vec, "<" => GT);
    P: Int_Vec(Wr'Range); -- Pivot
    Tmp: Vector(Wr'Range);
  begin
    for I in P'Range loop P(I) := I; end loop;
    QSort(P'First,P'Last,P);
    for I in Wr'Range loop Copy(Wr(I),Tmp(I)); end loop;
    for I in Wr'Range loop Copy(Tmp(P(I)),Wr(I)); end loop;
    for I in Wi'Range loop Copy(Wi(I),Tmp(I)); end loop;
    for I in Wi'Range loop Copy(Tmp(P(I)),Wi(I)); end loop;
  end Dec_MaxNorm_Sort;

end Vectors.Sorting;
