#!perl

=head1 NAME

ixchel - Automate various sys admin stuff.

=head1 SYNOPSIS

ixchel -a <action> [B<--config> <config>] [B<--noConfig>]

ixchel --help [B<-a> <action>]

=head1 DESCRIPTION

=head1 FLAGS

The following are just the base flags. Actions can have additional configs.

=head2 -a <action>

The action to perform.

To get a list of available actions use 'list_actions'.

If this is undef, it will be set to 'list_actions'.

=head2 --config <file>

The config file to load. May be JSON, YAML, or TOML.
If not specified the first one found below is used.
If it is not found, a empty hash is used.

    Default: /usr/local/etc/ixchel/server.yaml
             /usr/local/etc/ixchel/server.json
             /usr/local/etc/ixchel/server.toml

This option will be ignored if --noConfig specified.

=head2 --noConfig

Do not attempt to load the config even if it exists.

This is automatic for the action 'list_actions' and 'sys_info'

The option --config will be ignored if this is specified.

=head1 ENVIROMENTAL VARIABLES

If the following values are defined, the matching ENV is set.

    .proxy.ftp       ->  FTP_PROXY
    .proxy.http      ->  HTTP_PROXY
    .proxy.https     ->  HTTPS_PROXY
    .perl.cpanm_home ->  PERL_CPANM_HOME

Additionally any of the variables defined under .env will also be
set. So .env.TMPDIR will set $ENV{TMPDIR}.

=cut

use strict;
use warnings;
use Getopt::Long qw(:config pass_through);
use File::Slurp;
use JSON     qw(decode_json);
use YAML::XS qw(Load);
use Ixchel;
use utf8;
use Pod::Usage;
use Pod::Find qw(pod_where);

sub version {
	print 'ixchel v. ' . $Ixchel::VERSION . "\n";
}

# disable color if asked
if ( defined( $ENV{NO_COLOR} ) ) {
	$ENV{ANSI_COLORS_DISABLED} = 1;
}

my $config_file;
my $action;
my $help;
my $version;
my $noConfig;
GetOptions(
	'a=s'      => \$action,
	'config=s' => \$config_file,
	'noConfig' => \$noConfig,
	'help'     => \$help,
	'version'  => \$version,
);

if ($version) {
	&version;
	exit 0;
}

if ($help) {
	&version;

	print '

-a <action>       The action to perform.

--config <file>   The config file to load. May be JSON, YAML, or TOML.
                  If not specified the first one found below is used.
                  If it is not found, a empty hash is used.
                  Default: /usr/local/etc/ixchel/server.yaml
                           /usr/local/etc/ixchel/server.json
                           /usr/local/etc/ixchel/server.toml

--noConfig        Do not attempt to load the config even if it exists.

';

	if ( !defined($action) ) {
		print 'For help on a specific topic use --help with the specified action in question.

For a list of actions use the action list_actions
';
		exit 0;
	}

	print "Action specific help... \n\n";
	pod2usage(
		-input   => pod_where( { -inc => 1 }, 'Ixchel::Actions::' . $action, ),
		-verbose => 99,
		-output  => \*STDOUT
	);

	exit 0;
} ## end if ($help)

# try figure out what config file to try if non is specified
if ( !defined($config_file) ) {
	if ( -e '/usr/local/etc/ixchel/server.yaml' ) {
		$config_file = '/usr/local/etc/ixchel/server.yaml';
	} elsif ( -e '/usr/local/etc/ixchel/server.json' ) {
		$config_file = '/usr/local/etc/ixchel/server.json';
	} elsif ( -e '/usr/local/etc/ixchel/server.toml' ) {
		$config_file = '/usr/local/etc/ixchel/server.toml';
	}
}

# set noConfig for items that won't need it
if ( $action eq 'list_actions' || $action eq 'sys_info' ) {
	$noConfig = 1;
}

my $parsed_config;
if ( defined($config_file) && -e $config_file && !$noConfig ) {

	my $raw_config = read_file($config_file) || die( 'Failed to read "' . $config_file . '"' );

	if ( $config_file =~ /[Jj][Ss][Oo][Nn]$/ ) {
		eval { $parsed_config = decode_json($raw_config); };
		if ($@) {
			die( 'Parsing "' . $config_file . '" failed... ' . $@ );
		}
	} elsif ( $config_file =~ /([Yy][Mm][Ll]|[Yy][Aa][Mm][Ll])$/ ) {
		utf8::encode($raw_config);
		eval { $parsed_config = Load($raw_config); };
		if ($@) {
			die( 'Parsing "' . $config_file . '" failed... ' . $@ );
		}
	} elsif ( $config_file =~ /[Tt][Oo][Mm][Ll]$/ ) {
		eval {
			my $err;
			my $to_eval = 'use TOML::Tiny qw(from_toml); ( $parsed_config, $err ) = from_toml($raw_config);';
			eval($to_eval);
			unless ($parsed_config) {
				die($err);
			}
		};
		if ($@) {
			die( 'Parsing "' . $config_file . '" failed... ' . $@ );
		}
	} ## end elsif ( $config_file =~ /[Tt][Oo][Mm][Ll]$/ )
} elsif ( defined($config_file) && !-e $config_file && !$noConfig ) {
	die( '"' . $config_file . '" does not exist and --noConfig is not specified' );
} else {
	$parsed_config = {};
}

my $i = Ixchel->new( config => $parsed_config );

$i->action( action => $action );

exit $i->{errors_count};
