function cmp = mfs_flutter(cmp, list, rho, method, varargin)

# usage: cmp = mfs_flutter(cmp, list, rho, method, varargin)
#
#        cmp = mfs_flutter(cmp. kred, rho, "k", opts)
#        cmp = mfs_flutter(cmp, v, rho, "pk", opts)
#        cmp = mfs_flutter(cmp, v, rho, "pk", pairs, opts)
#
# Input  cmp       Stucture with aeroelastic component
#        kred(:)   Array with reduced frequencies
#        v(:)      Array with velocities
#        rho       Mass density of air
#        method    Flutter solution method ("k" or "pk")
#        opts      Structure with options (optional)
#        pairs(:)  List of flutter mode pairs (optional)
#
# Output cmp       Structure with aeroelastic component
#
# In the pk-method, k-iterations are performed only for those pairs
# of complex conjugate pairs that are defined in array pairs. If no
# pairs are defined, iterations are performed for all pairs.
#
# Options:
#
#    Name    Default     Meaning
#  ------------------------------------------------------------------
#    msg        0        File handle of message file
#                        (if 0, no messages are printed)
#    nx        10        Number of intervals per chord length cref
#    m1         4        Factor to divide mimimum control point distance
#                        from trailing edge to get size of first interval
#    lenw      20        Length of wake behind last control point in
#                        multiples of cref
#    tmp        0        Indicates whether a temporary file should be
#                        used (1) or not (0)
#    mtol     100        Tolerance to identify modes that do not
#                        participate in flutter (in multiples of eps)
#    ktol     1e-4       Tolerance for reduced frequencies
#    mxiter    10        Maximum number of iterations
#
# The function performs a flutter analysis.
#
# ------------------------------------------------------------------------

# Copyright (c) 2018 by Johannes Wandinger

  t0 = clock();

# Default options

  defopts = struct("msg", 0, "nx", 10, "m1", 4, "lenw", 20, "tmp", 0,
                   "mtol", 100, "ktol", 1e-4, "mxiter", 10);

# Check arguments

  if (nargin < 4 || nargout != 1)
     print_usage();
  end
  if (! isstruct(cmp))
     error("mfs_flutter: first argument must be a structure\n");
  end
  if (! isvector(list))
     error("mfs_flutter: second argument must be a vector\n");
  end
  if (! isfloat(rho))
     error("mfs_flutter: third argument must be a real number\n");
  end
  if (! ischar(method))
     error("mfs_flutter: method must be a string\n");
  end

# Check component type and status

  if (! strcmp(cmp.type, "aeroelastic"))
     error("mfs_flutter: component type must be \"aeroelastic\"\n");
  end
  if (! isfield(cmp, "splines"))
     error("mfs_flutter: definition of splines missing\n");
  end
  if (! isfield(cmp.splines, "Shg"))
     error("mfs_flutter: spline matrices missing\n");
  end
  if (! isfield(cmp.solid, "modes"))
     error("mfs_flutter: normal modes missing\n");
  end
  if (! cmp.aero.pancols.npcol)
     error("mfs_flutter: wake undefined\n");
  end
  if (! cmp.aero.cref)
     error("mfs_flutter: reference chord length undefined\n");
  end

# Initialize

  nargs = length(varargin);

# Branch on flutter solution method

  switch method

  case "k"
     if (nargs)
        if (isstruct(varargin{1})) 
           opts = mfs_defopts(varargin{1}, defopts);
        else
           error("mfs_flutter: argument opts must be a structure\n");
        end
     else
        opts = defopts;
     end
     time_stamp = ignore_function_time_stamp("all");
     mfs_paths("add", "mfs_flutter.m", "aeroelastic", "aero");
     cmp = mfs_flutter_k(cmp, list, rho, opts);
     rc  = 0;
     mfs_paths("remove");
     ignore_function_time_stamp(time_stamp);

  case "pk"
     if (nargs == 1)
        if (isstruct(varargin{1}))
           opts = mfs_defopts(varargin{1}, defopts);
        else
           opts = defopts;
           if (isvector(varargin{1}))
              pairs = varargin{1};
           else
              error("mfs_flutter: argument pairs must be a vector\n");
           end
        end
     elseif (nargs == 2)
        if (isvector(varargin{1}))
           pairs = varargin{1};
        else
           error("mfs_flutter: argument pairs must be a vector\n");
        end
        if (isstruct(varargin{2}))
           opts  = mfs_defopts(varargin{2}, defopts);
        else
           error("mfs_flutter: argument opts must be a structure\n");
        end
     else
        opts = defopts;
        pairs = 1 : cmp.solid.modes.nofmod;
     end
     time_stamp = ignore_function_time_stamp("all");
     mfs_paths("add", "mfs_flutter.m", "aeroelastic", "aero");
     [cmp, rc] = mfs_flutter_pk(cmp, list, rho, pairs, opts);
     mfs_paths("remove");
     ignore_function_time_stamp(time_stamp);

  otherwise
     error("mfs_flutter: flutter method \"%s\" not supported\n",
           method);

  end

  if (rc)
     error("mfs_flutter ended with errors\n");
  end

  elapsed_time = etime(clock(), t0);
  printf("%10.4f seconds needed to perform flutter analysis of component %s\n",
         elapsed_time, inputname(1));
  fflush(stdout);

end
