%# -*- mode: Octave -*-
%!shared x, y, Y, z
%! x=dataframe(randn(3, 3), 'rownames', (7:-1:5).');
%! x(1:3, 1) = 3;
%! x(1:3, 1) = (4:6).';
%!assert(x(2, 1), 5);
%! x(1, 1:3) = 3;	  
%! x(1, 1:3) = (4:6).';
%!assert(x(1, 2), 5);
%!assert(isempty(x.rowidx), false);
%! x.types ='single';
%!assert(class(x(1, 1)), 'single')
%! x=dataframe('octave_frame/data_test.csv');
%! # remove rownames
%! x.rownames = [];
%!assert(size(x.rownames), [0 0])
%! # remove a column through '.' access
%! y = x; y.DataName = [];
%!assert(size(y), [10 6]);
%! y = x{};
%!assert(size(y), [10 7]);
%! y = x{[2 5], [2 7]};
%!assert(y, {-5.8, "E"; -5.2, "C"});
%! y = x{}([2 5], [2 7]);
%!assert(y, {-5.8, "E"; -5.2, "C"});
%! y = x{1:2, 1:2}(4);
%!assert(y, {-5.8});	
%! # remove a column through (:, name) access
%! y = x; y(:, "DataName") = [];
%!assert(size(y), [10 6]);
%! # create an empty dataframe
%! y = dataframe([]);
%!assert(isempty(y), true);
%! y = x.df(:, 2:6);
%! Y = 2*pi*double(y.Freq).*y.C+y.G;
%! z = dataframe(y,{{'Y'; Y}});
%!assert(size(z), [10 6]);
%!assert(abs(z(1, "Y") - Y(1)), 0);
%! # direct matrix setting through struct access
%! y.Freq=[(1:10).' (10:-1:1).'];
%! # verify the "end" operator on the third dim
%!assert(y(2, 2, end), 9);
%! # direct setting through 3D matrix
%! y(:, ["C"; "G"], 1:2) = repmat(y(:, ["C"; "G"]), [1 1 2]);
%! y(4:5, 4:5) = NaN;
%!test
%! if any(size(x) != [10 7]),
%!   error('x: wrong input size')
%! endif
%! if any(size(y) != [10 5 8]),
%!   error('y: wrong input size')
%! endif
%!assert(numel(x), 1);
%! # test simple slices
%!assert(x.VBIAS(1:6), (-6:.2:-5).');
%!assert(x(6:end, 2), (-5:.2:-4.2).');
%!assert(x(6, "OK"), 'B');
%!assert(x(2, logical([0 0 1 1])), x(2, 3:4))
%!assert(size(y(:, :, :)), [10 5 2]);
%!assert(size(y(:, :)), [10 10]);
%!assert(size(y(:, 2, 2)), [10 1]);
%!assert(size(y(:, 2)), [10 1]);
%!assert(y.C(4:5), [NaN NaN]);
%!error error("Accessing past limits")
%! x(1, 8)
%! x(11, 1)
%! x(1, logical(ones(1, 7)))
%! x.types{"FReq*"}
%! x(1, :)
%!test
%! #!! removed -- output format may only be specified before selection
%! #select one column	      
%! #assert(x(1:3, 1).cell(:), x.cell(1:3)(:))	
%! #assert(x(33:35).cell.', x(33:35).cell(:))
%! #select two columns	      
%!assert(x.cell(1:10, 2:3)(:), x.cell(11:30)(:))	
%!error error("Complex accesses");
%! x(:);
%! x.dataframe(:);
%! x.dataframe.cell
%!test
%! # test modifying column type
%! x.types("Freq") = 'uint32'; x.types(2) = 'single';
%! # downclassing must occur !
%!assert(class(x(1, ["Freq"; "C"])), 'uint32')
%! # upclassing must occur !
%!assert(class(x.as.double(1, ["Freq"; "C"])), 'double')
%!error error("Incorrect internal field sub-referencing")
%! x.types{"Freq"}	 
%!error error("mixing different types") 
%! x([12:18 22:28 32:38]);
%!error error("non-square access")
%! x([22:28 32:37]).dataframe;
%! x.cell([1:19]);
%!error error("Single-dimension name access")
%! x("Freq");
%!test
%! # complex access
%! x(x.OK=='?', ["C"; "G"]) = NaN;
%!assert(x(4, 5:6), [NaN NaN])
%! # extract values
%! y = x.dataframe(x.OK=='A', {"Freq", "VB*", "C", "G"});
%! #comparison using cell output class, because assert use (:)
%!assert(y.cell(:, 2:3), x.cell([1 7], ["VB*"; "C"]))
%!assert(x((33:35).'), x(3:5, 4))
%! #test further dereferencing
%!assert(x(:, "C")(2:4), x(2:4, "C"))
%! # complex modifications through cell access
%! z = dataframe(x, {"VB*", {"Polarity" ,"Sense"; ones(12,2), zeros(10,2)}});
%!assert(size(z), [12 9 11]);
%!assert(z.Sense(11:12, :), NA*ones(2, 2));
%!assert(size(z._over{2}, 2) - size(x._over{2}, 2), 2);

%!demo
%! x=dataframe('octave_frame/data_test.csv')
%! disp("Access as a struct: x.VBIAS(1:6)")
%! x.VBIAS(1:6)
%! pause; disp("Access as a matrix: x(6, 'OK')")
%! x(6, "OK")
%! pause; disp("Removing the row names:  x.rownames = []");
%! x.rownames = []
%! pause; disp("Modifying column type: x.types{'Freq'}='uint32'");
%! x.types{"Freq"}='uint32'
%! pause; disp("Partial extract, returning a dataframe");
%! disp("y = x(x.OK=='A'|x.OK=='B', {'Freq', 'VB*', 'C', 'G'}, 'dataframe')")
%! y = x(x.OK=='A'|x.OK=='B', {"Freq", "VB*", "C", "G"}, "dataframe")
%! pause; disp("Setting rownames")
%! disp("y.rownames = char({'low', 'med', 'med', 'high'})");
%! y.rownames = char({'low', 'med', 'med', 'high'})
%! pause; disp("Partial modification of one column")
%! disp("y.Freq('med')=[290e3; 310e3]")
%! y.Freq('med') = [290e3; 310e3]
%! pause; disp('Complex access');
%! disp("y.C('med')([2 1])");
%! y.C('med')([2 1])
%! pause; disp('Print stats about a dataframe: summary(y)');
%! summary(y)

%!demo
%! disp('Modifying a dataframe from a cell array')
%!  RHS={ 'don''t care', 'idx', 'Vb', 'freq', 'Ib', 'C', 'status', 'comment'
%!        'yes',     uint16(5), single(3.2), 10000, 1e-11, 6e-13, 'bla', '@'
%!        'no',     uint16(16), 4, 12000, 2e-11, 4e-13, 7, 'X'};
%! disp("Resetting a dataframe: x=dataframe([])");
%! x = dataframe([]);
%! x(:, :) = RHS
%! disp("Overwriting the second line")
%! RHS{1, 2} = "idg"; RHS{3, 1}= "No!";
%! disp("'x(2, :) = RHS(1:2, :)' will produce two warnings")
%! disp("Notice that only the second line content will change");
%! disp("x(2, :) = RHS(1:2, :)")
%! x(2, :) = RHS(1:2, :)
%! pause; disp('same effect, but skipping first column');
%! disp("x(1, :) = RHS([1 3], 2:end)");
%! x(1, :) = RHS([1 3], 2:end)
%!demo
%! disp("same game, but using row indexes.")
%! disp("Notice the first field name is empty")
%! RHS= { '', 'idx', 'Vb', 'freq', 'Ib', 'C', 'status', 'comment'
%!        5, uint32(16),   5.3, 11000, 3e-12, 5e-12, "may", "8th"}; 
%! disp("x= dataframe(RHS)")
%! x = dataframe(RHS)
%! pause; disp("The same effect is achieved by assigning to an empty dataframe")
%! x = dataframe([]);
%! x(:, :) = RHS
