#!/usr/bin/perl
# vim: set et ts=4 sw=4:
# -*- coding: utf-8 -*-
#*****************************************************************************
#
#  Copyright (c) 2002 Guillaume Cottenceau
#  Copyright (c) 2002-2008 Thierry Vignaud <tvignaud@mandriva.com>
#  Copyright (c) 2003, 2004, 2005 MandrakeSoft SA
#  Copyright (c) 2005-2008 Mandriva SA
#  Copyright (c) 2013 Matteo Pasotti <matteo.pasotti@gmail.com>
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License version 2, as
#  published by the Free Software Foundation.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
#*****************************************************************************
#
# $Id: rpmdragora 267936 2010-04-26 16:40:21Z jvictor $

use File::ShareDir ':ALL';

use MDK::Common::Func qw(any if_ before_leaving);
use utf8;
use English;

use MDK::Common::DataStructure qw(uniq intersection);
use MDK::Common::Various qw(to_bool first);
use MDK::Common::System qw(arch);

use urpm::media;
use urpm::msg;

use ManaTools::Rpmdragora::init;
use ManaTools::rpmdragora;
use ManaTools::Shared;
use ManaTools::Shared::Locales;
use ManaTools::Rpmdragora::open_db;
use ManaTools::Rpmdragora::gui;
use ManaTools::Rpmdragora::rpmnew;
use ManaTools::Rpmdragora::formatting;
use ManaTools::Rpmdragora::pkg;

use yui;

use feature 'state';
use POSIX qw/uname/;

my $wm_icon = File::ShareDir::dist_file(ManaTools::Shared::distName(), "images/rpmdragora/title-$MODE.png");

# Declarations
my $my_win;
my $factory;
my $mgaFactory;
my $optFactory;
my $extWidgets;

my @itemsToBeRemoved;
my @itemsToBeInstalled;

our $w;
our $statusbar;
my $loc = ManaTools::rpmdragora::locale();

my %elems;

sub _viewbox_callback {
    my ($selection, $options, $wanted_categories) = @_;
    state $old_index = -1;

    # TODO add a check on selection type YItem
    my $curr_index = $selection->index();
    return 0 if $curr_index == $old_index;

    yui::YUI::app()->busyCursor();

    $old_index = $curr_index;
    $default_list_mode = $options->{rviews}->[$curr_index];

    # NOTE an undef value assignment produces a an array containing undef that is not a valid value to pass to
    #      join into writeconf()
    @$mandrakeupdate_wanted_categories = $wanted_categories->{$options->{rviews}->[$curr_index]} ?
                                         @{$wanted_categories->{$options->{rviews}->[$curr_index]}} :
                                         ();

    if ($options->{tree_mode} ne $options->{rviews}->[$curr_index]) {
        $tree_mode->[0] = $options->{tree_mode} = $options->{rviews}->[$curr_index];
        $tree_flat->[0] = $options->{state}{flat};
        reset_search();
        switch_pkg_list_mode($options->{rviews}->[$curr_index]);
        $options->{rebuild_tree}->();
    }

    yui::YUI::app()->normalCursor();

    return 1;
}

sub _filterbox_callback {
    my ($selection, $options, $rfilters) = @_;
    state $old_index = -1;

    # TODO add a check on selection type YItem
    my $curr_index = $selection->index();
    return 0 if $curr_index == $old_index;

    yui::YUI::app()->busyCursor();

    $old_index = $curr_index;
    my $val = $rfilters->[$curr_index];
    if ($filter->[0] ne $val) {
        $filter->[0] = $val;
        $options->{'skip_other'} = $val eq 'skip_other';
        reset_search();
        slow_func(sub { switch_pkg_list_mode($default_list_mode) });
        $options->{rebuild_tree}->();
    }

    yui::YUI::app()->normalCursor();

    return 1;
}

sub _searchmenu_callback {
    my ($selection, $options, $search_types, $current_search_type) = @_;
    state $old_index = -1;

    # TODO add a check on selection type YItem
    my $curr_index = $selection->index();
    return 0 if $curr_index == $old_index;

    yui::YUI::app()->busyCursor();

    $old_index = $curr_index;
    my $val = $search_types->[$curr_index];
    if ($$current_search_type ne $val) {
        $$current_search_type = $val;
        reset_search();
        slow_func(sub { switch_pkg_list_mode($default_list_mode) });
        $options->{rebuild_tree}->();
    }

    yui::YUI::app()->normalCursor();

    return 1;
}


my $current_group = -1;
sub _tree_callback {
    my ($selection, $options) = @_;

    undef $force_displaying_group;
    $selection or return;

    my $fullname = $selection->label();
    my $it = $selection;
    while ($it = $it->parent()) {
        $fullname = join("|", $it->label(), $fullname);
    }
    my $group = $fullname;

    utf8::decode($group);

    if (!$selection->hasChildren()) {
        $options->{add_nodes}->(@{$elems{$group}});
    }
    return;
}

sub _detaillist_changeditem_callback {
    my ($detail_list, $options) = @_;
    my $changedItem = $detail_list->changedItem();
    return if (!$changedItem);

    fast_toggle($changedItem);

    return;
}

sub _detaillist_callback {
    my ($selection, $info, $options, $show_options) = @_;

    $info->setValue("");
    return if( ref $selection ne "yui::YItem");

    ManaTools::Rpmdragora::gui::setInfoOnWidget($options->{table_item_list}[$selection->index()], $info, $show_options);
}

sub _do_search($$$$$$) {
    my ($find_entry, $tree, $options, $current_search_type, $urpm, $pkgs) = @_;

    my $entry = $find_entry->value();
    return if !$entry;

    if (!$use_regexp->[0]) {
        $entry = quotemeta $entry;
        # enable OR search by default:
        $entry =~ s/\\ /|/g if $current_search_type eq 'normal';
    }
    # remove leading/trailing spacing when pasting:
    if ($entry !~ /\S\s\S/) {
        # if spacing in middle, likely a string search in description
        $entry =~ s/^\s*//;
        $entry =~ s/^\s*$//;
    }
    my $entry_rx = eval { qr/$entry/i } or return;

    reset_search();
    # TODO FIXME speed up, we cannot remove an item but rebuilding all is slow
    # We could just rebuild the tree items
    $options->{rebuild_tree}->();

    $options->{state}{flat} and $options->{delete_all}->();
    # TODO: write a collapse_all method
    #$tree->collapse_all;
    my @search_results;
    if ($current_search_type eq 'normal') {
        my $count;
        foreach (@filtered_pkgs) {
            if ($NVR_searches->[0]) {
                next if !/$entry_rx/;
            } else {
                next if MDK::Common::Various::first(split_fullname($_)) !~ /$entry_rx/;
            }
            push @search_results, $_;
            # FIXME: should be done for all research types
            last if $count++ > 2000;
        }
    } elsif ($current_search_type eq 'summaries') {
        my $count;
        foreach (@filtered_pkgs) {
            next if get_summary($_) !~ /$entry_rx/;
            push @search_results, $_;
            # FIXME: should be done for all research types
            last if $count++ > 2000;
        }
    } else {
        my $searchstop;
        #my $searchw = ugtk2->new($loc->N("Software Management"), grab => 1, transient => $w->{real_window});
        my $searchw = $factory->createPopupDialog;
        my $vbox = $factory->createVBox($searchw);
        my $lblWIP = $factory->createLabel($vbox, $loc->N("Please wait, searching..."));
        my $searchprogress = $factory->createProgressBar($vbox, '');

        my $replace_pnt = $factory->createReplacePoint($vbox);
#         my $stop_button = $factory->createIconButton($vbox,"",$loc->N("Stop"));

        #gtkadd(
        #$searchw->{window},
        #gtkpack__(
            #gtknew('VBox', spacing => 5),
            #gtknew('Label', text => $loc->N("Please wait, searching...")),
            #my $searchprogress = gtknew('ProgressBar', width => 300),
            #gtkpack__(
            #gtknew('HButtonBox', layout => 'spread'),
            #gtksignal_connect(
                #Gtk2::Button->new(but($loc->N("Stop"))),
                #clicked => sub { $searchstop = 1 },
            #),
            #),
        #),
        #);
        #$searchw->sync;
        $searchw->recalcLayout();
        $searchw->pollEvent();

        # should probably not account backports packages or find a way to search them:
        my $total_size = scalar keys %$pkgs;
        my $progresscount = 0;

        my $update_search_pb = sub {
            $progresscount++;
            my $val = int($progresscount * 100 / $total_size);
            $searchprogress->setValue($val);
            $searchw->pollEvent() if $searchw->isTopmostDialog(); # refresh only if top most or crashing
        };
        my $gurpm; # per medium download progress bar (if needed)
        my $_gurpm_clean_guard = MDK::Common::Func::before_leaving { undef $gurpm };
        foreach my $medium (grep { !$_->{ignore} } @{$urpm->{media}}) {
            $searchstop and last;

            my $xml_info_file =
                urpm::media::any_xml_info($urpm, $medium,
                                        ($current_search_type eq 'files' ? 'files' : 'info'),
                                        undef, sub {
                                            $gurpm ||= ManaTools::Rpmdragora::gurpm->new(
                                                text => $loc->N("Please wait"),
                                                main_dialog => $searchw,
                                                parent => $replace_pnt,
                                            );
                                            $gurpm->progress(0);
                                            download_callback($gurpm, @_) or do {
                                                $searchstop = 1;
                                            };
                                        });
            if (!$xml_info_file) {
                $urpm->{error}($loc->N("no xml-info available for medium \"%s\"", $medium->{name}));
                next;
            }
            $searchstop and last;

            require urpm::xml_info;
            require urpm::xml_info_pkg;

            $urpm->{log}("getting information from $xml_info_file");
            if ($current_search_type eq 'files') {
                # special version for speed (3x faster), hopefully fully compatible
                my $F = urpm::xml_info::open_lzma($xml_info_file);
                my $fn;
                local $_;
                while (<$F>) {
                    if ($searchstop) {
                        statusbar_msg($loc->N("Search aborted"), 1);
                        goto end_search;
                    }
                    if (m!^<!) {
                        ($fn) = /fn="(.*)"/;
                        $update_search_pb->();
                    } elsif (/$entry_rx/) {
                        $fn or $urpm->{fatal}("fast algorithm is broken, please report a bug");
                        push @search_results, $fn;
                    }
                }
            } else {
                eval {
                    urpm::xml_info::do_something_with_nodes(
                        'info',
                        $xml_info_file, sub {
                            $searchstop and die 'search aborted';
                            my ($node) = @_;
                            $update_search_pb->();
                            push @search_results, $node->{fn} if $node->{description} =~ $entry_rx;
                            #$searchstop and last;
                            return 0 || $searchstop;
                        },
                    );
                };
                my $err = $@;
                if ($err =~ /search aborted/) {
                    statusbar_msg($loc->N("Search aborted"), 1);
                }
            }
        }

        end_search:
        @search_results = uniq(@search_results); #- there can be multiple packages with same version/release for different arch's
        @search_results = intersection(\@search_results, \@filtered_pkgs);
        $searchw->destroy;
    }

    if (@search_results) {
        @search_results = sort_packages(@search_results);
        $elems{$results_ok} = [ map { [ $_, $results_ok ] } @search_results ];

        ManaTools::Rpmdragora::gui::add_tree_item($tree, $results_ok, 1);
        $options->{add_nodes}->(map { [ $_, $results_ok . ($options->{tree_mode} eq 'by_presence'
                                 ? '|' . ($pkgs->{$_}{pkg}->flag_installed ? $loc->N("Upgradable") : $loc->N("Addable"))
                                 : ($options->{tree_mode} eq 'by_selection'
                                    ? '|' . ($pkgs->{$_}{selected} ? $loc->N("Selected") : $loc->N("Not selected"))
                                    : ''))
                      ] } @search_results);
    } else {
        ManaTools::Rpmdragora::gui::add_tree_item($tree, $results_none, 1);
        # clear package list:
        $options->{add_nodes}->();
        my $string = $default_list_mode eq 'all' && $filter->[0] eq 'all' ? $loc->N("No search results.") :
          $loc->N("No search results. You may want to switch to the '%s' view and to the '%s' filter",
            $loc->N("All"), $loc->N("All"),);
        statusbar_msg($string , 1);
    }
    my $tree_selection = $tree->currentItem();
}

sub _quit {
    real_quit();
}

sub _run_treeview_dialog {
    my ($callback_action) = @_;

    my ($options, $tree, $detail_list, $detail_list_model);
    (undef, $size_free) = MDK::Common::System::df('/usr');

    # OLD $::main_window = $w->{real_window};
    $::main_window = $my_win;
    $size_selected = 0;

    $options = {
        build_tree => sub { build_tree($tree, \%elems, $options, $force_rebuild, @_) },
        partialsel_unsel => sub {
            my ($unsel, $sel) = @_;
            @$sel = grep { exists $pkgs->{$_} } @$sel;
            @$unsel < @$sel;
        },
        get_status => sub {
            $loc->N("Selected: %s / Free disk space: %s", urpm::msg::formatXiB($size_selected), urpm::msg::formatXiB($size_free*1024));
        },
        rebuild_tree => sub { $tree->rebuildTree(); },
    };

    my $vbox = $factory->createVBox($my_win);

    my $hbox_headbar = $factory->createHBox($vbox);
    my $head_align_left = $factory->createLeft($hbox_headbar);
    my $head_align_right = $factory->createRight($hbox_headbar);
    my $headbar = $factory->createHBox($head_align_left);
    my $headRight = $factory->createHBox($head_align_right);

    #Line for logo and title
    my $hbox_iconbar  = $factory->createHBox($vbox);
    $head_align_left  = $factory->createLeft($hbox_iconbar);
    $hbox_iconbar     = $factory->createHBox($head_align_left);
    $factory->createImage($hbox_iconbar, $wm_icon);

    $factory->createHeading($hbox_iconbar, $::MODE eq 'update' ? $loc->N("Software Packages Update") : $loc->N("Software Management"));

    my $hbox_top = $factory->createHBox($vbox);
    my $hbox_middle = $factory->createHBox($vbox);
    my $hbox_bottom = $factory->createHBox($vbox);
    my $hbox_footbar = $factory->createHBox($vbox);

    $hbox_headbar->setWeight(1,10);
    $hbox_top->setWeight(1,10);
    $hbox_middle->setWeight(1,50);
    $hbox_bottom->setWeight(1,30);
    $hbox_footbar->setWeight(1,10);

    # Tree for groups
    $tree = $factory->createTree($hbox_middle, "");
    $tree->setWeight(0,20);
    $tree->setNotify(1);

    my $detail_list_header = new yui::YTableHeader();
    my $display_arch_col = to_bool(arch() =~ /64/);
    my @columns = (qw(name summary version release), if_($display_arch_col, 'arch'));

    my %columns = (
        'name' => {
            title => $loc->N("Package"),
            markup => $pkg_columns{short_name},
        },
        'summary' => {
            title => $loc->N("Summary"),
        },
        'version' => {
            title => $loc->N("Version"),
            text => $pkg_columns{version},
        },
        'release' => {
            title => $loc->N("Release"),
            text => $pkg_columns{release},
        },
        if_($display_arch_col, 'arch' => {
            title =>
              #-PO: "Architecture" but to be kept *small* !!!
              $loc->N("Arch."),
            text => $pkg_columns{arch},
        }),
        'mark' => {
            title => $loc->N("ToInst"),
        }
    );
    ## check column is first no title needed here, but we need to add it
    $detail_list_header->addColumn("");
    foreach my $col (@columns{@columns}) {
        $detail_list_header->addColumn($col->{title});
    }

    $detail_list_header->addColumn($loc->N("Status"));

    $detail_list = $mgaFactory->createCBTable($hbox_middle,$detail_list_header,$yui::YCBTableCheckBoxOnFirstColumn);
    $detail_list->setWeight(0,50);
    $detail_list->setImmediateMode(1);

=for comment
    my $cursor_to_restore;
    $_->signal_connect(
    expose_event => sub {
        $cursor_to_restore or return;
        gtkset_mousecursor_normal($tree->window);
        undef $cursor_to_restore;
    },) foreach $tree, $detail_list;

    $tree->currentItem(changed => sub {
        my ($model, $iter) = $_[0]->get_selected;
        return if !$iter;
        state $current_group;
        my $new_group = $model->get_path_str($iter);
        return if $current_group eq $new_group && !$force_displaying_group;
        undef $force_displaying_group;
        $current_group = $new_group;
        $model && $iter or return;
        my $group = $model->get($iter, 0);
        my $parent = $iter;
        while ($parent = $model->iter_parent($parent)) {
            $group = join('|', $model->get($parent, 0), $group);
        }
        $detail_list->window->freeze_updates;
        $options->{add_nodes}->(@{$elems{$group}});
        $detail_list->window->thaw_updates if $detail_list->window;
    });
=cut
    $options->{state}{splited} = 1;
    $options->{state}{flat} = $tree_flat->[0];


    my $is_backports = get_inactive_backport_media(fast_open_urpmi_db());

    my %filters = (
        all           => $loc->N("All"),
        installed     => $loc->N("Installed"),
        non_installed => $loc->N("Not installed"),
    );
    my @ordered_filters = (qw (all installed non_installed) );
    my ($sysname, $nodename, $rel, $ver, $machine) = POSIX::uname();
    if ($machine eq "x86_64") {
        # NOTE this should work on other architectures too, but maybe it
        #      is a nonsense, at least for i586
        $filters{'skip_other'} = $loc->N("Show %s and noarch only", $machine);
        push @ordered_filters, 'skip_other';
    }

#     leaving the code by now waiting for rpmdrake developers comment
#     # handle migrating config file from rpmdragora <= 4.9
#     if (exists $filters{$default_list_mode}) {
#         $filter->[0] = $default_list_mode;
#         $default_list_mode = 'all';
#     }

    $options->{tree_mode} = $default_list_mode;

    my %modes = (
        flat => $loc->N("All packages, alphabetical"),
        by_group => $loc->N("All packages, by group"),
        by_leaves => $loc->N("Leaves only, sorted by install date"),
        by_presence => $loc->N("All packages, by update availability"),
        by_selection => $loc->N("All packages, by selection state"),
        by_size => $loc->N("All packages, by size"),
        by_source => $loc->N("All packages, by medium repository"),
    );

    my %views = (
        all => $loc->N("All"),
        if_($is_backports, backports => $loc->N("Backports")),
        meta_pkgs => $loc->N("Meta packages"),
        gui_pkgs => $loc->N("Packages with GUI"),
        all_updates => $loc->N("All updates"),
        security => $loc->N("Security updates"),
        bugfix => $loc->N("Bugfixes updates"),
        normal => $loc->N("General updates")
   );
    my @ordered_views = (qw (all meta_pkgs gui_pkgs all_updates security normal) );
    push @ordered_views, 'backports' if $is_backports;

    $options->{rviews} = \@ordered_views;

    my %default_mode = (install => 'all', # we want the new GUI by default instead of "non_installed"
                        remove => 'installed',
                        update => 'security',
                    );
    my %wanted_categories = (
        all_updates => [ qw(security bugfix normal) ],
        security => [ 'security' ],
        bugfix => [ 'bugfix' ],
        normal => [ 'normal' ],
    );

    my $view_box = $factory->createComboBox($hbox_top,"");
    my $itemColl = new yui::YItemCollection;

    foreach (@ordered_views) {
        my $item = yui::YItem->new("$views{$_}", 0);
        $item->setSelected(1) if defined($views{$default_list_mode}) && $_ eq $default_list_mode;
        $itemColl->push($item);
        $item->DISOWN();
    }
    $view_box->addItems($itemColl);
    $view_box->setNotify(1);

    $options->{tree_submode} ||= $default_list_mode;
    $options->{tree_subflat} ||= $options->{state}{flat};

    my $filter_box = $factory->createComboBox($hbox_top,"");
    $itemColl = new yui::YItemCollection;

    $options->{'skip_other'} = $filter->[0] eq 'skip_other';

    foreach (@ordered_filters) {
        my $item = yui::YItem->new("$filters{$_}", 0);
        $item->setSelected(1) if defined($filters{$filter->[0]}) && $_ eq $filter->[0];
        $itemColl->push($item);
        $item->DISOWN();
    }
    $filter_box->addItems($itemColl);
    $filter_box->setNotify(1);


    my %local_search_types = (
        normal       => $loc->N("in names"),
        descriptions => $loc->N("in descriptions"),
        summaries    => $loc->N("in summaries"),
        files        => $loc->N("in file names"),
    );
    my @search_types = ( qw(normal descriptions summaries files) );
    my $current_search_type = $search_types[0];

    my $search_menu = $factory->createComboBox($hbox_top,"");
    $itemColl = new yui::YItemCollection;
    foreach (@search_types) {
        my $item = yui::YItem->new("$local_search_types{$_}", 0);
        $item->setSelected(1) if defined($local_search_types{$current_search_type}) && $_ eq $current_search_type;
        $itemColl->push($item);
        $item->DISOWN();
    }
    $search_menu->addItems($itemColl);
    $search_menu->setNotify(1);

    $find_entry = $factory->createInputField($hbox_top, "");

    my $icon_file = File::ShareDir::dist_file(ManaTools::Shared::distName(), "images/manalog.png");
    my $find_button = $factory->createIconButton($hbox_top, $icon_file, $loc->N("Search"));
    $find_button->setWeight(0,6);
    $my_win->setDefaultButton($find_button);
    $find_entry->setKeyboardFocus();

    $icon_file = File::ShareDir::dist_file(ManaTools::Shared::distName(), "images/rpmdragora/clear_22x22.png");
    my $reset_search_button = $factory->createIconButton($hbox_top, $icon_file, $loc->N("Reset"));
    $reset_search_button->setWeight(0,7);
    $find_entry->setWeight(0,10);

    #OLD my $info = Gtk2::Mdv::TextView->new;
    #my $info = $factory->createMultiLineEdit($hbox_bottom,"");
    my $info = $factory->createRichText($hbox_bottom,"");
    #$info->setDisabled();
    $info->setWeight(0,40);
    $info->setWeight(1,40);
    #OLD $info->set_left_margin(2);
    #OLD $info->set_right_margin(15);  #- workaround when right elevator of scrolled window appears

    my $find_callback = sub {
        _do_search($find_entry, $tree, $options, $current_search_type, $urpm, $pkgs);
    };

    my $select_all_button = $factory->createIconButton($hbox_footbar,"",$loc->N("&Select all"));
    $select_all_button->setWeight(0,6);

    my $apply_button = $factory->createIconButton($hbox_footbar,"",$loc->N("&Apply"));
    $apply_button->setWeight(0,6);
    # NOTE apply button is disabled if not root atm
    # TODO use a method instead of testing uid    #
    $apply_button->setEnabled(0) if ($EUID != 0);

    my $QuitButton = $factory->createIconButton($hbox_footbar,"",$loc->N("&Quit"));
    $QuitButton->setWeight(0,6);


    #my $hpaned = gtknew('HPaned', position => $typical_width*0.9,
    #                    child1 => gtknew('ScrolledWindow', child => $tree),
    #                    resize1 => 0, shrink1 => 0,
    #                    resize2 => 1, shrink2 => 0,
    #                    child2 => gtknew('VPaned',
    #                                     child1 => gtknew('ScrolledWindow', child => $detail_list), resize1 => 1, shrink1 => 0,
    #                                     child2 => gtknew('ScrolledWindow', child => $info), resize2 => 1, shrink2 => 0
    #                                 )
    #                );

    my $reload_db_and_clear_all = sub {
        slow_func(sub {
                      $force_rebuild = 1;
                      ManaTools::Rpmdragora::gui::pkgs_provider($options->{tree_mode}, skip_updating_mu => 1);
                      ManaTools::Rpmdragora::gui::reset_search();
                      $size_selected = 0;
                      $options->{rebuild_tree}->();
                      $find_callback->();
        });
    };

    #OLD my $status = gtknew('Label');
    my $status = $factory->createLabel($vbox, "");
    my $checkbox_show_autoselect;
    my %check_boxes;
    my $auto_select_string =
            $loc->N("/_Options") . $loc->N("/_Select dependencies without asking");
    my $clean_cache_string =
            $loc->N("/_Options") . "/" .
            $loc->N("Clear download cache after successful install");
    my $updates_string = $loc->N("/_Options") . $loc->N("/_Compute updates on startup");
    my $NVR_string = $loc->N("/_Options") . "/" . $loc->N("Search in _full package names");
    my $regexp_search_string = $loc->N("/_Options") . "/" . $loc->N("Use _regular expressions in searches");

    $itemColl = new yui::YItemCollection;
    # build File menu
    my %fileMenu = (
            widget => $factory->createMenuButton($headbar,$loc->N("File")),
            update => new yui::YMenuItem($loc->N("Update media")),
         reset_sel => new yui::YMenuItem($loc->N("Reset the selection")),
            reload => new yui::YMenuItem($loc->N("Reload the packages list")),
            quit   => new yui::YMenuItem($loc->N("&Quit")),
    );

    my @ordered_menu_lines = qw(update reset_sel reload quit);
    foreach (@ordered_menu_lines) {
        $itemColl->push($fileMenu{ $_ });
        $fileMenu{$_}->DISOWN();
    }
    $fileMenu{ widget }->addItems($itemColl);
    $fileMenu{ widget }->rebuildMenuTree();
    $itemColl->clear();

    # build Settings (old Options) menu
    my $settings_menu = $factory->createMenuButton($headbar,$loc->N("Settings"));
    my %settingsMenuLabel = (
        media_manager => $loc->N("&Media Manager"),
        options       => $loc->N("Options"),
    );
    @ordered_menu_lines = qw( media_manager options );
    foreach my $lbl (@ordered_menu_lines) {
        my $item = new yui::YMenuItem($settingsMenuLabel{ $lbl });
        $itemColl->push($item);
        $item->DISOWN();
    }
    $settings_menu->addItems($itemColl);
    $settings_menu->rebuildMenuTree();
    $itemColl->clear();

=for comment
    my $a_s_string = $auto_select_string;
    my $c_c_string = $clean_cache_string;
    # stripping gtk-related stuff
    $a_s_string =~s/\/.+\/_//g;
    $c_c_string =~s/\/.+\/_//g;
    my $optMnuItemAutoSelect = new yui::YMenuItem($a_s_string);
    my $optMnuItemCleanCache = new yui::YMenuItem($c_c_string);

    $settings_menu->addItem($optMnuItemAutoSelect);
    $settings_menu->addItem($optMnuItemCleanCache);

    $settings_menu->rebuildMenuTree();

=cut

    # build View menu
    my $view_menu = $factory->createMenuButton($headbar,$loc->N("View"));

    # build help menu
    my %helpMenu = (
            widget     => $factory->createMenuButton($headRight, $loc->N("&Help")),
            help       => new yui::YMenuItem($loc->N("Manual")),
            report_bug => new yui::YMenuItem($loc->N("Report Bug")),
            about      => new yui::YMenuItem($loc->N("&About")),
    );
    @ordered_menu_lines = qw(help report_bug about);
    foreach (@ordered_menu_lines) {
        $helpMenu{ widget }->addItem($helpMenu{ $_ });
    }
    $helpMenu{ widget }->rebuildMenuTree();


    $statusbar = $factory->createBusyIndicator($hbox_footbar, "" );

=for comment
    my ($menu, $factory) = create_factory_menu(
    $w->{real_window},
    [ $loc->N("/_File"), undef, undef, undef, '<Branch>' ],
    if_(
        ! $>,
        [ $loc->N("/_File") . $loc->N("/_Update media"), undef, sub {
        update_sources_interactive($urpm, transient => $w->{real_window})
            and $reload_db_and_clear_all->();
        }, undef, '<Item>' ]
    ),
    [ $loc->N("/_File") . $loc->N("/_Reset the selection"), undef, sub {
        if ($MODE ne 'remove') {
                my $db = eval { open_rpm_db() };
                if (!ref($db)) {
                    statusbar_msg($loc->N("Reset aborted (RPM DB is locked by another process)"), 1);
                    return;
                }
        $urpm->disable_selected(
            $db, $urpm->{state},
            map { if_($pkgs->{$_}{selected}, $pkgs->{$_}{pkg}) } keys %$pkgs,
        );
        }
        undef $pkgs->{$_}{selected} foreach keys %$pkgs;
        reset_search();
        $size_selected = 0;
        $force_displaying_group = 1;
        my $tree_selection = $tree->get_selection;
        $tree_selection->select_path(Gtk2::TreePath->new_from_string('0')) if !$tree_selection->get_selected;
        $tree_selection->signal_emit('changed');
    }, undef, '<Item>' ],
    [ $loc->N("/_File") . $loc->N("/Reload the _packages list"), undef, $reload_db_and_clear_all, undef, '<Item>' ],
    [ $loc->N("/_File") . $loc->N("/_Quit"), $loc->N("<control>Q"), \&quit, undef, '<Item>', ],
    #[ $loc->N("/_View"), undef, undef, undef, '<Branch>' ],
    if_(!$>,
        [ $loc->N("/_Options"), undef, undef, undef, '<Branch>' ],
        [ $auto_select_string, undef,
              sub {
                  my $box = $check_boxes{$auto_select_string};
                  $auto_select->[0] = $box->get_active;
                  $::rpmdragora_options{auto} = $box->get_active;
                  $urpm->{options}{auto} = $box->get_active;
              },
              undef, '<CheckItem>' ],
        [ $clean_cache_string, undef,
              sub {
                  $clean_cache->[0] =
                          $check_boxes{$clean_cache_string}->get_active;
                  $::noclean = !$clean_cache->[0];
              },
              undef, '<CheckItem>' ],
        [ $loc->N("/_Options") . $loc->N("/_Media Manager"), undef, sub {
               require ManaTools::Rpmdragora::edit_urpm_sources;
               ManaTools::Rpmdragora::edit_urpm_sources::run() && $reload_db_and_clear_all->();
           }, undef, '<Item>' ],
        [ $loc->N("/_Options") . $loc->N("/_Show automatically selected packages"), undef, sub {
        $dont_show_selections->[0] = !$checkbox_show_autoselect->get_active;
        }, undef, '<CheckItem>' ],

        [ $updates_string, undef, sub {
                $compute_updates->[0] = $check_boxes{$updates_string}->get_active;
        }, undef, '<CheckItem>' ],
        [ $NVR_string, undef, sub {
                $NVR_searches->[0] = $check_boxes{$NVR_string}->get_active;
        }, undef, '<CheckItem>' ],
        [ $regexp_search_string, undef, sub {
                $use_regexp->[0] = $check_boxes{$regexp_search_string}->get_active;
        }, undef, '<CheckItem>' ],
    ),
    [ $loc->N("/_View"), undef, undef, undef, '<Branch>' ],
        (map {
            state ($idx, $previous);
            my $type = $idx ? join('/', $loc->N("/_View"), $previous) : '<RadioItem>';
            $type =~ s/_//g; # gtk+ retrieve widgets by their path w/o any shortcut marks
            $previous = $modes{$_};
            $idx++;
            my $val = $_;
            [ $loc->N("/_View") . '/' . $modes{$_}, undef, sub { $view_callback->($val) }, 0, $type ];
        } qw(flat by_group by_leaves by_presence by_selection by_size by_source)),
    [ $loc->N("/_Help"), undef, undef, undef, '<Branch>' ],
     [ $loc->N("/_Help") . $loc->N("/_Report Bug"), undef, sub { run_drakbug('rpmdragora') }, undef, '<Item>' ],
    [ $loc->N("/_Help") . $loc->N("/_Help"), undef, sub { ManaTools::rpmdragora::open_help('') }, undef, '<Item>' ],
     [ $loc->N("/_Help") . $loc->N("/_About..."), undef, sub {
         my $license = formatAlaTeX(translate($::license));
         $license =~ s/\n/\n\n/sg; # nicer formatting
         my $w = gtknew('AboutDialog', name => $loc->N("Rpmdragora"),
                        version => $ManaTools::Rpmdragora::init::version,
                        copyright => $loc->N("Copyright (C) %s by Mandriva", '2002-2009')."\n".$loc->N("Copyright (C) %s by Mageia.Org", '2010-2013'),
                        license => $license, wrap_license => 1,
                        comments => $loc->N("Rpmdragora is the Mageia package management tool."),
                        website => 'http://www.mageia.org',
                        website_label => $loc->N("Mageia"),
                        authors => "Thierry Vignaud <vignaud@mandriva.com>\nAngelo Naselli <anaselli@gmail.com>\nMatteo Pasotti <matteo.pasotti@gmail.com>",
                        artists => 'Hélène Durosini <ln@mandriva.com>',
                        translator_credits =>
                          #-PO: put here name(s) and email(s) of translator(s) (eg: "John Smith <jsmith@nowhere.com>")
                          $loc->N("_: Translator(s) name(s) & email(s)\n"),
                        transient_for => $::main_window, modal => 1, position_policy => 'center-on-parent',
                    );
         $w->show_all;
         $w->run;
       }, undef, '<Item>'
     ]

    );

    # to retrieve a path, one must prevent "accelerators completion":
    my $get_path = sub { return join('', map { my $i = $_; $i =~ s/_//g; $i } @_) };

    if (my $widget = $factory->get_item('<main>' . $get_path->($loc->N("/_View") . '/' . $modes{$mode->[0]}))) {
        $widget->set_active(1);
    } else {
        warn "Impossible to set $mode->[0] view as default\n";
    }

    %check_boxes = map {
        $_ => $factory->get_widget("<main>" . $get_path->($_));
    } ($auto_select_string,
       $clean_cache_string,
       $NVR_string,
       $updates_string,
       $regexp_search_string);

    if (!$>) {
        $check_boxes{$regexp_search_string}->set_active($use_regexp->[0]);
        $check_boxes{$NVR_string}->set_active($NVR_searches->[0]);
        $check_boxes{$auto_select_string}->set_active($auto_select->[0]);
        $check_boxes{$updates_string}->set_active($compute_updates->[0]);
        $check_boxes{$clean_cache_string}->set_active($clean_cache->[0]);
    }

    $checkbox_show_autoselect = $factory->get_widget("<main>" . strip_first_underscore($loc->N("/_Options"), $loc->N("/_Show automatically selected packages")))
    and $checkbox_show_autoselect->set_active(!$dont_show_selections->[0]);

    my $accel = Gtk2::AccelGroup->new;
    $accel->connect(Gtk2::Gdk->keyval_from_name('F'), [ 'control-mask' ], [ 'visible' ], sub { $find_entry->grab_focus });
    $w->{real_window}->add_accel_group($accel);

    gtkadd(
    $w->{window},
    gtkpack_(
        gtknew('VBox', spacing => 3),
        0, $menu,
        if_(second(gtkroot()->get_size) >= 600, 0, getbanner()),
        1, gtkadd(
        gtknew('Frame', border_width => 3, shadow_type => 'none'),
        gtkpack_(
            gtknew('VBox', spacing => 3),
            0, gtkpack_(
            gtknew('HBox', spacing => 10),
            0, $view_box,
            0, $filter_box,
            0, gtknew('Label', text => $loc->N("Find:")),
            1, $find_entry = gtknew('Entry', width => 260,
                                             primary_icon => 'gtk-find',
                                             secondary_icon => 'gtk-clear',
                                             tip => $loc->N("Please type in the string you want to search then press the <enter> key"),
                                             'icon-release' => $find_callback,
                                             'icon-press' => sub {
                                                 my (undef, $pos, $event) = @_;
                                                 # emulate Sexy::IconEntry's clear_button:
                                                 if ($pos eq 'secondary') {
                                                     $find_entry->set_text('');
                                                     reset_search();
                                                 }
                                                 return if $pos ne 'primary';
                                                 $search_menu->popup(undef, undef, undef, undef, $event->button, $event->time);
                                             },
                key_press_event => sub {
                member($_[1]->keyval, $Gtk2::Gdk::Keysyms{Return}, $Gtk2::Gdk::Keysyms{KP_Enter})
                    and $find_callback->();
                },
                                         ),
            ),
            1, $hpaned,
            0, $status,
            0, gtkpack_(
            gtknew('HBox', spacing => 20),
            0, gtksignal_connect(
                Gtk2::Button->new(but_($loc->N("Select all"))),
                clicked => sub {
                       toggle_all($options, 1);
                   },
            ),
            1, gtknew('Label'),
            0, my $action_button = gtksignal_connect(
                Gtk2::Button->new(but_($loc->N("Apply"))),
                clicked => sub { do_action($options, $callback_action, $info) },
            ),
            0, gtksignal_connect(
                Gtk2::Button->new(but_($loc->N("Quit"))),
                clicked => \&quit,
            ),
            ),
        ),
        ),
        0, $statusbar = Gtk2::Statusbar->new,
    ),
    );
    $action_button->set_sensitive(0) if $>;
    $find_entry->grab_focus;

    gtktext_insert($info, [
        [ $info->render_icon('gtk-dialog-info', 'GTK_ICON_SIZE_DIALOG', undef) ],
        @{ ugtk2::markup_to_TextView_format(
            formatAlaTeX(join("\n\n\n", format_header($loc->N("Quick Introduction")),
                              $loc->N("You can browse the packages through the categories tree on the left."),
                              $loc->N("You can view information about a package by clicking on it on the right list."),
                              $loc->N("To install, update or remove a package, just click on its \"checkbox\"."))))
      }
    ]);

    $w->{rwindow}->set_default_size($typical_width*2.7, 500) if !$::isEmbedded;
=cut

    $find_entry->setText($rpmdragora_options{search}[0]) if $rpmdragora_options{search};

    #if ($rpmdragora_width->[0] && $rpmdragora_height->[0]) {
        ## so that we can shrink back:
        #$w->{real_window}->set_default_size($rpmdragora_width->[0], $rpmdragora_height->[0]);
    #}
    #$w->{rwindow}->show_all;
    #$w->{rwindow}->set_sensitive(0);

    # ensure treeview get realized so that ->get_selection returns something
    #$detail_list->realize;
    #gtkflush();

    #OLD slow_func($::main_window->window, sub { pkgs_provider($default_list_mode) }); # default mode
    slow_func(sub { pkgs_provider($default_list_mode) }); # default mode
    if (@initial_selection) {
        print "\n== Initial selection: @initial_selection\n";
        $options->{initial_selection} = \@initial_selection;
        undef $pkgs->{$_}{selected} foreach @initial_selection;
    }

    #$w->{rwindow}->set_sensitive(1);

    $options->{widgets} = {
        w => $my_win,
        tree => $tree,
        #detail_list_model => $detail_list_model,
        detail_list => $detail_list,
        info => $info,
        status => $status,
    };
    $options->{init_callback} = $find_callback if $rpmdragora_options{search};

    ask_browse_tree_given_widgets_for_rpmdragora($options);

    my $info_options = {};
    # select group and show items evenctually
    _tree_callback($tree->currentItem(),\%$options);
     _detaillist_callback($detail_list->selectedItem(), $info, \%$options);

    ######## main loop ####################
    while(1) {
        my $event = $my_win->waitForEvent();

        my $eventType = $event->eventType();

        #event type checking
        if ($eventType == $yui::YEvent::CancelEvent) {
            last if _quit();
        }
        elsif ($eventType == $yui::YEvent::MenuEvent) {
            ### MENU ###
            my $item = $event->item();
            if (!$item) {
                #URL emitted or at least a ref into RichText widget
                my $url = yui::toYMenuEvent($event)->id ();
                if (ManaTools::Rpmdragora::gui::info_details($url, $info_options) )  {
                    $item = $detail_list->selectedItem();
                    _detaillist_callback($item, $info, \%$options, $info_options);
                }
                else {
                    # default it's really a URL
                    ManaTools::Rpmdragora::gui::run_browser($url);
                }
            }
            else {
                my $menuLabel = $item->label();
print "Menu " . $menuLabel . " chosen\n";
                if ($menuLabel eq $fileMenu{ quit }->label()) {
                    #menu File->Quit
                    last if _quit();
                }
                elsif ($menuLabel eq $fileMenu{ update }->label()) {
                    update_sources_interactive($urpm, transient => $my_win)
                    and $reload_db_and_clear_all->();
                }
                elsif ($menuLabel eq $fileMenu{ reset_sel }->label()) {
                    if ($MODE ne 'remove') {
                        my $db = eval { open_rpm_db() };
                        if (!ref($db)) {
                            statusbar_msg($loc->N("Reset aborted (RPM DB is locked by another process)"), 1);
                            last;
                        }
                        $urpm->disable_selected(
                            $db, $urpm->{state},
                            map { if_($pkgs->{$_}{selected}, $pkgs->{$_}{pkg}) } keys %$pkgs,);
                    }
                    undef $pkgs->{$_}{selected} foreach keys %$pkgs;
                    reset_search();
                    $size_selected = 0;
                    $force_displaying_group = 1;
                    my $tree_selection = $tree->currentItem();
                }
                elsif ($menuLabel eq $fileMenu{ reload }->label()) {
                    $reload_db_and_clear_all->();
                }
                elsif ($menuLabel eq $settingsMenuLabel{media_manager}) {
                    require ManaTools::Rpmdragora::edit_urpm_sources;
                    ManaTools::Rpmdragora::edit_urpm_sources::run() && $reload_db_and_clear_all->();
                }
                elsif ($menuLabel eq $settingsMenuLabel{options}) {
                }
                elsif ($menuLabel eq $helpMenu{ about }->label()) {
                    my $translators = ManaTools::Shared::i18NTranslators($loc->N("_: Translator(s) name(s) & email(s)\n"));

                    my $sh_gui = ManaTools::Shared::GUI->new();
                    $sh_gui->AboutDialog({ name => "Rpmdragora",
                                                version => $VERSION,
                            credits => $loc->N("Copyright (C) %s Mageia community", '2013-2017'),
                            license => $loc->N("GPLv2"),
                            description => $loc->N("Rpmdragora is the Mageia package management tool."),
                            authors => $loc->N("<h3>Developers</h3>
                                                        <ul><li>%s</li>
                                                            <li>%s</li>
                                                        </ul>
                                                        <h3>Translators</h3>
                                                        <ul>%s</ul>",
                                                        "Angelo Naselli &lt;anaselli\@linux.it&gt;",
                                                        "Matteo Pasotti &lt;matteo.pasotti\@gmail.com&gt;",
                                                        $translators
                                                        ),
                                }
                    );
                }
            }
        }
        elsif ($eventType == $yui::YEvent::WidgetEvent) {
            # widget selected

            my $widget      = $event->widget();
            my $perform_search = 0;
            my $perform_show_packages = 0;

            if($widget == $reset_search_button) {
                $find_entry->setValue('');
                reset_search();
                $options->{rebuild_tree}->();
                $perform_show_packages = 1;
            }
            elsif ($widget == $find_button) {
                $perform_search = 1;
            }
            elsif ($widget == $select_all_button) {
                toggle_all($options, 1);
                #select_all_current_packages(\$detail_list);
            }
            elsif ($widget == $apply_button) {
                do_action($options, $callback_action, $info);
            }
            elsif ($widget == $view_box) {
                if (_viewbox_callback($view_box->selectedItem(), \%$options, \%wanted_categories)) {
                    if ($find_entry->value()) {
                        $perform_search = 1;
                    }
                    else {
                        $perform_show_packages = 1;
                    }
                }
            }
            elsif ($widget == $filter_box) {
                if (_filterbox_callback($filter_box->selectedItem(), \%$options, \@ordered_filters)) {
                    if ($find_entry->value()) {
                        $perform_search = 1;
                    }
                    else {
                        $perform_show_packages = 1;
                    }
                }
            }
            elsif ($widget == $search_menu) {
                if (_searchmenu_callback($search_menu->selectedItem(), \%$options, \@search_types, \$current_search_type)) {
                    if ($find_entry->value()) {
                        $perform_search = 1;
                    }
                    else {
                        $perform_show_packages = 1;
                    }
                }
            }
            elsif ($widget == $tree) {
                $perform_show_packages = 1;
            }
            elsif ($widget == $detail_list){
                $info_options = {};
                my $wEvent = yui::toYWidgetEvent($event);

                if ($wEvent->reason() == $yui::YEvent::ValueChanged) {
                    yui::YUI::app()->busyCursor();
                    _detaillist_changeditem_callback($detail_list, \%$options);
                    yui::YUI::app()->normalCursor();
                    _tree_callback($tree->currentItem(),\%$options);
                }
                _detaillist_callback($detail_list->selectedItem(), $info, \%$options);
            }
            elsif ($widget == $QuitButton) {
                last if _quit();
            }

            if ($perform_search) {
                yui::YUI::app()->busyCursor();
                _do_search($find_entry, $tree, $options, $current_search_type, $urpm, $pkgs);
                yui::YUI::app()->normalCursor();
                _detaillist_callback($detail_list->selectedItem(), $info, \%$options);
                $perform_search = 0;
                $perform_show_packages = 0;
            }
            elsif ($perform_show_packages) {
                _tree_callback($tree->currentItem(),\%$options);
                _detaillist_callback($detail_list->selectedItem(), $info, \%$options);
                $perform_show_packages = 0;
            }
        }

    }

    $my_win->destroy
}


# -=-=-=---=-=-=---=-=-=-- main -=-=-=---=-=-=---=-=-=-


if (my $pid = ManaTools::Shared::isProcessRunning('rpmdragora')) {
    interactive_msg($loc->N("Warning"), $loc->N("rpmdragora is already running (pid: %s)", $pid), yesno => [ $loc->N("&Quit") ]);
    exit(0);
}

if(!warn_about_user_mode()) {
    exit(0);
}

yui::YUI::app()->setApplicationTitle($loc->N("Software Management"));
yui::YUI::app()->setApplicationIcon($wm_icon);

my $MGAPlugin = "mga";

$factory = yui::YUI::widgetFactory;
$mgaFactory = yui::YExternalWidgets::externalWidgetFactory($MGAPlugin);
$mgaFactory = yui::YMGAWidgetFactory::getYMGAWidgetFactory($mgaFactory);
$optFactory = yui::YUI::optionalWidgetFactory;

### MAIN DIALOG ###
$my_win = $factory->createMainDialog;

readconf();

ManaTools::Rpmdragora::rpmnew::do_merge_if_needed();

init();

_run_treeview_dialog(\&perform_installation);

writeconf();

1;
