#!perl

=head1 NAME

yqh - Helper wrapper around yq.

=head1 SYNOPSIS

yqh B<-f> <yaml> B<-a> clear_array B<--var> <var>

yqh B<-f> <yaml> B<-a> clear_hash B<--var> <var>

yqh B<-f> <yaml> B<-a> create_array B<--var> <var> [B<--vals> <vals>]

yqh B<-f> <yaml> B<-a> create_hash B<--var> <var>

yqh B<-f> <yaml> B<-a> dedup_array B<--var> <var>

yqh B<-f> <yaml> B<-a> delete B<--var> <var>

yqh B<-f> <yaml> B<-a> delete_array B<--var> <var>

yqh B<-f> <yaml> B<-a> delete_hash B<--var> <var>

yqh B<-f> <yaml> B<-a> ensure

yqh B<-f> <yaml> B<-a> is_array B<--var> <var>

yqh B<-f> <yaml> B<-a> is_hash B<--var> <var>

yqh B<-f> <yaml> B<-a> is_defined B<--var> <var>

yqh B<-f> <yaml> B<-a> merge_yaml B<--yaml> <yaml> [B<--mode> <mode>]

yqh B<-f> <yaml> B<-a> push_array B<--var> <var> B<--vals> <vals>

yqh B<-f> <yaml> B<-a> set_array B<--var> <var> B<--vals> <vals>

yqh B<-f> <yaml> B<-a> set_hash B<--var> <var> B<--hash> <hash>

yqh B<-f> <yaml> B<-a> set_in_array B<--var> <var> B<--vals> <vals> [B<--dedup>]

yqh B<-f> <yaml> B<-a> yaml_diff B<--yaml> <yaml_file_2>

=head1 FLAGS

=head2 -f <file>

YAML file to operate on.

Default :: undef

=head2 -a <action>

Action to perform.

Default :: undef

=head2 --var <string>

Variable to set.

Default :: undef

=head2 --vals <string>

Comma seperate list of array values.

Default :: undef

=head2 --hash <string>

Comma seperate list of hash values. Each
value is a sub string with key/value seperate
by a /=/.

Default :: undef

=head2 --dedup <bool>

If it should dedup the data for the op.

Default :: 1

=head2 --yaml <file>

Another YAML file to use with like the merge_yaml
action or the like.

Default :: undef

=head2 --mode <mode>

Merge mode to use.

Default :: deeply

=head1 ACTIONS

=head2 clear_array

Clears the specified array.

Requires :: --var

=head2 clear_hash

Clears the specified hash.

Requires :: --var

=head2 create_array

Creates the specified array if it does not exist.

Requires :: --var

Optional :: --vals

=head2 create_hash

Creates the specified hash if it does not exist.

Requires :: --var

=head2 dedup_array

Deduplicates an array.

Requires :: --var

=head2 delete

Deletes the var without checking the type.

Requires :: --var

=head2 delete_array

Deletes the specified array.

Requires :: --var

=head2 delete_hash

Deletes the specified hash.

Requires :: --var

=head2 ensure

Ensures that the YAML starts with

    %YAML $version
    ---

This is largely for use with stuff used by
LibYAML as that sometimes does not play nice
when that is missing.

Version 1.1 is used if it is not set.

=head2 is_array

Returns 0 or 1 based on if it is a array.

Requires :: --var

=head2 is_hash

Returns 0 or 1 based on if it is a hash.

Requires :: --var

=head2 is_defined

Returns 0 or 1 based on if it is defined.

Requires :: --var

=head2 merge_yaml

Merges the specified YAML into the YAML.

Requires :: --yaml

Optional :: --mode

=head2 push_array

Pushes a set of items onto an array.

Requires :: --var, --vals

=head2 set_array

Clears the array and sets it to specified values.

Requires :: --var, --vals

=head2 set_hash

Clears the hash and sets it to specified values.

Requires :: --var, --hash

=head2 set_in_array

Make sure a set of values exist in a array and if not add them.

Requires :: --var, --vals

Optional :: --dedup

=head2 yaml_diff

Diffs the two YAMLs.

Requires :: --yaml

=cut

use strict;
use warnings;
use Getopt::Long;
use YAML::yq::Helper;
use Pod::Usage;

sub version {
	print "yqh v. " . $YAML::yq::Helper::VERSION . ".\n";
}

sub help {
	pod2usage( -exitval => 255, -verbose => 2, -output => \*STDOUT );
}

# get the commandline options
my $help    = 0;
my $version = 0;
my $file;
my $var;
my $action;
my $vals_string;
my $val_string;
my $vals_sep = ',';
my $key;
my $hash_string;
my $val;
my $dedup = 1;
my $yaml2;
my $mode = 'deeply';
Getopt::Long::Configure('no_ignore_case');
Getopt::Long::Configure('bundling');
GetOptions(
	'version' => \$version,
	'v'       => \$version,
	'help'    => \$help,
	'h'       => \$help,
	'f=s'     => \$file,
	'a=s'     => \$action,
	'var=s'   => \$var,
	'sep=s'   => \$vals_sep,
	'vals=s'  => \$vals_string,
	'hash=s'  => \$hash_string,
	'val=s'   => \$val_string,
	'k=s'     => \$key,
	'dedup=s' => \$dedup,
	'yaml=s'  => \$yaml2,
	'mode=s'  => \$mode,
);

$vals_sep = quotemeta($vals_sep);

#
# make sure we've not been passed ' or " to make things simpler to handle
#
if ( defined($var) ) {
	if ( $var =~ /[\'\"]/ ) {
		die('--var may not contain \' or "');
	}
}

if ( defined($val_string) ) {
	if ( $val_string =~ /[\'\"]/ ) {
		die('--val may not contain \' or "');
	}
}

if ( defined($hash_string) ) {
	if ( $hash_string =~ /[\'\"]/ ) {
		die('--hash may not contain \' or "');
	}
}

#
# break up the array vals string if passed
#
my @vals;
if ( defined($vals_string) ) {
	if ( $vals_string =~ /[\'\"]/ ) {
		die('--vals may not contain \' or "');
	}

	@vals = split( /$vals_sep/, $vals_string );
}

#
# break up the hash string if passed
#
my $hash = {};
if ( defined($hash_string) ) {
	if ( $hash_string =~ /[\'\"]/ ) {
		die('--hash may not contain \' or "');
	}

	my @items = split( /$vals_sep/, $hash_string );
	foreach my $item (@items) {
		my ( $item_key, $item_val ) = split( /\=/, $item );
		if ( defined($item_key) and $item_key ne '' ) {
			$hash->{$item_key} = $item_val;
		} elsif ( defined($item_key) and $item_key eq '' ) {
			die('--hash contains a key that matches ""');
		}
	}
} ## end if ( defined($hash_string) )

# print version or help if requested
if ($help) {
	&help;
	exit 42;
}
if ($version) {
	&version;
	exit 42;
}

if ( !defined($action) ) {
	die('No action defined for -a');
}

my $yq = YAML::yq::Helper->new( file => $file );

if ( $action eq 'is_array' ) {
	print $yq->is_array( var => $var ) . "\n";
	exit 0;
}

if ( $action eq 'is_hash' ) {
	print $yq->is_hash( var => $var ) . "\n";
	exit 0;
}

if ( $action eq 'is_defined' ) {
	print $yq->is_defined( var => $var ) . "\n";
	exit 0;
}

if ( $action eq 'clear_array' ) {
	$yq->clear_array( var => $var );
	exit 0;
}

if ( $action eq 'clear_hash' ) {
	$yq->clear_hash( var => $var );
	exit 0;
}

if ( $action eq 'delete_array' ) {
	$yq->delete_array( var => $var );
	exit 0;
}

if ( $action eq 'delete_hash' ) {
	$yq->delete_hash( var => $var );
	exit 0;
}

if ( $action eq 'delete' ) {
	$yq->delete( var => $var );
	exit 0;
}

if ( $action eq 'set_array' ) {
	$yq->set_array( var => $var, vals => \@vals );
	exit 0;
}

if ( $action eq 'set_hash' ) {
	$yq->set_hash( var => $var, hash => $hash );
	exit 0;
}

if ( $action eq 'set_val' ) {
	$yq->set_val( var => $var, val => $val );
	exit 0;
}

if ( $action eq 'set_in_array' ) {
	$yq->set_in_array( var => $var, vals => \@vals, dedup => $dedup );
	exit 0;
}

if ( $action eq 'push_array' ) {
	$yq->push_array( var => $var, vals => \@vals, );
	if ($dedup) {
		$yq->dedup_array( var => $var );
	}
	exit 0;
}

if ( $action eq 'dedup_array' ) {
	$yq->dedup_array( var => $var );
	exit 0;
}

if ( $action eq 'create_array' ) {
	$yq->create_array( var => $var, vals => \@vals );
	exit 0;
}

if ( $action eq 'create_hash' ) {
	$yq->create_hash( var => $var );
	exit 0;
}

if ( $action eq 'merge_yaml' ) {
	$yq->merge_yaml( yaml => $yaml2, merge_mode => $mode );
	exit 0;
}

if ( $action eq 'yaml_diff' ) {
	print $yq->yaml_diff( yaml => $yaml2 );
	exit 0;
}

if ( $action eq 'ensure' ) {
	$yq->ensure( force=>1 );
	exit 0;
}

#
# means we did not match anything
#
die( 'No matching action, -a, found for "' . $action . '"' );
