## Copyright (C) 2025
##
## 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
## <https://www.gnu.org/licenses/>.

## -*- texinfo -*-
## @deftypefn {} {@var{tbl} =} table (@var{var1}, @var{var2}, @dots{})
## @deftypefnx {} {@var{tbl} =} table (@dots{}, 'VariableNames', @var{names})
## @deftypefnx {} {@var{tbl} =} table (@dots{}, 'RowNames', @var{names})
## Create a table from input variables.
##
## Create a table from one or more input variables.  Each input variable
## becomes a column in the table.
##
## @example
## @group
## tbl = table ([1; 2; 3], [4; 5; 6], 'VariableNames', @{'A', 'B'@})
## @result{} tbl =
##    A    B
##    -    -
##    1    4
##    2    5
##    3    6
## @end group
## @end example
##
## @seealso{struct2table, istable, height, width}
## @end deftypefn

function tbl = table (varargin)
  if (nargin == 0)
    % MATLAB compatibility: table() with no arguments creates an empty table
    % Create empty table structure matching the normal table format
    tbl = struct ();
    tbl.Properties = struct ();
    tbl.Properties.VariableNames = {};
    tbl.Properties.RowNames = {};
    tbl.Properties.Description = "";
    tbl.Properties.VariableDescriptions = {};
    tbl.Properties.VariableUnits = {};
    return;
  endif

  ## Parse name-value pairs
  var_names = {};
  row_names = {};
  description = "";
  
  ## Find name-value pairs
  name_value_start = 1;
  for i = 1:nargin
    if (ischar (varargin{i}) || isstring (varargin{i}))
      name_value_start = i;
      break;
    endif
  endfor

  ## Extract data variables (before name-value pairs)
  data_vars = varargin(1:name_value_start-1);
  
  ## Parse name-value pairs
  i = name_value_start;
  while (i <= nargin)
    if (ischar (varargin{i}) || isstring (varargin{i}))
      name = varargin{i};
      if (i < nargin)
        value = varargin{i+1};
        
        switch (lower (name))
          case "variablenames"
            if (iscellstr (value) || isstring (value))
              var_names = cellstr (value);
            else
              error ("table: VariableNames must be a cell array of strings or string array");
            endif
          case "rownames"
            if (iscellstr (value) || isstring (value))
              row_names = cellstr (value);
            else
              error ("table: RowNames must be a cell array of strings or string array");
            endif
          case "description"
            if (ischar (value) || isstring (value))
              description = char (value);
            else
              error ("table: Description must be a string");
            endif
        endswitch
        i += 2;
      else
        error ("table: name-value pair requires a value");
      endif
    else
      i += 1;
    endif
  endwhile

  ## Create table structure
  tbl = struct ();
  
  ## Add data columns
  num_cols = numel (data_vars);
  if (isempty (var_names))
    ## Generate default variable names
    var_names = cell (1, num_cols);
    for i = 1:num_cols
      var_names{i} = sprintf ("Var%d", i);
    endfor
  elseif (numel (var_names) != num_cols)
    error ("table: number of VariableNames must match number of input variables");
  endif

  ## Get number of rows from first variable
  if (isempty (data_vars))
    num_rows = 0;
  else
    first_var = data_vars{1};
    if (isvector (first_var))
      num_rows = length (first_var);
    elseif (ismatrix (first_var))
      num_rows = size (first_var, 1);
    else
      num_rows = size (first_var, 1);
    endif
  endif

  ## Add variables to table
  for i = 1:num_cols
    var_data = data_vars{i};
    ## Ensure column vector
    if (isrow (var_data) && num_rows > 1)
      var_data = var_data(:);
    endif
    tbl.(var_names{i}) = var_data;
  endfor

  ## Initialize Properties structure
  tbl.Properties = struct ();
  tbl.Properties.VariableNames = var_names;
  if (! isempty (row_names))
    if (numel (row_names) != num_rows)
      error ("table: number of RowNames must match number of rows");
    endif
    tbl.Properties.RowNames = row_names;
  else
    tbl.Properties.RowNames = {};
  endif
  tbl.Properties.Description = description;
  tbl.Properties.VariableDescriptions = cell (1, num_cols);
  tbl.Properties.VariableUnits = cell (1, num_cols);
endfunction


