The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/env perl
use strict;
use warnings;
use File::Basename;
use lib File::Basename::dirname(__FILE__)."/../../../../lib";
use lib File::Basename::dirname(__FILE__)."/../../..";
use URT;
use Test::More tests => 83;

use IO::File;
use File::Temp;


# File data: id name score color
my @data = (
            [1, 'one',   10,'red'],
            [2, 'two',   10,'green'],
            [3, 'three', 9, 'blue'],
            [4, 'four',  9, 'black'],
            [5, 'five',  8, 'yellow'],
            [6, 'six',   8, 'white'],
            [7, 'seven', 7, 'purple'],
            [8, 'eight', 7, 'orange'],
            [9, 'nine',  6, 'pink'],
            [10, 'ten',  6, 'brown'],
          );

my $datafile = File::Temp->new();
ok($datafile, 'Created temp file for data');

my $data_source = UR::DataSource::Filesystem->create(
    path => $datafile->filename,
    delimiter => "\t",
    record_separator => "\n",
#    handle_class => 'URT::FileTracker',
    columns => ['thing_id','name','score','color'],
);
ok($data_source, 'Create filesystem data source');

ok(UR::Object::Type->define(
    class_name => 'URT::Thing',
    id_by => [
        thing_id => { is => 'Number' }
    ],
    has => [
        name  => { is => 'String' },
        score => { is => 'Integer' },
        color => { is => 'String'},
    ],
    data_source_id => $data_source->id,
),
'Defined class for things');


my @file_columns_in_order = ('id','name','score','color');
my %sorters;
foreach my $cols ( [id => 0], [name => 1], [score => 2], [color => 3] ) {
    my($key,$col) = @$cols;
    $sorters{$key} = sub { no warnings 'numeric'; $a->[$col] <=> $b->[$col] or $a->[$col] cmp $b->[$col] };
}

foreach my $cols ( [id => 0], [name => 1], [score => 2], [color => 3] ) {
    my($key,$col) = @$cols;
    $sorters{'-'.$key} = sub { no warnings 'numeric'; $b->[$col] <=> $a->[$col] or $b->[$col] cmp $a->[$col] };
}

foreach my $write_sort_order ( 'asc','desc' ) {
    foreach my $sortby_col ( 0 .. 3 ) { # The number of columns in @data
        # sort the data by one of the columns...
        my %file_write_sorters = (
            asc  => sub { no warnings 'numeric'; $a->[$sortby_col] <=> $b->[$sortby_col] or $a->[$sortby_col] cmp $b->[$sortby_col] },
            desc => sub { no warnings 'numeric'; $b->[$sortby_col] <=> $a->[$sortby_col] or $b->[$sortby_col] cmp $a->[$sortby_col] },
        );

        my $write_sorter = $file_write_sorters{$write_sort_order};
        my @write_data = sort $write_sorter @data;

        ok(save_data_to_file($datafile, \@write_data),
             "Saved data sorted by column $sortby_col $write_sort_order $file_columns_in_order[$sortby_col]");
        $data_source->sorted_columns( [ ($write_sort_order eq 'desc' ? '-' : '') . $data_source->columns->[$sortby_col] ] );

        URT::Thing->unload();
        my @results = map { [ @$_{@file_columns_in_order} ] } URT::Thing->get();
        my $sort_sub = $sorters{'id'};
        my @expected = sort $sort_sub @data;
        is_deeply(\@results, \@expected, 'Got all objects in default (id) sort order');
    
        foreach my $order_by_direction ( '', '-') {
            for my $sort_prop ( 'id', 'name', 'score', 'color' ) {
                URT::Thing->unload();
                my $order_by_prop = $order_by_direction . $sort_prop;
                my @results = map { [ @$_{@file_columns_in_order} ] } URT::Thing->get(-order => [ $order_by_prop]);
                my $sort_sub = $sorters{$order_by_prop};
                my @expected = sort $sort_sub @data;
                is_deeply(\@results, \@expected, "Got all objects sorted by $order_by_prop in the right order");
            }
        }
    }
}



sub save_data_to_file {
    my($fh, $datalist) = @_;

    $fh->seek(0,0);
    $fh->print(map { $_ . "\n" }
               map { join("\t", @$_) }
               @$datalist);
    truncate($fh, $fh->tell());
    $fh->flush();
    return 1;
}