## Copyright (C) 1996, 1998, 2000, 2002, 2003, 2004, 2005, 2006, 2007
##               Auburn University.  All rights reserved.
##
## This file is part of Octave.
##
## Octave is free software; you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 3 of the License, or (at
## your option) any later version.
##
## Octave is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with Octave; see the file COPYING.  If not, see
## <http://www.gnu.org/licenses/>.

## -*- texinfo -*-
## @deftypefn {Function File} {@var{sys} =} sysappend (@var{syst}, @var{b}, @var{c}, @var{d}, @var{outname}, @var{inname}, @var{yd})
## appends new inputs and/or outputs to a system
##
## @strong{Inputs}
## @table @var
## @item syst
## system data structure
##
## @item b
## matrix to be appended to sys "B" matrix (empty if none)
##
## @item c
## matrix to be appended to sys "C" matrix (empty if none)
##
## @item d
## revised sys d matrix (can be passed as [] if the revised d is all zeros)
##
## @item outname
## list of names for new outputs
##
## @item inname
## list of names for new inputs
##
## @item yd
## binary vector; @math{yd(ii)=0} indicates a continuous output;
## @math{yd(ii)=1} indicates a discrete output.
## @end table
##
## @strong{Outputs}
## @table @var
## @item sys
## @example
## @group
##    sys.b := [syst.b , b]
##    sys.c := [syst.c  ]
##             [ c     ]
##    sys.d := [syst.d | D12 ]
##             [ D21   | D22 ]
## @end group
## @end example
## where @math{D12}, @math{D21}, and @math{D22} are the appropriate dimensioned
## blocks of the input parameter @var{d}.
## @itemize @bullet
## @item The leading block @math{D11} of @var{d} is ignored.
## @item If @var{inname} and @var{outname} are not given as arguments,
##      the new inputs and outputs are be assigned default names.
## @item @var{yd} is a binary vector of length rows(c) that indicates
##      continuous/sampled outputs.  Default value for @var{yd} is:
## @itemize @minus
## @item @var{sys} is continuous or mixed
## @var{yd} = @code{zeros(1,rows(c))}
##
## @item @var{sys} is discrete
## @var{yd} = @code{ones(1,rows(c))}
## @end itemize
## @end itemize
## @end table
## @end deftypefn

## Author: John Ingram <ingraje@eng.auburn.edu>
## Created: August 1996

function retsys = sysappend (sys, b, c, d, outname, inname, yd)

  ## check input arguments
  if (nargin < 2 || nargin > 7)
    print_usage ();
  elseif (! isstruct (sys))
    error ("sys must be a system data structure");
  endif

  ## default system type must be state space form
  [Aa, Ab, Ac, Ad, Ats, Ann, Anz, Ast, Ain, Aout, Ayd] = sys2ss(sys);
  [Ann, Anz, Am, Ap] = sysdimensions(sys);

  ## default c
  if (nargin < 3)
    c = [];
  endif

  ## default d
  if (nargin < 4)
    make_d = 1;
  elseif (isempty(d))
    make_d = 1;
  else
    make_d = 0;
  endif

  if (make_d)
    d = zeros (rows(c)+Ap, columns(b)+Am);
  endif

  ## Append new input(s) if any
  Bm = max (columns(d), columns(b)+Am);
  if (Bm != Am)
    ## construct new signal names
    if (nargin >= 6)   # new names were passed
	if (! ischar (inname))
	  error ("inname must be a string");
	elseif (rows (inname) != Bm - Am)
	  error ("%d new inputs requested; inname(%dx%d)",
		 Bm-Am, rows (inname), columns (inname));
	endif
    else
	inname = __sysdefioname__ (Bm, "u", Am+1);
    endif

    if (Am)
      Ain = __sysconcat__(Ain, inname);
    else
      Ain = inname;
    endif

    ## default b matrix
    if (isempty (b))
      b = zeros (Ann+Anz, (Bm-Am));
    elseif (rows (b) != Ann+Anz || columns (b) != Bm-Am)
      error ("b(%dx%d); should be (%dx%d)", rows(b), columns(b),
	     Ann+Anz, Bm-Am);
    endif

    ## append new b matrix
    Ab = [Ab, b];
  endif

  ## Append new output(s) if any
  Bp = max (rows(d), rows(c)+Ap);
  if (Bp != Ap)

    ## construct new signal names, output classification
    if (nargin >= 5)  # new names were passed
      if (! ischar (outname))
	error ("outname must be a string");
      elseif (rows (outname) != Bp-Ap)
	error ("%d new outputs requested; outname(%dx%d)",
	       Bp-Ap, rows (outname), columns (outname));
      endif
    else
	outname = __sysdefioname__ (Bp, "y", (Ap+1));
    endif
    if (Ap)
      Aout = __sysconcat__ (Aout, outname);
    else
      Aout = outname;
    endif

    ## construct new yd entries
    if (nargin == 7)
      if (! isvector (yd))
	error ("yd(%dx%d) must be a vector", rows (yd), columns (yd));
      elseif (rows (c) != length (yd) && rows (d) != length (yd))
	error ("length(yd) = %d; c(%dx%d), d(%dx%d); mismatch",
	       length (yd), rows (c), columns (c), rows (d), columns (d));
      endif
    else
      ## default yd values
      yd = ones (1, Bp) * ((Ats > 0) & (Ann == 0) & isempty (find (Ayd == 0)));
    endif
    Ayd = [vec(Ayd); vec(yd)];

    ## default c matrix
    if (isempty (c))
      c = zeros (Bp-Ap, Ann+Anz);
    elseif (columns (c) != Ann+Anz || rows (c) != Bp-Ap)
      error ("c(%dx%d); should be (%dx%d)", rows (c), columns (c),
	     Bp-Ap, Ann+Anz); 
    endif

    ## append new c matrix
    Ac = [Ac; c];
  endif

  ## check d matrix
  if (isempty (d))
    d = zeros (Bp, Bm);
  elseif (rows (d) != Bp || columns (d) != Bm)
    error ("d(%dx%d) should be (%dx%d)", rows (d), columns (d), Bp, Bp);
  endif

  ## Splice in original D matrix
  if (Am & Ap)
    d(1:Ap, 1:Am) = Ad;
  endif
  Ad = d;

  ## construct return system
  retsys = ss (Aa, Ab, Ac, Ad, Ats, Ann, Anz, Ast, Ain, Aout, find (Ayd == 1));

endfunction
