#!/usr/bin/env perl

use strict;
use warnings;
use Pod::Usage;
use Getopt::Long qw(:config posix_default no_ignore_case gnu_compat);
use Term::ANSIColor qw(colored);

use Data::Generator::FromDDL;
use Data::Generator::FromDDL::Util;

sub parse_num_option {
    # $num_option_str is like 'users:20,bugs:30,100'
    my $num_option_str = shift;
    my @nums = split ',', $num_option_str;

    my $parsed = {
        all => undef,
        tables => {},
    };
    for (@nums) {
        my ($table, $n) = split ':', $_;
        if ($n) {
            $parsed->{tables}{$table} = $n;
        } else {
            # $table contains number
            $parsed->{all} = $table;
        }
    }
    return $parsed;
}

sub parse_bytes_per_sql_option {
    my $bytes = shift;
    if ($bytes =~ /(\d+)KB?/i) {
        return $1 * 1024;
    } elsif ($bytes =~ /(\d+)MB?/i) {
        return $1 * 1024 * 1024;
    } elsif ($bytes =~ /(\d+)GB?/i) {
        return $1 * 1024 * 1024 * 1024;
    } else {
        return $bytes;
    }
}

sub read_ddl {
    my $ddl_files = shift;
    local $/;
    if (@$ddl_files) {
        # read from multiple files
        my $ddl_str = '';
        for my $ddl_file (@$ddl_files) {
            open my $fh, '<', $ddl_file
                or die("Can't open $ddl_file to read\n");
            $ddl_str .= <$fh>;
        }
        return $ddl_str;
    } else {
        return <STDIN>;
    }
}

sub main {
    my $help;
    my $n = 10;;
    my $parser = 'mysql';
    my $include = '';
    my $exclude = '';
    my $out;
    my $format = 'sql';
    my $pretty;
    my $bytes_per_sql = 1024 * 1024; # 1MB
    GetOptions(
        "help|h" => \$help,
        "num|n=s" => \$n,
        "parser|p=s" => \$parser,
        "include|i=s" => \$include,
        "exclude|e=s" => \$exclude,
        "out|o=s" => \$out,
        "format|f=s" => \$format,
        "pretty" => \$pretty,
        "bytes_per_sql=s" => \$bytes_per_sql,
    ) or pod2usage(2);

    pod2usage({
        -exitval => 0,
        -verbose => 99,
        -noperldoc => 1,
        -sections => 'SYNOPSIS|OPTIONS',
    }) if $help;
    pod2usage({
        -message => "Can't specify both of --include and --exclude options",
        -exitval => 1,
        -verbose => 99,
        -noperldoc => 1,
        -sections => 'SYNOPSIS|OPTIONS',
    }) if $include && $exclude;

    my $ddl = read_ddl(\@ARGV);

    my $out_fh;
    if ($out) {
        open $out_fh, '>', $out
            or die("Can't open $out to write\n");
    } else {
        $out_fh = *STDOUT;
    }

    my @include = split ',', $include;
    my @exclude = split ',', $exclude;
    my $num = parse_num_option($n);
    $bytes_per_sql = parse_bytes_per_sql_option($bytes_per_sql);

    my $generator = Data::Generator::FromDDL->new({
        ddl => $ddl,
        parser => $parser,
        include => \@include,
        exclude => \@exclude,
    });

    eval {
        $generator->generate($num, $out_fh, $format, $pretty, $bytes_per_sql);
    };
    if ($@) {
        print colored($@, 'red');
        exit 1;
    }
}

&main();

__END__

=encoding utf-8

=head1 NAME

datagen_from_ddl - Dummy data generator from DDL statements

=head1 SYNOPSIS

    $ datagen_from_ddl [options] your_ddl.sql
    $ datagen_from_ddl --num=users:10,100 --include=users,blogs --format=sql --pretty your_ddl.sql

=head1 DESCRIPTION

B<datagen_from_ddl> generates dummy records and output them to STDOUT in default so that it can pipe to RDBMS client.

    $ datagen_from_ddl --num=100 your_ddl.sql | mysql -u user -p DBNAME

=head1 OPTIONS

=over 4

=item B<-n|--num> (default: 10)

Number of records generated.

Example:

    --num=20 (20 records for all tables)
    --num=users:10,100 (10 records for users and 100 records for other tables)

=item B<-p|--parser (default: MySQL)>

Parser for DDL. Choices are MySQL, SQLite, Oracle, or PostgreSQL.

=item B<-i|--include>

Only tables which are specified this option are processed.

=item B<-e|--exclude>

Tables which are specified this option are ignored(--include and --exclude options are exclusively used).

=item B<-o|--out>

Output file.

=item B<-f|--format (default: SQL)>

Output format. Choices are SQL or JSON.

=item B<--pretty>

Print output prettily.

=item B<--bytes_per_sql> (default: 1MB)

The maximum bytes of bulk insert statement.

This option is releated to the MySQL's B<'max_allowed_packet'> variable which stands for the maximum size of string. It's recommended to suit this option for your MySQL settings.

cf. https://dev.mysql.com/doc/refman/5.1/en/server-system-variables.html#sysvar_max_allowed_packet

=back

=cut

