/**
 *  File:
 *    OSR.ycp
 *
 *  Module:
 *
 *
 *  Summary:
 *	Control of the automatic scan and repair sequence.
 *
 *  Author:
 *    Johannes Buchhold <jbuch@suse.de>
 *
 * $Id: OSR.ycp 20450 2004-12-01 11:55:31Z jsuchome $
 */
{
  module "OSR";

  import "Linuxrc";
  import "Mode";
  import "Stage";
  import "Report";

  import "OSRCommon";
  import "OSRMode";
  import "OSRProgress";
  import "OSRSummary";
  import "OSRStatus";
  import "OSRLogFile";
  import "OSRDirect";

  textdomain "repair";

  // function prototypes (needed by includes)
  global define void SetReboot();

  // we have to include this files, because using them as clients is not
  // possible (because of passing function references)
  include "repair/osr_module_init.ycp";
  include "repair/osr_module_partition.ycp";
  include "repair/osr_module_packages.ycp";
  include "repair/osr_module_bootloader.ycp";
  // ----------------------------

  /**
   * Only for define ComputesDetectMethodSequence ! not global.
   */
  list<string> global_provides_list		= [];

  /**
   * Only for define Detect. Contains the current module index.
   * osrmodule_init       -> 0
   * osr_module_partition -> 1
   * osr_module_grub      -> 2
   */
  integer index_modules = 0;

  /**
   * Only for define Detect. Contains the current detection method index of a module.
   * OSRPartitionCheckMBR   ->0
   * OSRPartitionCheckDisks -> 1
   * ..
   */
  integer index_detect  = 0;

  /**
   * Static global_provides entries for all detection methods.
   * $["root_mountpoint":"/mnt"]
   */
  map static_provides			= $[];

  /**
   * A map with all lists of detect-methods-entries. The function-names have to be enclosed in
   * double-quoted braces!
   $["osr_module_init":[
                        $["group":"init",
			  "method": ``OSRInitInit(),
			  "progress":10,
			  "provides":["has_floppy"],
			  "requires":[],
			  "summary":"Probing floppy"],
		        $["group":"init",
			  "method": ``OSRInitFloppy(),
			  "progress":10,
			  "provides":["repair_target"],
			  "requires":[],
			  "summary":"Init target system"]],
     "osr_module_partition":[
                        $["group":"mbr_check",
			  "method":``OSRPartitionMBR(),
			  "progress":10,
			  "provides":["valid_target"],
			  "requires":["repair_target"],
			  "summary":"Searching for harddisks"],
			  ]
			  ...   
   */
   map module_detection_methods = $[]; 

   /**
    * Contains all reset method descriptions.
    * Need to reset settings for a scan and repair sequence.
    */
   map module_reset_methods	= $[];

  /**
   * Sequence of all rescue (detect and repair) modules
   *
   * ["osr_module_init", "osr_module_partition"]
   */
   list<string> module_sequence			= [];

  /**
   * Date of all rescue modules
   *
   *  $["osr_module_init": $[
                             "headline":"OSRInit",
                             "name":"osr_module_init",
			     "provides":["has_floppy", "repair_target"],
			     "requires":[]],
       "osr_module_partition":$[
                              "headline":"Partitions and filesystems",
                              "name":"osr_module_partition",
			      "provides":["valid_target",
			      "valid_target_list", "swap_partition_list", "valid_swap_partitions", "swapable_partitions", "fs_module_loaded", .......],
		              "requires":["repair_target", "has_floppy", "valid_target", "valid_target_list", "swap_partition_list", .......]
			]]
	...
   */
   map module_maps			= $[];



  /**
   * Allowed back jump in a scan and repair sequence error appear.
   */
  global string next_detect_method		= "";

  /**
   * Maximal execution of a detect function.
   * (The proper meaning is "do not run max_index_detect_loop-times", so
   * the variable means "maximal execution + 1")
   */
  integer max_index_detect_loop     = 3;

  /**
   * Reset all.
   */
  global define void Reset()``{
      global_provides_list	= [];

      index_detect		= 0;
      index_modules		= 0;

      module_detection_methods		= $[];
      module_sequence			= [];

      module_maps			= $[];

      OSRCommon::Reset ();
  }

  /**
   * Reset detect settings.
   */
  global define void ResetDetect() ``{
      index_detect		= 0;
      index_modules		= 0;

      global_provides_list      = [];

      OSRCommon::SetGlobalProvides (static_provides);

      OSRCommon::current_detect_map	= $[];
      OSRCommon::current_module_name	= "";
  }

  /**
   * set OSRCommon::detect_group_list to []
   */
  global define void ResetDetectGroupList() {
      OSRCommon::detect_group_list = [];
  }

  /**
   * return size of OSRCommon::detect_group_list
   */
  global define integer SizeDetectGroupList () {
      return size (OSRCommon::detect_group_list);
  }

  /**
   * set new value for OSRCommon::detect_group_list
   */
  global define void SetDetectGroupList (list<string> gl) {
      OSRCommon::detect_group_list = gl;
  }

  /**
   * get value of OSRCommon::detect_group_list
   */
  global define list<string> DetectGroupList() {
      return OSRCommon::detect_group_list;
  }

  /**
   * Computes the sequence of the detection methods of a module. 
   */
  define list<map> ComputesDetectMethodSequence(string module_name )``{

      y2milestone("Build method sequence for module %1", module_name );

      list<map> module_detect_methods	=
	module_detection_methods[module_name]:[];
      list<string> method_requires_list	= [];
      integer index			= 0;
      list<map> ret			= [];

      while((index >= 0) && index < size (module_detect_methods )) {

	  map mm =  module_detect_methods[index]:$[];
	  method_requires_list = mm["requires"]:[];

	  if ( OSRCommon::IsSubSet(method_requires_list, global_provides_list ))
	  {
	      // if true add this module as next module in the sequence list, remove it from the
	      // list of modules and decrease the size of the list
	      ret  = add(ret, mm );

	      module_detect_methods = remove(module_detect_methods, index );
	      index                 = 0;

	      // concatenate, sort and remove duplicates of the global_provides_list and the module_provides_list
	      global_provides_list = (list<string>)
		union (global_provides_list, mm["provides"]:[]);
	  }
	  else
	  {
	      index = index + 1;
	  }
      }
//      y2debug ("Detection method sequence for module %1 : %2", module_name , ret);
      return ret;
  }

  /**
   *  This method resolves the requirements and provides of the modules and computes
   *  the correct sequence of detection modules.
   *
   *  @return boolean True if the module sequence was successfully created.
   */
  define boolean ComputeModuleSequence(list<string> module_name_list ) ``{

      integer index				= 0;
      string  module_name			= "";
      list<string>    module_provides_list	= [];
      list<string>    module_requires_list	= [];
      list<string>    global_provides_list      = [];

      while ((index >= 0) && (index < size(module_name_list )))
      {
	  // get the module name and its requirements
	  module_name          = module_name_list[ index]:"";

	  module_requires_list = module_maps [module_name,"requires"]:[];
	  module_provides_list = module_maps [module_name,"provides"]:[];

	  // check if the requirements of the current module are resolved by the global provides
	  if (OSRCommon::IsSubSet (module_requires_list, (list<string>)
	      union (global_provides_list, module_provides_list)))
	  {
	      // if true add this module as next module in the sequence list, remove it from the
	      // list of modules and decrease the size of the list
	      module_sequence  = add(module_sequence, module_name);
	      module_name_list = remove(module_name_list, index);
	      index            = 0;

	      // concatenate, sort and remove duplicates of the global_provides_list and the module_provides_list
	      global_provides_list = (list<string>) union (global_provides_list,
		module_provides_list);
	  }
	  else
	  {
	      index = index + 1;
	  }
      }
      if (size(module_name_list) != 0 )
      {
	  y2error("ComputeModuleSequence: module(s) not added to the sequence list: %1", module_name_list);
	  return false;
      }
      return true;
  };

  /**
   *  This method initializes the YaST OS Repair system. It is started at first and
   *  builds the main window, initializes the global osr_map and a lot of other data.
   *
   *  For internal use only.
   *
   *  @return boolean True if the initialization progress succeeded.
   */
  global define boolean Init() ``{

    // set repair mode (used e.g. from Bootloader)
    Mode::SetMode ("repair");

    list<string> module_function_list	= [
	"osr_module_init",
	"osr_module_partition",
	"osr_module_packages",
	"osr_module_bootloader",
    ];
    map init_functions			= $[
	"osr_module_init"	: OSRInitInit,
	"osr_module_partition"	: OSRPartitionInit,
	"osr_module_packages"	: OSRPackagesInit,
	"osr_module_bootloader" : OSRBootloaderInit
    ];

    list<string> module_name_list	= [];
    integer index			= 0;

    if (( module_function_list == nil) || (size( module_function_list) == 0))
    {
	  y2error("Something's wrong with the
file \"osr_module_list.ycp\".
YaST system repair halts now!");

      // popup text: %1 is "YaST System Repair" (translated)
	  Report::Error(sformat(_("
Error during initialization.
%1 halts now.
"), OSRCommon::tool_name ));
	  return false;
    }


    OSRLogFile::Add (sformat("List of modules:\n%1\n", module_function_list));

    // execute the init-functions of all modules in the module-list
    while ((index >= 0) && (index < size( module_function_list)))
    {
	// result of this evaluation is the module_map of the specific module
	map result_map = $[];
	if (module_function_list [index]:"" != "")
	{
	    // call Init functions from all includes...
	    map () f = init_functions [module_function_list[index]:""]:OSRCommon::EmptyMap;
	    result_map = f ();
	}

	  if ((result_map == nil) || (result_map == $[]))
	  {
	      Report::Error(sformat(
// popup text: %1 is function name, %2 is "YaST System Repair" (translated)
_("An error occurred during execution
of the init functions of module: %1

%2 halts now.
"), module_function_list[index]:"", OSRCommon::tool_name ));

	      y2error("An error occurred during execution of the init-functions
of module: %1. YaST system repair halts now!",
		      module_function_list[index]:"" );

	      return false;
	  }

	  // the name of the current module
	  string module_name = result_map["name"]:"";

	  // add the detect-methods of the current module to the global detect-methods-map
	  module_detection_methods[module_name]=result_map["detect_methods"]:[];
	  module_reset_methods [module_name] =  result_map["reset_methods"]:[];

	  list module_provides = [];
	  list module_requires = [];

	  foreach (map mb, result_map["detect_methods"]:[], {
	      module_provides = union (module_provides, mb["provides"]:[]);
	      module_requires = union (module_requires, mb["requires"]:[]);
	  });

	  result_map["provides"] = module_provides;
	  result_map["requires"] = module_requires;


	  // get the current module-name, put it to the module-list and store it in the global map
	  module_name_list = add(module_name_list, module_name );

	  static_provides  = union (static_provides, result_map["static_provides"]:$[] );


	  OSRCommon::global_entries   = union( OSRCommon::global_entries,  result_map["global_entries"]:$[]);

	  OSRDirect::AddEntries (result_map["direct_methods"]:[],
	    module_function_list[index]:"");

	  // delete the detect_methods from the result_map (it should not appear in the osr_map)
	  result_map = filter (string k, any v, (map<string,any>) result_map, ``(
	    k != "detect_methods" &&
	    k != "static_provides" &&
	    k != "global_entries"  &&
	    k != "direct_methods" )
	  );

	  // add the module_map to the global osr_map
	  module_maps[ module_name ] =  result_map;

	  // increase the index counter
	  index = index + 1;
    }

    // Create the sequence-list of the detection-modules.
    // This is the provides- and requirement-resolver.
    if (! ComputeModuleSequence( module_name_list ))
    {
	y2error("Not all dependencies between the
modules successfully solved. YaST system repair halts now!");

	if (! OSRMode::automatic )
	{
	    // show error message and close the main window
	    Report::Error(sformat(_("
Not all dependencies between the
modules were successfully solved.

%1 halts now."), OSRCommon::tool_name ));
	}
	return false;
    }

    y2milestone("Module sequence : %1", module_sequence );
    return true;
  };


  /**
   * Empty term.
   */
  global define boolean osr_empty() ``{
      y2error("No methods to detect ");
      return false;
  };

  /**
   * Return a list of string with group names executed at the
   * beginning of every Detect sequence.
   */
  define list<string> forall_groups_names()``{

    // Add init groups ("mode" == "forall" )  to OSRCommon::detect_group_list
    return (list<string>) maplist (string m, map vv,
	filter (string k, map v, (map<string,map>)OSRCommon::global_entries, ``(
	    v["mode"]:"" == "forall" )),
	``( m ));
  }

  /**
   * Returns if all detection groups are selected for detection.
   */
  define boolean all_groups_selected() {
      return (SizeDetectGroupList () == (size(OSRCommon::global_entries) - size( forall_groups_names())));
  }


  /**
   * Returns true if the specified requires argument
   * is not provided (not in the map global_provides).
   */
  define boolean requires_not_provided (list<string> requires) {
    return !OSRCommon::IsSubSet (
    requires, maplist (string k, any v, OSRCommon::GlobalProvides () ,``(k)));
  }

  /**
   * Returns true if all specified requires are supported
   * from the selected detection groups.
   */
  define boolean requires_in_detection_group(list<string> requires )``{

    boolean req_not_in_detection_group = false;
    foreach (string module_name, list module_detect_list,
	    (map<string,list>) module_detection_methods,``{

	list<map> required_module_detection_methods = (list<map>)
	    filter (map detect_method, (list<map>) module_detect_list, ``(
		size (union (detect_method["provides"]:[], requires)) <
		size (merge (detect_method["provides"]:[], requires)))
	    );

	list<string> required_groups = (list<string>)
	    maplist (map detect_method, required_module_detection_methods, ``(
		detect_method["group"]:""));

	y2debug("Required module groups %1", required_groups );
	if (!OSRCommon::IsSubSet (required_groups, DetectGroupList ()))
	{
	    req_not_in_detection_group = true;
	}
    });

    y2debug("Requires are not in detection group: %1",
	req_not_in_detection_group );
    return ! req_not_in_detection_group;
  }


  /**
   * Returns true if a detect method is not a member of a slected
   * detection group. Skip detection.
   */
  define boolean skip_detect_method(map method_map )``{

      // Check if only a few groups are selected -- ignore requires ( at the moment )
      if ( !contains (DetectGroupList (), method_map["group"]:""))
      {
	  y2milestone ("Detection method '%1' skipped (not in detection group)",
	    method_map["name"]:"");
	  return true;
      }
      else
      {
	  // If not all entries are selected
	  if (all_groups_selected ()) {
	      // Check if the requires for the next detection method
	      if ( requires_not_provided (method_map["requires"]:[] )  &&
		   requires_in_detection_group (method_map["requires"]:[]))
	      {
		  // next step can not be executed - skip execution
		  OSRLogFile::Add(sformat("Detection method with the summary :%1 could not be executed.
The conditions are not complied.",module_detection_methods["summary"]:""));

		  y2error ("Skip detection method (requires not solved ) %1",
		    method_map["name"]:"");
		  return true;
	      }
	  }
      }
      return false;
  }

  /**
   * Reset the temporary changes.
   * e.g.: Umount temporary mounted partitions ...
   */
  global define boolean ResetDetectionModules()``{

      // count of executed modules
      integer reset_module_index = index_modules;

      // for every module
      while( reset_module_index >= 0 ) {

	  string reset_module_name = module_sequence[reset_module_index]:"";
	  list<map> reset_methods  = module_reset_methods[reset_module_name]:[];
	  integer index_reset	   = 0;

	  while( index_reset <= size( reset_methods )) {
	      map current_reset_map = reset_methods[index_reset]:$[];

	      if( current_reset_map != $[] )
	      {
		  if (haskey (current_reset_map , "method"))
		  {
		    boolean () f = current_reset_map["method"]:OSRCommon::False;
		    if (f())
		    {
			y2milestone("%1 : was successfull",
			    current_reset_map["summary"]:"");
		    }
		    else
		    {
			y2milestone("%1 : was not successfull",
			    current_reset_map["summary"]:"");
		    }
		  }
	      }
	      index_reset = index_reset + 1;
	  }
	  reset_module_index = reset_module_index -1;
      }
      return true;
  }


  /**
   * Go back to a previous detection method.
   * e.g. if a error can not repaired.
   */
  define boolean back2status_detect_method_name()``{

      if( OSRStatus::next_detect_method_name == "")
	  return false;

      integer i_modules = 0;
      integer i_detect  = 0;

      while (i_modules < size(module_sequence))
      {
	  string c_module_name  = module_sequence[ i_modules ]:"";
	  list<map> d_methods	= ComputesDetectMethodSequence(c_module_name );

	  while(( i_detect >= 0) && ( i_detect < size(d_methods)))
	  {
	      map c_detect_map =  d_methods [i_detect]:$[];
	      if (OSRStatus::next_detect_method_name == c_detect_map["name"]:"")
	      {
		  index_modules = i_modules;
		  index_detect  = i_detect;
		  return true;
	      }
	      i_detect = i_detect +1;
	  }
	  i_modules = i_modules +1 ;
      }

      y2error("Next detection method name not found");
      return false;
  }


  /**
   * Count of all detection methods.
   */
  define integer DetectionMethodesCount()``{

    integer number_of_detection_methods = 0;
    if (size( module_sequence ) > 0)
    {
	list<string> detect_list	= DetectGroupList ();
	foreach (string mod, module_sequence, ``{

	    // count the total number of detection methods
	    number_of_detection_methods = number_of_detection_methods + size (
		filter (map v, module_detection_methods[mod]:[], ``(
		    contains (detect_list, v["group"]:"" ))
		));
	});
    }
    else
    {
	y2error("The sequence of the modules is empty.");
    }
    return number_of_detection_methods;
  }


  /**
   *  This is the main detection method. It looks for the module_sequence and
   *  executes all detection methods from the forthcoming modules.
   *
   *  @return boolean True if the detection progress succeeded.
   */
  define symbol detect() ``{

      integer old_detect_size = 0;

      if (!OSRCommon::IsSubSet (forall_groups_names(), DetectGroupList ()))
      {
	  SetDetectGroupList ((list<string>) merge (
	    forall_groups_names(), DetectGroupList ()));
      }
      if ( size( module_sequence ) <= 0 )
      {
	  y2error("List module_sequence is empty: %1. YaST system repair halts now!", module_sequence);
	  return `error;
      }

      // Set the global progressbar steps count
      if ( index_modules == 0 )
	  OSRProgress::SetSteps(`global_progress_bar, DetectionMethodesCount());

      ////////////////////////////////////////////////////////////////////////
      //
      // For every repair module
      //
      ///////////////////////////////////////////////////////////////////////
    while (index_modules < size(module_sequence))
    {
	OSRCommon::current_module_name = module_sequence [ index_modules ]:"";
	OSRCommon::current_direct_name = "";

	y2milestone("The name of the current module is: %1",
	    OSRCommon::current_module_name );

	map module_map= module_maps [ OSRCommon::current_module_name ]:$[];

	// sort the detect method sequence
	list<map> detect_methods = ComputesDetectMethodSequence (
	    OSRCommon::current_module_name);

	if (index_detect == old_detect_size)
	    index_detect = 0;

	old_detect_size = size(detect_methods);

	if (index_detect == 0)
	    OSRProgress::SetSteps (`module_progress_bar, size(detect_methods));

	////////////////////////////////////////////////////////////////////////
	//
	// Execute all detect-functions of the specified module
	//
	//////////////////////////////////////////////////////////////////////
	integer index_detect_loop_counter = 0;
	integer last_index_detect        = index_detect;

	while (( index_detect >= 0) && ( index_detect < size(detect_methods)))
	{
	    // Poll user input
	    if (!OSRMode::script)
	    {
		symbol ret = (symbol) UI::PollInput();
	        if (ret == `pause || ret == `cancel || ret == `abort ||
		    ret == `details )
		    return ret;
	    }

	    OSRCommon::current_detect_map =  detect_methods[index_detect]:$[];
	    y2milestone("The name of the current detect method is: %1",
		OSRCommon::current_detect_map["name"]:"");
	    if (OSRCommon::current_detect_map["name"]:"" == "")
	    {
		y2warning ("detect map: %1", OSRCommon::current_detect_map);
	    }

	    // check call count - no endless loop
	    if (index_detect != last_index_detect )
	    {
		last_index_detect = index_detect;
	    }
	    else
	    {
		index_detect_loop_counter = index_detect_loop_counter +1;
	    }

	    // check skip
	    if (skip_detect_method(OSRCommon::current_detect_map) ||
	        index_detect_loop_counter == max_index_detect_loop )
	    {
	        index_detect = index_detect + 1;
	        if ( index_detect == size( detect_methods ))
		{
	            index_modules = index_modules +1 ;
	            index_detect  = 0;
	            return `restart;
	        }
	        continue;
	    }

	    // Init module progress bar (DownloadProgress widget)
	    OSRSummary::PrepareNewEntry(OSRCommon::current_detect_map );

	    // evaluate the functions and get the result_map
	    // ret is boolean and not used at the moment
	    if (haskey (OSRCommon::current_detect_map, "method"))
	    {
		boolean () f =
		    OSRCommon::current_detect_map["method"]:OSRCommon::False;
		f ();
	    }

	    ///////////////////////////////////////////////////////////////////
	    //
	    // Analyse the status set by one detection method
	    //
	    ///////////////////////////////////////////////////////////////////
	    if ((OSRStatus::IsStatusDetectError() &&
		 OSRStatus::IsErrorSeverityBlocking())  ||
		(OSRStatus::IsStatusRepairError() &&
		 OSRStatus::IsErrorSeverityBlocking())	||
		(OSRStatus::IsStatusRepairOmit() &&
		 OSRStatus::IsErrorSeverityBlocking())	||
		OSRStatus::IsStatusExit()  ||
		OSRStatus::IsCancel())
	    {
		// RepairError & ErrorSeverityBlocking:
		// if a blocking error was detected but the repair method failed
		// halt the rescue system

		// DetectError & ErrorSeverityBlocking:
		// if a blocking error was detected but no repair method started
		// halt the rescue system

		// RepairOmit & ErrorSeverityBlocking:
		// if a blocking error was detected but the user omitted repair
		// halt the rescue system

		// Exit:
		// if a blocking error was detected exit the rescue system,
		// e.g. if no harddisks were detected

		y2milestone("A blocking error was detected. YaST system repair halts now!");
		OSRProgress::Fill (`global_progress_bar);
		if( back2status_detect_method_name())
		{
		    return `restart;
		}
		return (OSRStatus::IsCancel()) ? `back :  `error;
	    }
	    else if ( ( OSRStatus::IsStatusDetectError() &&
			    OSRStatus::IsErrorSeverityModuleBlocking()) ||
			( OSRStatus::IsStatusRepairError() &&
			    OSRStatus::IsErrorSeverityModuleBlocking())	||
			( OSRStatus::IsStatusRepairOmit() &&
			    OSRStatus::IsErrorSeverityModuleBlocking()))
	    {
		/*
		    - DetectError & SeverityModuleBlocking:
			if a module-blocking error was detected but no repair
			method started
		    - RepairError & SeverityModuleBlocking:
			if a module-blocking error was detected but the repair
			method failed
		    - RepairOmit & SeverityModuleBlocking:
			if the user omitted repairing a module-blocking error

		    -> execute no further detection methods from the current
			module and jump to the next detection module
		*/

		// adjust the value of the global progress bar
		while (index_detect < size(detect_methods))
		{
		    OSRProgress::Increase(`global_progress_bar);
		    index_detect = index_detect + 1;
		}
	    }
	    else if ( OSRStatus::IsStatusDetectOK ()		||
			OSRStatus::IsStatusDetectOmit()		||
			OSRStatus::IsStatusNotFound()		||
			OSRStatus::IsStatusDetectError()	||
			OSRStatus::IsStatusDetectProblem()	||
			OSRStatus::IsStatusRepairOmit())
	    {
		  /*
		    - DetectOK:
			no error detected
		    - DetectProblem:
			potential problem detected and no repair method started
		    - RepairOmit:
			user omitted repairing a "normal" error

		    -> go to the next detection method
		    */

		// TODO no restarting is done here, so why is DetectError here?
		// DetectError:
		// if a "normal" error was detected but no repair method started
		// restart the current detection method
		OSRProgress::Increase(`global_progress_bar);
		index_detect = index_detect + 1;
	    }
	    else if (OSRStatus::IsStatusRepairOK() ||
		     OSRStatus::IsStatusRepairError() )
	    {
		/*
		    - RepairError:
			repair-method was not successfull
		    - RepairOK:
			all detected errors were repaired
		    ->restart detect
		*/

		y2milestone ("restarting detection method after repair");
		/*
		    NOTE: detection is restarted only once - see above check
		    "index_detect_loop_counter == max_index_detect_loop"
		*/
	    }
	    else if ( OSRStatus::IsOpen() )
	    {
		y2milestone("no status set in detection method: %1 (group %2)",
		    OSRCommon::current_detect_map["name"]:"",
		    OSRCommon::current_detect_map["group"]:"");
		OSRProgress::Increase(`global_progress_bar);
		index_detect = index_detect + 1;
	    }
	    else
	    {
		y2error("not a valid status: %1", OSRStatus::status );
	    }

	    OSRSummary::FinishNewEntry();

	    if (back2status_detect_method_name())
	    {
		  OSRStatus::Open();
		  OSRCommon::current_detect_map  = $[];
		  return `restart;
	    }
	    OSRStatus::Open();
	    OSRCommon::current_detect_map  = $[];
	}
	// fill the module-progress-bar to 100%, if not already done
	OSRProgress::Fill(`module_progress_bar);

	y2milestone("Finished module with the name  %1",
	OSRCommon::current_module_name);

	OSRCommon::current_module_name = "";

	// go to the next module
	index_modules = index_modules + 1;
    }

    // fill up the global-progress-bar to 100%, this can be necessary
    // because of arithmetic rounding problems
    OSRProgress::Fill(`global_progress_bar);
    OSRSummary::Finish();

    return `detectok;
  };


  /**
   * Start detection loop.
   */
  global define symbol Detect()``{
      symbol ret = `restart;
      while( ret == `restart ) {
	  ret = detect();
      }
      return ret;
  }

  /**
   * Sort the sequence of all detection methods of the
   * specified group.
   */
  define list<map> SortGroupSequence (map groups) ``{

      list<map> ret		= [];
      list<string> g_list	= [];
      foreach (string module_name,  module_sequence, ``{

	  list<map> detect_methods = ComputesDetectMethodSequence(module_name );
	  foreach(map method, detect_methods, ``{
	      if (!contains( g_list, method["group"]:"" ))
	      {
		  g_list = add (g_list , method["group"]:"");
	      }
	  });
      });
      foreach(string group, g_list, ``{
	  ret = add( ret, add( groups[group]:$[], "key", group ));
      });
      return ret;
  }

  /**
   * Count of all reset Methods.
   */
  define integer ResetMethodesCount()``{

      integer number_of_reset_methods = 0;

      foreach (string mod, module_sequence, ``{
	  number_of_reset_methods = number_of_reset_methods +
	      size(module_reset_methods[mod]:[] );
      });
      return number_of_reset_methods;
  }


  /**
   * Build item list with all group items.
   * @param mode if all entries should be checked ('Select all')
   */
  global define list<term> GroupItems(boolean mode)``{

    list<term> entries      = [];

    foreach (map d, SortGroupSequence( OSRCommon::global_entries ), ``{
	if (SizeDetectGroupList () > 0)
	{
	    mode = contains (DetectGroupList (), d["key"]:"");
	}
	if (d["mode"]:"" != "forall" && d["key"]:"" != "" && d["text"]:"" != "")
	{
	    entries = add (entries, `item(`id(d["key"]:""), d["text"]:"",mode));
	}
	else if( d["mode"]:"" != "forall" )
	{
	    y2error("Key not valid ('%1') or text entry ('%2') is empty",
		d["key"]:"", d["text"]:"");
	}
    });
    return entries;
  }




  global define void SelectDefaultDetectGroups()``{

    SetDetectGroupList (maplist (map vv,
	filter (map v, SortGroupSequence (OSRCommon::global_entries), ``(
	    v["selected"]:true == true)),
	``(vv["key"]:""))
    );
  }

  /**
   * check the dependencies for seleced detect groups
   */
  global define list<string> CheckGroupRequires()``{

    list<string> ret =  [];
    boolean again = true;
    while ( again )
    {
	boolean found = false;
	foreach (string group, DetectGroupList (), {

	    list<string> requires = (list<string>)
		OSRCommon::global_entries[group,"requires"]:[];
	    foreach (string req, requires, {
		if (!contains (OSRCommon::detect_group_list, req))
		{
		    if (!contains(ret, req))
		    {
			ret = (list<string>) toset(add(ret, req));
			found = true;
		    }
		}
	    });
	});
	if (found)
	{
	    SetDetectGroupList ((list<string>) union (DetectGroupList (), ret));
	    again = true;
	}
	else
	{
	    again = false;
	}
    }
    return ret;
  }

  /**
   * Prepare for reboot system
   */
  global define void SetReboot()``{
      if ( Stage::initial () )
      {
	  Linuxrc::WriteYaSTInf($["Root" : "reboot", "RebootMsg" : "0"]);
	  y2milestone ( "Make a hard reboot" );
      }
  }

}//EOF
