/**
 * Module:		inst_sw_select.ycp
 *
 * Authors:		Gabriele Strattner <gs@suse.de>
 *			Klaus Kaempf <kkaempf@suse.de>
 *
 * Purpose:
 * Displays software selection screen. Show radioboxes for software
 * main categories. Let the user select the software.
 *
 * Packages module read:
 *
 * Packages module write:
 */

{
    textdomain "packager";

    import "Arch";
    import "Mode";
    import "Installation";
    import "Product";
    import "ProductFeatures";
    import "Packages";
    import "PackagesUI";
    import "SpaceCalculation";
    import "Stage";

    import "Wizard";
    import "Popup";

    include "partitioning/partition_defines.ycp";


    // ------------------------------------------------------------------------

    // get all available base selections
    // checked in help below !
    list<string> available_base_selections = Pkg::GetSelections( `available, "base" );
    y2milestone ("available_base_selections %1", available_base_selections);

    if (size (available_base_selections) == 0)
    {
	y2error( "No base selections available" );
    }

    // if there is only a single base selection, setting up a radio-button dialog
    // box for a single base selection is useless. Go to the single package selection
    // directly in this case.

    if (size (available_base_selections) == 1)
    {
	y2milestone ( "Only one base selections available, going directly to single package selection" );

	any ret = `again;
	while ( ret == `again )
	{
	    ret = WFM::CallFunction( "inst_packages", [] );

	    if ( ret == `accept )
		ret = `next;
	}
	return ret;
    }

    // we have multiple base selections, let the user choose

    Wizard::OpenAcceptDialog();

    // Dialog title for software selection
    string title = _("Software Selection");

    // Help text Software Selection dialog
    // Explain selectable system configurations but beware:
    // some of the text in <b>'s, e.g. Default comes from the index file,
    // translations must be consistent with po/index/index.??.po
    string helptext = _("<p>
The &product; <b>Default</b> system is a good software
selection for most users.
</p>
");

    // only add this part to help text if an office.sel file is available
    if ( contains( available_base_selections, "Office" ) )
    {
	// help text, continued
	helptext = helptext + _("<p>It includes powerful graphical office applications.
</p>");
    }

    // help text, continued
    helptext = helptext + _("<p>
   You will not need to insert all of the CDs that
come with &product; for this selection. Additional software from the
other CDs can always be installed later.
</p>
");

    // help text, continued
    helptext = helptext + _("<p>
The <b>Minimal</b> system includes just the bare essentials needed
to safely run &product;. This selection <b><i>does not include
graphical desktop environments</i></b> -- no X11, no KDE, no GNOME.
Select this option as a base for your own custom selection, for
dedicated server systems that do not need a graphical desktop, or for
systems that are short on disk space or memory.
</p>
");

   // help text, continued
    helptext = helptext + _("<p>
With the <b>Minimum graphical system</b>, install the &product;
base system and all packages required for X11, the graphical user
interface (GUI).
You can then work with a simple graphical desktop. </p>
");

//    if (Product::name == "Novell Linux Desktop")
    if (ProductFeatures::software_proposal == "desktop")
	helptext = Packages::desktop_help_text;

    // help text, continued
    helptext = helptext + _("<p>
To make a more precise selection of software to install, select
<b>Detailed selection</b>.
</p>
");

    // dont ask user for software selection if imap server, product
    if ( ProductFeatures::base_selection_choice == `fixed )
    {
	Wizard::SetContents(title,
			    `HVCenter(`Label(
				     // Intermediate contents of the software selection screen
				     _("This product has a fixed software selection that cannot be changed."))),
			    helptext, (boolean)WFM::Args(0), (boolean)WFM::Args(1));
        any ret = Wizard::UserInput();
	Wizard::CloseDialog();
	y2milestone("product cd return %1",ret);
	return ret;
    }
    else
    {
	Wizard::SetContents(title,
			    // Intermediate contents of the software selection screen
			    `HVCenter(`Label(_("Reading package database..."))),
			    helptext, (boolean)WFM::Args(0), (boolean)WFM::Args(1));
    }

    if ( Stage::initial () )
	Wizard::SetTitleIcon( "software" );



    // ------------------------------------------------------------------------

    //
    // save state solver and dependencies in case of `cancel
    //
    list restore_selections = Pkg::GetSelections( `selected, "base" );
    restore_selections = union ( restore_selections, Pkg::GetSelections( `selected, "" ) );
    y2milestone ("restore_selections %1", restore_selections);

    // save the current selection
    boolean retval = Pkg::SaveState();
    y2milestone( "Save selection: %1, return: %2", restore_selections, retval );

    // get the currently selected base selection
    list current_base_selections = Pkg::GetSelections( `selected, "base" );
    y2milestone ("current_base_selections %1", current_base_selections);

    // save the current base selection
    string save_selection = current_base_selections[0]:"default";

    // Construct a box with radiobuttons for each software base configuration
    term baseconfs_box = `VBox();

    // sort available_base_selections by order
    // $[ "order" : [ "name", "summary" ], .... ]

    map<string, list<string> > sorted_base_selections = $[];
    foreach( string selection, available_base_selections,
    ``{
	map selection_data = Pkg::SelectionData (selection);
	if (selection_data != nil)
	{
	    string order = selection_data["order"]:"";
	    // use selection name as sort criteria if not given
	    if (order == "")
		order = selection;
	    sorted_base_selections[order] = [selection, selection_data["summary"]:("'"+selection+"'")];
	}
    });

    // construct display box in order
    foreach(string order, list<string> data, sorted_base_selections,
    ``{
	{
	    baseconfs_box = add( baseconfs_box, `Left(`RadioButton(`id(data[0]:""),		// id
						       `opt(`notify, `autoShortcut),
						       data[1]:"",				// descrption
						       contains( current_base_selections, data[0]:""))));
	}
    });

    string wrn_msg = "";


    // Checking: already selected addons or single selection?
    if (Pkg::RestoreState(true) && Packages::base_selection_modified)		// only check state diffs
    {
	// Display warning message
	wrn_msg = _("\
You have already chosen software from \"Detailed selection\".\n\
You will lose that selection if you change the basic selection.");
    }


    term contents = `HVSquash(
			      `VBox(
				    `HSquash(
					     `VBox(
						   `Frame(
							  // Frame caption for software selection
							  _("Software"),
							  `VBox(
								`VSpacing(0.3),
								`RadioButtonGroup(`id(`baseconf),`opt(`notify), baseconfs_box),
								`VSpacing(0.3)
								)
							  ),
						   `VSpacing(),

						   // Push button that will pop up the detailed
						   // software selection (e.g. Multimedia, Games,
						   // KDE, Gnome, ... - not the individual packages!)
						   `PushButton( `id(`details),  _("&Detailed selection...") )
						   )
					     ),
				    `VSpacing(0.7),
				    `Label( `id(`wrn_label), wrn_msg )
				    )
			      );

    Wizard::SetContents(title, contents, helptext, (boolean)WFM::Args(0), (boolean)WFM::Args(1));

    any ret = nil;
    boolean error_found = false;

    repeat
    {
	ret = Wizard::UserInput();

	// get the newly selected base configuration
	string base_selection = (string) UI::QueryWidget( `id(`baseconf),`CurrentButton );
	if ( base_selection == nil )
	    base_selection = "";

	if (ret == `abort && Popup::ConfirmAbort (`painless))
	{
	    Pkg::RestoreState(false);
	    Wizard::CloseDialog();
	    return `abort;
	}

	// if the selection has changed and the user has already selected some addons or single packages
	if ( (save_selection != base_selection)
	     && Pkg::RestoreState(true) && Packages::base_selection_modified )
	{
            // popup text: ask the user whether to reset his individuell selection
	    boolean ret = Popup::YesNo(_("Do you really want\nto reset your detailed selection?"));
	    if ( !ret )
	    {
		Pkg::ClearSaveState();		// free the previously saved state
		Wizard::CloseDialog();
		// rebuild the former selected RadioButton
		return `again;
	    }
	    else
	    {
		Packages::base_selection_modified = false;
	    }
	}

	// Inform the package manager on `next about the new (only about a NEW) selection
	// or if the selection has changed
	if (save_selection != base_selection)
	{
	    // set the new selection
	    boolean ret = Pkg::SetSelection( base_selection );

	    y2milestone ( "Selecting '%1' returns: %2", base_selection, ret );
	    y2milestone ( "All selected addon selections: %1", Pkg::GetSelections(`selected, "") );


            list<string> other_selections = Packages::ComputeSystemSelectionList();
            foreach(string sel, other_selections, ``{
                    if (!Pkg::SetSelection(sel))
                        y2error("Error setting selection: %1", sel);
                    });

	    ret = Pkg::ActivateSelections();
	    y2milestone ("Pkg::ActivateSelections() returns %1", ret);

	    save_selection = base_selection;				// this is the new one

	    // add additional (internal) packages, like kernel etc.
	    Pkg::DoProvide (Packages::ComputeSystemPackageList());
	    Pkg::PkgSolve(false);

	    string msg = "";

	    // FIXME: get notify description
            // msg = Pkg::GetNotify( base_selection );

	    if ( msg != "" )
	    {
		term msg_text = `RichText( "<p>" + base_selection + "</p>" + "<p>" + msg + "</p>" );
		PackagesUI::DisplayHelpMsg( "", // headline
					    msg_text, `none, 10 );
	    }

	    // reset the warning: you have already choosen ...
	    wrn_msg	= "";
	    UI::ChangeWidget(`id(`wrn_label), `Value, wrn_msg );

	}

	// call the package selection dialog

	if ( ret == `details )
	{
	    ret = `again;

	    // add additional (internal) packages, like kernel etc.
	    Pkg::DoProvide (Packages::ComputeSystemPackageList());
	    Pkg::PkgSolve(false);

	    while ( ret == `again )
	    {
		ret = WFM::CallFunction( "inst_packages", [] );

		if ( ret == `accept )
		{
		    Packages::base_selection_modified = true;
		    ret = `next;
		}
	    }

	    error_found = SpaceCalculation::ShowPartitionWarning();

	    if ( error_found )
	    {
		y2error( "Not enough disk space" );
		ret = `again;
	    }

	    if ( Pkg::RestoreState(true) )		// just checking
	    {
		// Display warning message
		wrn_msg = _("\
You have already chosen software from \"Detailed selection\".\n\
You will lose that selection if you change the basic selection.");
		UI::ChangeWidget(`id(`wrn_label), `Value, wrn_msg );
		UI::RecalcLayout();
	    }
	}
	else
	{
	    // FIXME: fix the module SpaceCalculation
	    // calculate required diskspace
	    error_found = SpaceCalculation::ShowPartitionWarning();
	    if ( error_found )
	    {
		y2error( "Not enough disk space" );
	    }
	}
    } until ( (ret == `next && !error_found) || ret == `cancel ||  ret == `back );

    if ( ret == `back || ret == `cancel )
    {
	boolean ret = Pkg::RestoreState( false );
	y2milestone( "RESET to software selection: %1, return: %2",  restore_selections, ret );
    }
    else if ( ret == `next )
    {
	Pkg::ClearSaveState();
	list selected_selections = Pkg::GetSelections( `selected, "base" );
	selected_selections = union ( selected_selections, Pkg::GetSelections( `selected, "") );
	y2milestone( "INSTALLING software selection: %1", selected_selections );
    }
    else
    {
	Pkg::ClearSaveState();
    }

    Wizard::CloseDialog();

    return ret;
}
