## 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} =} horzcat (@var{tbl1}, @var{tbl2}, @dots{})
## Horizontal concatenation of tables.
##
## Concatenate tables horizontally.  All tables must have the same number
## of rows.  Variable names are combined from all tables.
##
## @seealso{vertcat, table}
## @end deftypefn

function tbl = horzcat (varargin)
  if (nargin < 2)
    error ("horzcat: at least two tables required");
  endif

  ## REQ-TABLE-003: Delegate to built-in horzcat if any input is not a table
  for i = 1:nargin
    if (! istable (varargin{i}))
      ## At least one input is not a table, use built-in horzcat
      tbl = builtin ("horzcat", varargin{:});
      return;
    endif
  endfor

  ## Ensure all inputs are tables (redundant after above check, but kept for clarity)
  for i = 1:nargin
    varargin{i} = __ensure_properties__ (varargin{i});
  endfor

  ## Get number of rows from first table
  num_rows = height (varargin{1});

  ## Check all tables have same number of rows
  for i = 2:nargin
    if (height (varargin{i}) != num_rows)
      error ("horzcat: all tables must have the same number of rows");
    endif
  endfor

  ## Combine all tables
  tbl = varargin{1};

  ## Combine variable names
  all_var_names = tbl.Properties.VariableNames;

  for i = 2:nargin
    next_tbl = varargin{i};
    next_vars = next_tbl.Properties.VariableNames;

    ## Add columns from next table
    for j = 1:numel (next_vars)
      var_name = next_vars{j};
      ## Handle duplicate variable names by appending suffix
      if (any (strcmp (all_var_names, var_name)))
        suffix = 1;
        new_name = sprintf ("%s_%d", var_name, suffix);
        while (any (strcmp (all_var_names, new_name)))
          suffix += 1;
          new_name = sprintf ("%s_%d", var_name, suffix);
        endwhile
        var_name = new_name;
      endif
      tbl.(var_name) = next_tbl.(next_vars{j});
      all_var_names{end+1} = var_name;
    endfor
  endfor

  ## Update Properties
  tbl.Properties.VariableNames = all_var_names;
  tbl.Properties.RowNames = varargin{1}.Properties.RowNames;
  tbl.Properties.Description = varargin{1}.Properties.Description;
  
  ## Combine VariableDescriptions and VariableUnits
  num_vars = numel (all_var_names);
  tbl.Properties.VariableDescriptions = cell (1, num_vars);
  tbl.Properties.VariableUnits = cell (1, num_vars);
  
  var_idx = 1;
  for i = 1:nargin
    src_tbl = varargin{i};
    num_src_vars = numel (src_tbl.Properties.VariableNames);
    if (isfield (src_tbl.Properties, "VariableDescriptions"))
      tbl.Properties.VariableDescriptions(var_idx:var_idx+num_src_vars-1) = ...
        src_tbl.Properties.VariableDescriptions;
    endif
    if (isfield (src_tbl.Properties, "VariableUnits"))
      tbl.Properties.VariableUnits(var_idx:var_idx+num_src_vars-1) = ...
        src_tbl.Properties.VariableUnits;
    endif
    var_idx += num_src_vars;
  endfor
endfunction


