package Catmandu;

use Catmandu::Sane;

our $VERSION = '1.2024';

use Catmandu::Env;
use Catmandu::Util qw(:is);
use File::Spec;
use namespace::clean;
use Sub::Exporter::Util qw(curry_method);
use Sub::Exporter -setup => {
    exports => [
        config             => curry_method,
        log                => curry_method,
        store              => curry_method,
        fixer              => curry_method,
        importer           => curry_method,
        exporter           => curry_method,
        validator          => curry_method,
        export             => curry_method,
        export_to_string   => curry_method,
        import_from_string => curry_method
    ],
    collectors => {'-load' => \'_import_load', ':load' => \'_import_load',},
};

sub _import_load {
    my ($self, $value, $data) = @_;
    if (is_array_ref $value) {
        $self->load(@$value);
    }
    else {
        $self->load;
    }
    1;
}

sub _env {
    my ($class, $env) = @_;
    state $loaded_env;
    $loaded_env = $env if defined $env;
    $loaded_env
        ||= Catmandu::Env->new(load_paths => $class->default_load_path);
}

sub log {$_[0]->_env->log}

sub default_load_path {    # TODO move to Catmandu::Env
    my ($class, $path) = @_;
    state $default_path;
    $default_path = $path if defined $path;
    $default_path //= do {
        my $script = File::Spec->rel2abs($0);
        my ($script_vol, $script_path, $script_name)
            = File::Spec->splitpath($script);
        my @dirs = grep length, File::Spec->splitdir($script_path);
        if ($dirs[-1] eq 'bin') {
            pop @dirs;
            File::Spec->catdir(File::Spec->rootdir, @dirs);
        }
        else {
            $script_path;
        }
    };
}

sub load {
    my $class = shift;
    my $paths = [@_ ? @_ : $class->default_load_path];
    my $env   = Catmandu::Env->new(load_paths => $paths);
    $class->_env($env);
    $class;
}

sub roots {
    $_[0]->_env->roots;
}

sub root {
    $_[0]->_env->root;
}

sub config {
    my ($class, $config) = @_;
    if ($config) {
        my $env = Catmandu::Env->new(load_paths => $class->_env->load_paths);
        $env->_set_config($config);
        $class->_env($env);
    }
    $class->_env->config;
}

sub default_store {$_[0]->_env->default_store}

sub store {
    my $class = shift;
    $class->_env->store(@_);
}

sub default_fixer {$_[0]->_env->default_fixer}

sub fixer {
    my $class = shift;
    $class->_env->fixer(@_);
}

sub default_importer {$_[0]->_env->default_importer}

sub default_importer_package {$_[0]->_env->default_importer_package}

sub importer {
    my $class = shift;
    $class->_env->importer(@_);
}

sub default_exporter {$_[0]->_env->default_exporter}

sub default_exporter_package {$_[0]->_env->default_exporter_package}

sub exporter {
    my $class = shift;
    $class->_env->exporter(@_);
}

sub validator {
    my $class = shift;
    $class->_env->validator(@_);
}

sub export {
    my $class    = shift;
    my $data     = shift;
    my $exporter = $class->_env->exporter(@_);
    is_hash_ref($data) ? $exporter->add($data) : $exporter->add_many($data);
    $exporter->commit;
    return;
}

sub export_to_string {
    my $class    = shift;
    my $data     = shift;
    my $name     = shift;
    my %opts     = ref $_[0] ? %{$_[0]} : @_;
    my $str      = "";
    my $exporter = $class->_env->exporter($name, %opts, file => \$str);
    is_hash_ref($data) ? $exporter->add($data) : $exporter->add_many($data);
    $exporter->commit;
    $str;
}

sub import_from_string {
    my $class = shift;
    my $str   = shift;
    my $name  = shift;
    my %opts  = ref $_[0] ? %{$_[0]} : @_;
    $class->_env->importer($name, %opts, file => \$str)->to_array();
}

sub define_importer {
    my $class   = shift;
    my $name    = shift;
    my $package = shift;
    my $options = ref $_[0] ? $_[0] : {@_};
    $class->config->{importer}{$name}
        = {package => $package, options => $options};
}

sub define_exporter {
    my $class   = shift;
    my $name    = shift;
    my $package = shift;
    my $options = ref $_[0] ? $_[0] : {@_};
    $class->config->{exporter}{$name}
        = {package => $package, options => $options};
}

sub define_store {
    my $class   = shift;
    my $name    = shift;
    my $package = shift;
    my $options = ref $_[0] ? $_[0] : {@_};
    $class->config->{store}{$name}
        = {package => $package, options => $options};
}

sub define_fixer {
    my $class = shift;
    my $name  = shift;
    my $fixes = ref $_[0] ? $_[0] : [@_];
    $class->config->{fixer}{$name} = $fixes;
}

1;

__END__

=pod

=head1 NAME

Catmandu - a data toolkit

=head1 SYNOPSIS

    # From the command line

    # Convert data from one format to another
    $ catmandu convert JSON to CSV  < data.json
    $ catmandu convert CSV  to YAML < data.csv
    $ catmandu convert MARC to YAML < data.mrc

    # Fix data, add, delete, change fields
    $ catmandu convert JSON --fix 'move_field(title,my_title)' < data.json
    $ catmandu convert JSON --fix all_my_fixes.txt < data.json

    # Use a moustache preprocessor on the fix script
    $ catmandu convert JSON --fix all_my_fixes.txt --var opt1=foo --var opt2=bar < data.json

    # run a fix script
    $ catmandu run myfixes.fix

    # or, create an executable fix script
    $ cat myfixes.fix
    #!/usr/local/bin/catmandu run
    do importer(OAI,url:"http://biblio.ugent.be/oai")
        retain(_id)
    end
    $ chmod 755 myfixes.fix
    $ ./myfixes.fix

=head1 DESCRIPTION

Catmandu provides a command line tools for the conversion of various data 
formats including: JSON, YAML, RDF, CSV, TSV, XML and even Excel. Using 
extension modules, specialized conversions for metadata formats using 
in libraries, archives and museums is also supports. We provide support 
for MARC, MAB, MODS, OAI-PMH, PICA, PNX, RIS, LIDO, SRU and Z39.50. 

Specialized conversions require a mapping language. This is implemented in 
Catmandu using the `Fix` language. For a short introduction read
L<Catmandu::Introduction>.  Online tutorials can be found at the end of this document.

=head1 INSTALL 

=head2 From Source

    # Clone the directory
    git clone https://github.com/LibreCat/Catmandu

    # Build
    cd Catmandu
    cpanm -n -q --installdeps --skip-satisfied .
    perl Build.PL && ./Build && ./Build install

=head2 Using Docker

    docker build -t librecat/catmandu .
    
    # Run catmandu with access to you local files at <YourDrive>
    docker run -v <YourDrive>:/home/catmandu/Home  -it librecat/catmandu

    # E.g.
    docker run -v C:\Users\alice:/home/catmandu/Home -it librecat/catmandu

=head1 INSTALL EXTENSIONS

    cpanm install <PackageName>

    # E.g.
    cpanm install Catmandu::MARC

=head1 POPULAR EXTENSIONS

L<Catmandu::Breaker>

L<Catmandu::Identifier>

L<Catmandu::MARC>

L<Catmandu::OAI>

L<Catmandu::PICA>

L<Catmandu::RDF>

L<Catmandu::SRU>

L<Catmandu::Stat>

L<Catmandu::Template>

L<Catmandu::Validator>

L<Catmandu::XLS>

L<Catmandu::XSD>

L<Catmandu::Z3950>

=head1 SEE ALSO

=over 4

=item introduction

L<Catmandu::Introduction>

=item documentation

L<http://librecat.org/>

=item blog

L<https://librecatproject.wordpress.com/>

=item step-by-step introduction from basics

L<https://librecatproject.wordpress.com/2014/12/01/day-1-getting-catmandu/>

=item command line client

L<catmandu>

=item Perl API

L<Catmandu::PerlAPI>

=back

=head1 AUTHOR

Nicolas Steenlant, C<< <nicolas.steenlant at ugent.be> >>

=head1 CONTRIBUTORS

Patrick Hochstenbach, C<< patrick.hochstenbach at ugent.be >>

Nicolas Franck, C<< nicolas.franck at ugent.be >>

Johann Rolschewski, C<< jorol at cpan.org >>

Vitali Peil, C<< vitali.peil at uni-bielefeld.de >>

Jakob Voss, C<< nichtich at cpan.org >>

Magnus Enger, C<< magnus at enger.priv.no >>

Christian Pietsch, C<< christian.pietsch at uni-bielefeld.de >>

Dave Sherohman, C<< dave.sherohman at ub.lu.se >>

Snorri Briem, C<< snorri.briem at ub.lu.se >>

Pieter De Praetere, C<< pieter.de.praetere at helptux.be >>

Doug Bell

Upsana, C<< me at upasana.me >>

Stefan Weil

Tom Hukins

=head1 QUESTIONS, ISSUES & BUG REPORTS

For any questions on the use of our modules please join our mailing list at:

    librecat-dev@lists.uni-bielefeld.de

or send in your bug reports or feature requests to our issue tracker at:

    https://github.com/LibreCat/Catmandu/issues

=head1 LICENSE AND COPYRIGHT

This program is free software; you can redistribute it and/or modify it
under the terms of either: the GNU General Public License as published
by the Free Software Foundation; or the Artistic License.

See L<http://dev.perl.org/licenses/> for more information.

=cut
