/**
 * File:	OSRRepairUI.ycp
 * Module:	repair
 * Summary:     UI functions
 * Authors:	Johannes Buchhold <jbuch@suse.de>
 *
 * $Id: OSRRepairUI.ycp 20738 2005-01-12 17:47:48Z jsuchome $
 */
{
  module "OSRRepairUI";

  import "Arch";
  import "Hotplug";
  import "Label";
  import "Linuxrc";
  import "Mode";
  import "ModuleLoading";
  import "Popup";
  import "Progress";
  import "Report";
  import "Sequencer";
  import "Stage";
  import "StorageDevices";
  import "StorageControllers";
  import "Wizard";

  import "OSR";
  import "OSRCommon";
  import "OSRPopup";
  import "OSRMode";
  import "OSRSummary";
  import "OSRDirect";
  import "OSRExecute";
  import "OSRProgress";
  import "OSRStatus";


  textdomain "repair";

  /**
   * detected is true if the scan and requires sequencer is finished and
   * the user is in the last dialog ( EndDialog). Allows to go back to the
   * scan protocol.
   */
  boolean detected		= false;

  string exit_label		= Label::FinishButton();

  /**
   * Captions ...
   */
  string init_dialog_caption		=  "";
  string start_dialog_caption		=  "";
  string customize_dialog_caption	=  "";
  string scan_dialog_caption		=  "";
  string tool_dialog_caption		=  "";

  boolean initialized			= false;

  /**
   * Constructor
   */
  global define void OSRRepairUI()``{

      // dialog caption
      init_dialog_caption	= OSRCommon::tool_name + _(" -- Initialize");
      // dialog caption
      start_dialog_caption	= OSRCommon::tool_name + _(" -- Start Dialog");
      // dialog caption
      customize_dialog_caption	= OSRCommon::tool_name + _(" -- Customize");
      // dialog caption
      tool_dialog_caption	= OSRCommon::tool_name+_(" -- Tool Box Dialog");
      // dialog caption
      scan_dialog_caption	= _("YaST System Check");
  }

  /**
   * Reset api modules for the next scan and repair sequence.
   */
  global define void Reset()``{
      OSRSummary::Reset();
      OSRProgress::Reset();
      OSRExecute::Reset();
      OSRStatus::Reset();
      OSR::ResetDetect();
      OSRDirect::Reset();
  }

  /**
   * Init Dialog
   */
  global define symbol InitDialog() ``{

    if ( initialized )
	return `next;

    if ( Stage::initial () )
    {
	Wizard::RestoreAbortButton();
    }

    // Set help text
    if (!OSRMode::script) Wizard::RestoreHelp ( "" );

    // A callback function for abort
    block<boolean> abort = ``{
	return UI::PollInput () == `abort;
    };

    integer no_of_steps = 6;

    // We do not set help text here, because it was set outside
    if(!OSRMode::script)
	Progress::New ( init_dialog_caption, " ", no_of_steps,
			// progress label
		       [ _("Load rescue modules"),
			// progress label
			 _("Probe floppy disk devices"),
			// progress label
			 _("Probe hard disk controllers"),
			// progress label
			 _("Load kernel modules for hard disk controllers"),
			// progress label
			 _("Probe hard disks"),
			 // progress label
			 _("Probe USB")
			 ],
			// progress label
		       [ _("Loading rescue modules..."),
			// progress label
			 _("Probing floppy disk devices..."),
			// progress label
			 _("Probing hard disk controllers..."),
			// progress label
			_("Loading kernel modules for hard disk controllers..."),
			// progress label
			 _("Probing hard disks..."),
			// progress label
			 _("Probing USB..."),
			 // progress label
			 _("Finished") ],
			    ""
	);

    if (OSR::Init())
    {
	if (!OSRMode::script)
	{
	    Progress::NextStage ();
	    if ( eval (abort) ) return `abort;
	}
    }
    else
    {
	return `error;
    }

    // increase the progress to "finish"
    if( ! OSRMode::script ) Progress::NextStage ();

    // Start the client "inst_startup.ycp" if the rescue-system is launched
    // from a running Linux-system, else the module inst_startup.ycp
    // was already launched.
    if (! Mode::test ())
    {
	if (!(Arch::s390 () || Arch::board_iseries ()))
	{
	    // give user feedback what's happening
	    StorageDevices::FloppyReady ();
	    if (! OSRMode::script )
	    {
		Progress::NextStage();
		if ( eval (abort) ) return `abort;
	    }
	}
	// --------------------------------------------------------------
	//			     Hard disk controllers
	// 1. Probe
	// 2. Initialize (module loading)
	// --------------------------------------------------------------
	if (StorageControllers::Probe() <= 0)
	{
	    // error popup
	    Popup::Error(_("No hard disks were found.
Check your hardware.
"));

//		return `abort;
	}
	else
	{
	    if (! OSRMode::script )
	    {
	        Progress::NextStage();
	        if ( eval (abort) ) return `abort;
	    }
	}

	StorageControllers::Initialize();
	ModuleLoading::Load ("dm-mod", "", "Linux", "DM", Linuxrc::manual (), true);

	if (!OSRMode::script)
	{
	    Progress::NextStage();
	    if ( eval (abort) ) return `abort;
	}

	// --------------------------------------------------------------
	//				  Hard disks
	// --------------------------------------------------------------

	map targetMap = StorageDevices::Probe (true);
	if (size (targetMap) == 0)
	{
	    // error popue
	    Popup::Error(_("No hard disks were found.
Check your hardware.
"));
	    return `abort;
	}
	else
	{
	    if (! OSRMode::script )
	    {
	        Progress::NextStage();
	        if ( eval (abort) ) return `abort;
	    }
	}

	if (!(Arch::s390 () || Arch::board_iseries ()))
	{
	    Hotplug::StartUSB ();
	    if (! OSRMode::script )
	    {
	        Progress::NextStage();
	        if ( eval (abort) ) return `abort;
	    }
	}
    }

    //Probe cdroms and floppy
    if (!Mode::test () )
    {
	StorageDevices::FullProbe();
    }

    if (!OSRMode::script)
    {
	Wizard::EnableNextButton();
	Wizard::EnableAbortButton();
	Wizard::EnableBackButton();
	Wizard::SetFocusToNextButton();
    }
    initialized = true;
    return `next;
  }


  /**
   * Build (return) a description text for a label in the help_text field.
   * @param label the label
   * @param description the description text for the label.
   * @return the formatted label help text
   */
  define string build_label_description(string label, string description )``{
      return OSRPopup::build_label_description (label, description);
  }

  /**
   * Build a selection box with all scan and repair groups.
   * @param mode if all entries should be checked ('Select all')
   */
  define term build_multi_selection_box (boolean mode )``{

    return `MultiSelectionBox(`id(`options),
	// MultiSelectionBox label
	_("S&elect Scan and Repair Options:"), OSR::GroupItems(mode));
  }

  /**
   * Set the wizard button.
   */
  define void set_buttons_enable (boolean pause, boolean back, boolean next) ``{

      UI::ChangeWidget(`id(`pause),`Enabled, pause);

      if ( back )	Wizard::EnableBackButton();
      else		Wizard::DisableBackButton();

      if ( next )	Wizard::EnableNextButton();
      else		Wizard::DisableNextButton();
  }

 /**
  * The start dialog let the user select how the system should be analysed.
  * @return symbol for sequencer
  */
  define symbol StartDialog() ``{

    detected = false;

    // summary help text 1/3 (%1 is tool name - YaST System Repair)
    string help_text    = sformat(_("<p><I>%1</I>
can repair some parts of a damaged system. Therefore, the
tool scans the system and reports the errors found.</p>
"), OSRCommon::tool_name) +

    // summary help text 2/3
_("<p>After an error was found, YaST suggests one or
more repair methods or lets the user cancel the repair
process.</p>
") +

    // summary help text 3/3
    _("<p>Nothing will be repaired automatically.
Only if the user accepts the repair proposal will
the system be changed.</P>
");

    list<map> start_dialog_entries = [
	$[
	    // First entry - automatic analysis (headline)
	    "headline"		: _("&Automatic Repair"),
	    "symbol"		: `scan_repair,
	    // First entry - automatic analysis (description)
	    "description"	: _("Automatic analysis with repair
proposals. Fits in most cases.
"),
	    // First entry - automatic analysis (additional help text)
	    "help_text"		: _("Analyze the entire system automatically and
display repair proposals.")
	],
	$[
	    // Second entry - customise analyse (headline)
	    "headline"		: _("&Customized Repair"),
	    "symbol"		: `scan_repair_options,
	    // Second entry - customise analyse (description)
	    "description"	: _("Select parts of system analyzation
you need. Usable if you  already
know a little bit about your problem.
"),
	    // Second entry - customise analyse (additional help text)
	    "help_text"		: _("For example, deselect a category group, like
the boot loader test, then start analysis."),

	],
	$[
	    // Third entry - direct repair tools (headline)
	    "headline"		:  _("E&xpert Tools"),
	    "symbol"		: `direct_repair,
	    // Third entry - direct repair tools (description)
	    "description"	: _("Use if the automatic detection
fails or you know the exact type of
your problem.
"),
	    // Third entry - direct repair tools (additional help text)
	    "help_text"		: _("For example, directly recover lost
partition table or verify the package database.")
	]
    ];
    // FIXME "help_text" entries are not used...

    term left_box  = `VBox(`VSpacing(2));
    term right_box = `VBox(`VSpacing(2));
    foreach (map option, start_dialog_entries, ``{
	left_box  = add (left_box,
	    `VWeight(10, `Left(`Label(option["description"]:""))));
        right_box = add (right_box,
	    `VWeight(10, `Left(`PushButton(`id(option["symbol"]:`nothing), `opt(`hstretch) , option["headline"]:"" ))));
    });

    left_box  = add( left_box,  `VSpacing(2));
    right_box = add( right_box, `VSpacing(2));

    term contents = `HBox (
      `HWeight (60, `HBox(`HSpacing(4), left_box)),
      `HWeight (40, `HBox(`Left(right_box), `HSpacing(4)))
    );

    Wizard::SetContentsButtons (start_dialog_caption,contents,help_text,
	Label::BackButton(), exit_label );

    UI::SetFocus(`id(`scan_repair));

    if (!Stage::initial ())
    {
        Wizard::DisableBackButton();
    }
    else
    {
	Wizard::RestoreAbortButton();
    }

    symbol ret = (symbol) UI::UserInput();

    // set the default scan sequence selection
    if( ( ret == `scan_repair ) ||
        ( ret == `scan_repair_options && OSR::SizeDetectGroupList() == 0 ||
          OSR::DetectGroupList() == nil ))
    {
        OSR::SelectDefaultDetectGroups();
    }

    if ( ret == `back && Stage::initial () )
    {
        Wizard::RestoreNextButton();
    }
    return ret;
  }

  /**
   * Dialog which let the user select or deselect
   * some scan and repair groups.
   */
  define symbol ScanOptionsDialog()``{

    detected = false;

    // button label
    string select_all_label	= _("&Select all");
    // button label
    string unselect_all_label	= _("&Deselect all");

    // help text for "custom scan" dialog 1/3 (%1 is tool name)
    string help_text    = sformat(_("<P><I>%1</I> scans a
lot of system parts automatically. Usually, only one
or two scopes, like the boot loader or the file system,
are damaged.</P>
"), OSRCommon::tool_name) +

    // help text for "custom scan" dialog 2/3
    _("<P>Therefore, this dialog enables the selection
of system parts that should be scanned.</P>
") +

    // help text for "custom scan" dialog 2/3
    _("Some of the groups shown at the right side of
the dialog need other groups. YaST resolves these dependencies
for you.
") +
    build_label_description (select_all_label,
	// help text for '&Select all' button
	_("Select all entries in the list.")) +
    build_label_description (unselect_all_label,
	// help text for '&Deselect all' button
	_("Deselect all entries in the list."));

    term contents  = `HBox (
	`HSpacing(2),
	`VBox (
	    `VSpacing(1),
	    `ReplacePoint (`id(`rp), build_multi_selection_box(true)),
	    `VSpacing(0.5),
	    `HBox (
		`Left (`HBox (
		    `PushButton (`id(`all_options), select_all_label),
		    `PushButton (`id(`no_optins), unselect_all_label)
		)),
		`Right (`PushButton (`id(`help), Label::HelpButton()))
	    ),
	    `VSpacing(1)
	),
	`HSpacing(2)
    );

    Wizard::SetContentsButtons (customize_dialog_caption,contents,help_text,
	Label::BackButton(), Label::NextButton());

    // Select first Item
    UI::SetFocus(`id(`options));

    symbol ret = `next;

    repeat
    {
	ret = (symbol) UI::UserInput();

	OSR::SetDetectGroupList (
	    (list<string>) UI::QueryWidget(`id(`options), `SelectedItems));

	// user pressed the "select all" or the unselect all button
	if (ret == `all_options || ret == `no_optins)
	{
	    OSR::ResetDetectGroupList();
	    boolean mode = ( ret == `all_options );
	    UI::ReplaceWidget(`id(`rp), build_multi_selection_box (mode));
	    UI::SetFocus(`id(`options));
	}
	// user press the help button
	else if (ret == `help)
	{
	    string selected = (string)
		UI::QueryWidget(`id(`options), `CurrentItem );
	    map item_info   = OSRCommon::GetGroupMap (selected);

	    Popup::LongText (item_info["text"]:"",
		`RichText(item_info["help"]:""), 60, 15);
	    UI::SetFocus(`id(`options));
	}
	else if (ret == `next || ret == `abort || ret == `cancel)
	{
	    // not item seleted
	    if (ret == `next && OSR::SizeDetectGroupList() == 0)
	    {
		// error label (user should select the action to do)
		Popup::Message (_("Select at least one item."));
		ret = `again;
		continue;
	    }
	    if ( ret == `next )
	    {
		list<string> greq = OSR::CheckGroupRequires();

		if (size(greq) != 0)
		{
		    UI::OpenDialog (`opt(`decorated), `HBox(
			`HSpacing (0.5), `Label(
			// popup label: wait while dependencies are being solved
			_("YaST is solving the dependencies
between the selected groups...
")),
			`HSpacing(0.5)));
		    sleep (1000);
		    UI::CloseDialog();
		    UI::ChangeWidget(`id(`options), `SelectedItems,
			union (OSR::DetectGroupList(), greq));
		    ret = `again;
		}
	    }
	}
    } until ( ret == `next || ret == `abort  || ret == `back || ret == `cancel);

    return ret;
  }

  /**
   * Repair tool dialog
   */
  define symbol RepairToolsDialog()``{

    // help text for "expert tools" dialog 1/2 (%1 is tool name)
    string help_text     = sformat(_("<P><I>%1</I> allows the
direct repair of damaged system areas with the
tools shown at the right side of the dialog.</P> 
"), OSRCommon::tool_name ) +

    // help text for "expert tools" dialog 2/2
    _("<P>Each tool has a special functionality.
Read the description of the different options
and select one. If no entry matches your problem,
go back and start the automatic analysis.</P>
");

    term contents = OSRDirect::OptionMenu();

    Wizard::SetContentsButtons(tool_dialog_caption, contents, help_text,
	Label::BackButton(), Label::NextButton() );

    any ret = `next;
    repeat
    {
	ret = UI::UserInput();

	if (is(ret, string))
	{
	    symbol rret = OSRDirect::EvalDirectMethod ((string)ret);

	    // get a abort return from custom_part or a other tool
	    if ( rret == `abort ) return `really_abort;
	}
    } until ( ret == `next || ret == `abort  || ret == `back || ret == `cancel);

    return (symbol) ret;
  }

  /**
   * Init a new automatically analyse sequence.
   */
  define void DetectDialogInit() ``{

    if ( OSRMode::script )
    {
	return;
    }

    // progress bar label
    string module_check_label	= _("Module Check");
    // progress bar label
    string system_check_label	= _("System Check");
    // button label
    string show_all_label	= _("&Show All Details");
    // button label
    string pause_label		= _("&Pause");

    if ( UI::WidgetExists (`id(`local_rich_text_info ))) return;

    if ( !detected ) Reset();

    // Build window contents
    term module_progress_bar	=
	OSRProgress::Create (`module_progress_bar, module_check_label,10,true);
    term global_progress_bar    =
	OSRProgress::Create (`global_progress_bar, system_check_label,10,false);

    term buttons_right          = `Empty();
    term rich_text              = OSRSummary::Create (`local_rich_text_info,"");
    term contents               = `VBox(
	`VSpacing(0.3),
	`HBox (
	    rich_text,
	    buttons_right
	),
	module_progress_bar,
	global_progress_bar,
	`VSpacing(0.3),
	`HBox (
	    `Left (`PushButton(`id(`pause), pause_label)),
	    `Right (`CheckBox(`id(`details), `opt(`notify), show_all_label,
		OSRSummary::show_details))
	),
	`VSpacing(0.5)
    );

    // Help text for automatic check/repair process 1/4 (%1 is tool name)
    string help_text = sformat(_("<p><I>%1</I> is now checking your Linux system.</p>
"), OSRCommon::tool_name) +

    // Help text for automatic check/repair process 2/4
    _("<p>Depending on the CPU and the amount of memory, this can
take some time.</p>
") +

    // Help text for automatic check/repair process 3/4
    _("<p>Above all, the file system checks with fsck are very
time consuming.</p>
") +

    // Help text for automatic check/repair process 4/4 (%1 is tool name)
    sformat (_("<P>If the scan sequence finds an error, <i>%1</i>
suggests one or more repair proposals. 
Then select one proposal or cancel the repair. </P>
"), OSRCommon::tool_name) +

    build_label_description (pause_label,
	// help text for '&Pause' button
	_("Pause or continue analyzing the system.")) +

    build_label_description (show_all_label,
	// help text for '&Show All Details' button
	_("Activate or disable reporting details."));

    Wizard::SetContentsButtons (scan_dialog_caption, contents, help_text,
	Label::BackButton(), Label::OKButton());

    set_buttons_enable (false, true ,true);
  };

  /**
   *  AbortDialog
   **/
  define symbol AbortDialog() ``{

    // popup label, %1 is "YaST System Repair" (translated)
    if (Popup::YesNo(sformat(_("Really abort %1?
"),OSRCommon::tool_name )))
	return `yes;
    return `back;
  }

  /**
   * Controll the user interaction for the scan and repair sequence.
   */
  define symbol DetectDialog() ``{

    // button label
    string go_on_label = _("&Go On");

    if (OSRMode::script)
	return OSR::Detect();

    DetectDialogInit ();
    OSRSummary::Init ();

    symbol input = `pause;

    // if the detected is true the user can only view the
    // protocol. No scan and repair sequence starts.
    if ( detected )
    {
        set_buttons_enable (false, true, true );
        UI::ChangeWidget(`id( `module_progress_bar), `Enabled, false );
        UI::ChangeWidget(`id( `global_progress_bar), `Enabled, false ); 
        OSRSummary::Update();
        OSRProgress::Update();
    }

    repeat
    {
	// only view mode
	if (detected)
	{
	    input			= (symbol) UI::UserInput();
	    OSRSummary::show_details	= (boolean)
		UI::QueryWidget(`id(`details), `Value);

	    OSRSummary::Update();

	    if ( input == `abort || input == `cancel )
	    {
		if ( AbortDialog() != `yes )
		{
		    input = `again;
		}
		else
		{
		    return input;
		}
	    }
	}
	// scan and repair sequence
	else if ( input != `error )
	{
	    // after view mode after a scan and repair sequence
	    // user must press the next or back button to leave
	    // the dialog
	    if ( input == `detectok )
	    {

		  OSRSummary::Update();
		  set_buttons_enable (false, true,true);
		  input = (symbol) UI::UserInput();
	    }

	    if ( input == `abort || input == `cancel )
	    {
		if ( AbortDialog() != `yes )
		{
		    input = `pause;
		}
		else
		{
		    OSR::ResetDetectionModules();
		    return input;
		}
	    }

	    // switch between detail and overview protocol mode
	    if ( input == `details )
	    {
		OSRSummary::show_details = (boolean)
		    UI::QueryWidget(`id(`details), `Value );
		OSRSummary::Update();
		input = `pause;
	    }

	    // user press the pause button
	    // or fist start of the scan and repair sequence
	    if ( input == `pause )
	    {
		set_buttons_enable( true, false, false );
		UI::ChangeWidget(`id(`pause), `Label, _("&Pause"));

		input = OSR::Detect();

		if (input == `abort || input == `cancel)
		{
		    if ( AbortDialog() != `yes )
		    {
		        input = `pause;
		        continue;
		    }
		    else
		    {
		        OSR::ResetDetectionModules();
		        return `abort;
		    }
		}
		if ( input == `pause )
		{
		    set_buttons_enable( true,true, true );
		    UI::ChangeWidget(`id(`pause), `Label,  go_on_label );

		    // wait in pause mode and let the user change the protocol
		    // mode or abort
		    // the scan and repair sequence.
		    repeat
		    {
			input = (symbol) UI::UserInput();
			if ( input == `details )
			{
			    OSRSummary::show_details = (boolean)
				UI::QueryWidget(`id(`details), `Value );
			    OSRSummary::Update();
			}
			if(  input == `abort || input == `cancel )
			{
			    if ( AbortDialog() != `yes )
			    {
			        continue;
			    }
			    else
			    {
			        OSR::ResetDetectionModules();
			        return `abort;
			    }
			}
		    } until (input== `pause || input== `back || input == `next);
		}
	      }
	  }
    } until (input == `next || input == `back || input == `abort ||
	     input == `cancel || input == `error);

    // reset the scan and repair sequence
    // e.g. unount mounted partitions.
    if( ! detected ) OSR::ResetDetectionModules();

    // reset the hole api
    if ( input == `back ) Reset();
    if ( input == `next ) detected = true;

    return input;
  }


  /**
   *  FinishDialog
   **/
  define symbol FinishDialog() ``{

    // popup label, %1 is "YaST System Repair" (translated)
    if( Popup::YesNo(sformat(_("Really finish %1?
"),OSRCommon::tool_name )) )
	return `yes;

    return `back;
  }


/**
 * Main dialog.
 * Manage the sequence of the different dialogs.
 */
global define symbol OsrMainDialog() ``{

    map aliases = $[
		    "abort"		: ``(AbortDialog() ),
	            "start"		: ``(StartDialog() ),
		    "scan_options"	: ``(ScanOptionsDialog()),
		    "direct_repair"	: ``(RepairToolsDialog()),
		    "detect"		: ``(DetectDialog()),
		    "finish"		: ``(FinishDialog() ),
    ];

    map sequence = $[
        "ws_start" : "start",
	"start"	: $[
		    `abort		: "abort",
		    `scan_repair	: "detect",
		    `scan_repair_options: "scan_options",
		    `direct_repair	: "direct_repair",
		    `error		: `error,
		    `cancel		: "abort",
		    `back		: "abort",
		    `next		: "finish"
	],
	"scan_options" : $[
		    `abort		: "abort",
		    `next		: "detect",
		    `error		: `error,
		    `cancel		: "abort"
	],
	"direct_repair" : $[
		    `abort		: "abort",
		    `really_abort	: `abort,
		    `next		: "start",
		    `error		: `error,
		    `cancel		: "abort"
	],
	"detect" : $[
		    `abort		: `abort,
		    `error		: `error,
		    `next		: "start",
		    `cancel		: `cancel
        ],
	"abort" : $[
		    `yes		: `abort
        ],
	// TODO: does it work in Mode::init?
	"finish": $[
		    `yes		: `finish
	],
    ];

    return Sequencer::Run (aliases, sequence);
}

}//EOF
