#!/usr/bin/perl

use strict;
use warnings;
use Carp;
use Getopt::Long;

use DistroDBTools;
use DistroDB::Load;
use DistroDB::BinaryPremap;
use DistroDB::CLI::Stems qw/@loaded_stems/;
use DistroDB::CLI::DistroMap qw/$ORIGIN $DEST/;
use DistroDB::CLI::SaveState qw/$opt_save_state/;
use DistroDB::CLI::DebugName qw/$debug_obname $debug_oname/;
use DistroDB::CreateRawQuiver;
use DistroDB::BinaryDistroMap qw/
&postprocess_binary_distromap
$origin2dest
/;

# TODO: add contents_index based unique files mapping based criteria
# (like, mod %bin%, mod usr/share (not doc) if unique-mapping is dence enough (> 50% in the area)?
# to fix likes of broken mapping
# wesnoth-data    python-module-wesnoth

my $verbose=0;
my $help;
my ($opt_dry_run,$skip_id_map);
my $binary_output_file='binary/40-distrodb-new.txt';

my $opt_experimental;

GetOptions (
    @ProjectDBTools::LONGOPT,
    @DistroDB::CLI::Stems::LONGOPT,
    @DistroDB::CLI::DistroMap::LONGOPT,
    @DistroDB::CLI::SaveState::LONGOPT,
    @DistroDB::CLI::DebugName::LONGOPT,
    'dry-run' => \$opt_dry_run,
    'help'  => \$help,
    'id!'  => \$skip_id_map,
    'z|experimental!'  => \$opt_experimental,
    'O|output-file=s' => \$binary_output_file,
    'verbose+'  => \$verbose,
);

if ($help) {
    _usage();
    exit(0);
}

sub _usage {
    print $0.'
--stem=python3.raw,perl,...
--dry-run
--verbose(+)
';
    &DistroDB::CLI::DebugName::_usage();
}

DistroDB::CLI::Stems->process_options();
DistroDB::CLI::DistroMap->process_options();
$DistroDBTools::verbose=$verbose;
$DistroDB::BinaryPremap::verbose=$verbose;

my $origin={};
my $dest={};
&DistroDB::Load::load_distrodb($origin,$ORIGIN,\@loaded_stems);
&DistroDB::Load::load_distrodb($dest,$DEST,\@loaded_stems);

DistroDB::OriginDestTags->initialize($origin,$dest);
DistroDB::BinaryDistroMap->initialize($origin,$dest);
DistroDB::BinaryPremap->initialize($origin,$dest);

my $raw_origin2dest;
my %ambiguous_map;
if (not $opt_experimental) {
$raw_origin2dest=&DistroDB::CreateRawQuiver::create_map_pkg2pkghash2fingerprint($origin, $dest, \@loaded_stems);
&premap2distromapN($raw_origin2dest);
} else {
$raw_origin2dest=&DistroDB::CreateRawQuiver::create_map_pkg2pkg2stem2trait($origin, $dest, \@loaded_stems);
&premap2distromap1($raw_origin2dest);
}
&postprocess_binary_distromap();

if ($opt_save_state) {
    mkdir ('state'); mkdir ('state/binary');
    &DistroDBTools::write_flag($raw_origin2dest,'state/binary/originpkg.txt');
    &DistroDBTools::write_flag(\%ambiguous_map,'state/binary/ambiguous.txt');# if %ambiguous_map;
}

exit if $opt_dry_run;

unlink (qw/todo-source-reject-SST.txt/);
&DistroDBTools::sort_print_hasharray($origin2dest,$skip_id_map,$binary_output_file);
&DistroDBTools::write_flag(\%DistroDB::BinaryPremap::originsrc_reject_SST,'todo-source-reject-SST.txt') if \%DistroDB::BinaryPremap::originsrc_reject_SST;
# write always to overwrite old flags
&DistroDBTools::write_flag(\%DistroDB::BinaryPremap::originsrc_selfreject_SST,'flags/source/noversion/40-distrodb-SST.txt');

sub premap2distromap1 {
    my ($raw_map_pkg2pkg2stem2trait)=@_;
    foreach my $originpkg (keys(%$raw_map_pkg2pkg2stem2trait)) {
	my @arrows=&DistroDB::CreateRawQuiver::convert_pkg2stem2trait_to_quiver($raw_map_pkg2pkg2stem2trait->{$originpkg});
	my $originmapper=DistroDB::BinaryPremap->new(
	    -originpkg=>$originpkg,
	    -untrimmed_arrowsref=>\@arrows,
	    );
	$originmapper->premap_originpkg();
	if ($originmapper->{-have_same_dist} && ! $originmapper->{-same_map_found}) {
	    $ambiguous_map{$originpkg}=1;
	}
    }
}

sub premap2distromapN {
    my ($raw_map_pkg2pkghash2fingerprint)=@_;
    foreach my $originpkg (keys(%$raw_map_pkg2pkghash2fingerprint)) {
	my @arrows=&DistroDB::CreateRawQuiver::convert_pkghash2fingerprint_to_quiver($raw_map_pkg2pkghash2fingerprint->{$originpkg});
	my $originmapper=DistroDB::BinaryPremap->new(
	    -originpkg=>$originpkg,
	    -untrimmed_arrowsref=>\@arrows,
	    );
	$originmapper->premap_originpkg();
	if ($originmapper->{-have_same_dist} && ! $originmapper->{-same_map_found}) {
	    $ambiguous_map{$originpkg}=1;
	}
    }
}
