/*
 *************************************************************
 *
 *     YaST2      SuSE Labs                        -o)
 *     --------------------                        /\\
 *                                                _\_v
 *           www.suse.de / www.suse.com
 * ----------------------------------------------------------
 *
 * Author:        Thomas Fehr <fehr@suse.de>
 *
 * Description:   Make a proposal for partitioning
 *
 *
 *************************************************************

 $Id: do_proposal.ycp 22502 2005-03-14 12:55:21Z fehr $
*/
{

textdomain "storage";

import "Arch";
import "Mode";
import "Storage";
import "Partitions";
import "ProductFeatures";

list<map>    hitlist = [];
boolean hiterror = false;
integer min_nb_boot_cyl = 0;

include "partitioning/propose_part_util.ycp";
include "partitioning/propose_create_target.ycp";
include "partitioning/propose_slot_util.ycp";
include "partitioning/do_proposal_flexible.ycp";


define boolean ignore_disk( string dev, map entry, boolean soft )
    ``{
    boolean ret = !Storage::IsRealDisk( dev, entry );
    if( Arch::board_iseries () && find( dev, "/dev/sd" )==0 )
	{
	ret = true;
	}
    if( soft && entry["softraiddisk"]:false )
	{
	ret = true;
	}
    if( ret )
	{
	y2milestone( "ignoring disk %1 soft %2", dev, soft );
	}
    return( ret );
    };
  
define map do_proposal_real( boolean need_boot, map<string,map> targetMap,
                             boolean ignore_soft )
    ``{
    map<string,map> tmptargetMap = $[];

    y2milestone( "test with need_boot == %1", need_boot);
    

    /////////////////////////////////////////////////////////////////
    // Now we generate a proposal
    /////////////////////////////////////////////////////////////////

    foreach( string dev, map disk, 
	     filter( string k, map e, targetMap, 
	             ``(!ignore_disk(k,e,ignore_soft))),
	``{
	y2milestone( "checking disk %1", dev );

	list<integer> primary_possible = [1,2,3,4];
	boolean extended_allowed = true;
	if( disk["max_primary"]:4 > 4 )
	    {
	    extended_allowed = false;
	    integer i = 5;
	    while( i<=disk["max_primary"]:4 )
		{
		primary_possible = add( primary_possible, i );
		i = i+1;
		}
	    if( disk["label"]:"" == "sun" || disk["label"]:"" == "bsd" )
		{
		primary_possible = filter( integer n, primary_possible, ``(n != 3 ));
		}
	    }
	y2milestone( "extended_allowed %1, primary_possible %2", 
		     extended_allowed, primary_possible );

	/////////////////////////////////////////////////////////
	// 1. Step:
	// We collect info about the partitions on the disk
	/////////////////////////////////////////////////////////

	map main_slots      = $[];
	map extended_slots  = $[];

	integer cyl_count = disk["cyl_count"]:1;
	integer cyl_size  = disk["cyl_size"]:1;

	min_nb_boot_cyl = (Partitions::MinimalNeededBootsize() / cyl_size) + 1;

	y2milestone( "minimal_needed_cyl nb: %1", min_nb_boot_cyl );

	list<map> primary_list = 
	    filter( map part, disk["partitions"]:[],
		    ``( part["type"]:`unknown == `primary  && 
			!part["delete"]:false ));
	list<map> extended_list = 
	    filter( map part, disk["partitions"]:[],
		    ``( part["type"]:`unknown == `extended && 
			!part["delete"]:false ));
	list<map> logical_list = 
	    filter( map part, disk["partitions"]:[],
		    ``( part["type"]:`unknown == `logical && 
			!part["delete"]:false ));

	list<map>    pri_extd_list   = primary_list + extended_list;
	boolean i_have_extended = ( size(extended_list) > 0);
	y2milestone( "i_have_extended %1, extended_list %2", i_have_extended, 
		     extended_list );

	pri_extd_list = sort(map p_x, map p_y, pri_extd_list, 
			     ``(p_x["region",0]:0 < p_y["region",0]:0));
	logical_list  = sort(map p_x, map p_y, logical_list, 
			     ``(p_x["region",0]:0 < p_y["region",0]:0));

	y2milestone( "pri+extd parts %1", pri_extd_list );
	y2milestone( "logical_list   %1", logical_list  );

	// which primary partitions can I create?

	list pri_extd_nr_list = maplist(map p, pri_extd_list, ``(p["nr"]:0));
	list free_pri_extd_nr_list = 
	    filter( integer nr, primary_possible, 
		    ``( !contains( pri_extd_nr_list, nr )));

	y2milestone( "free pri+extd parts %1", free_pri_extd_nr_list );


	/////////////////////////////////////////////////////////
	// 2. Step
	// We look at the partitions, and create the list of possible slots
	/////////////////////////////////////////////////////////

	/////////////////////////////////////////////////////////
	//  a slot: a partition or the unallocated space between two 
	//  partitions
	//
	// example a disk with two partitions windows:hda1 (cyl 10--100) 
	// linux-root: hda2 (cyl 200-300)
	// [ slot1: free slot cyl 1   -   9 ]
	// [ slot2: slot hda1 cyl 10  - 100 ]
	// [ slot3: free slot cyl 101 - 199 ]
	// [ slot4: slot hda2 cyl 200 - 300 ]
	// [ slot5: free slot cyl 301 - 799 ]
	//
	// cyl: 1       9  10    100  101   199    200    300   556     998
	// nb:  [ slot1 ]  [ slot2 ]  [ slot3 ]    [ slot 4 ]   [ slot 5  ]
	// type free       win        free         linux         free
	//
	/////////////////////////////////////////////////////////
	// base-slot: big slot which can contain the root partition
	//            (probably it will be splitted in 2 or 3 parts:
	//            boot-[swap]-root partitions
	// boot-slot: little slot wich can contain a boot partition


	// slottype::
	// $[
	// "type" : "free"|"win_resize"|"linux"|"extended"|"swap"|"other"
	//    "win_resize" are all windows types, we can resize
	//
	//    "dev"       :     "/dev/hda" | "/dev/sdb" | ...
	//    "p_or_l"    :     "primary", "logical"
	//    "start_cyl" :     <start of slot>
	//    "end_cyl"   :     <end of slot>,
	//    "size"      :     <size in byte>   
	//                      for win_resize its the max free space I can 
	//                      get if I resize this windows
	//     --- optional ----
	//    "nr"        :     nr,    partition number, 1 in /dev/hda1 
	//                             valid if type != "free
	//    "win_size"  :    <new size of the win partition>
	//                     only for type == "win_resize"
	//    "win_length":    <length of the new win partition in cyl>
	//                     only for type == "win_resize"
	//  ]

	list<map> primary_slots = GetSlots( pri_extd_list, 0, cyl_count-1, cyl_size,
				       disk["readonly"]:false, dev );
	list<map> logical_slots = [];

	if( size(extended_list) >= 1 && extended_allowed )
	    {
	    map extended = extended_list[0]:$[];

	    integer begin_extd = extended["region",0]:0;
	    integer end_extd = begin_extd + extended["region",1]:1 - 1;

	    y2debug( "The extended: %1", extended );
	    logical_slots = GetSlots( logical_list, begin_extd, end_extd, 
				      cyl_size, disk["readonly"]:false, dev );
	    }

	logical_slots = maplist( map slot, logical_slots, 
				 ``(add(slot, "p_or_l", "logical")));
	primary_slots = maplist( map slot, primary_slots, 
				 ``(add(slot, "p_or_l", "primary")));
	/* hack added to prevent partition 0x41 (Prep Boot) being inside
	   an extended partition, it is a bit radical but anyway it reaches
	   its goal */
	if( Partitions::PrepBoot() && size(logical_slots)>0 )
	    {
	    logical_slots = maplist( map slot, logical_slots,
		``({
		if( slot["type"]:"" != "free" )
		    slot["type"] = "other";
		return( slot );
		}));
	    primary_slots = maplist( map slot, primary_slots,
		``({
		if( slot["type"]:"" != "free" )
		    slot["type"] = "other";
		return( slot );
		}));
	    }

	list<map> base_slots = primary_slots + logical_slots;

	integer i   = 0;
	base_slots = maplist( map slot, base_slots, 
			      ``{ i = i+1; 
				  return(add(slot, "slotnb", i)); 
				});

	y2debug( "pri+extd parts %1", pri_extd_list );
	y2debug( "primary_slots  %1", primary_slots );
	y2debug( "logical_list   %1", logical_list  );
	y2debug( "logical_slots  %1", logical_slots );


	/////////////////////////////////////////////////////////
	// now the boot slots

	map boot_slot_list = get_boot_slot_list( base_slots );

	y2debug( "OUT: ////////////// targetMap /////////////////");
	DumpPartitionList ( targetMap);

	y2debug( "OUT: //////////////   slots   /////////////////");
	foreach( map slot, base_slots,
	    ``{
	    string end_cyl = ToLen(6, sformat("%1", slot["end_cyl"]:0 ));
	    string start_cyl = ToLen(6, sformat("%1", slot["start_cyl"]:-1));
	    string psize = ToLen(6, sformat("%1", slot["size"]:0/1000000 ));
	    string slotnb = ToLen(2, sformat("%1", slot["slotnb"]:-1 ));
	    string stype = ToLen(10, slot["type"]:"other" );

	    y2debug( "OUT: Slot %1:  %2   %3   %4  to  %5   %6MB", slotnb, 
		     stype, slot["p_or_l"]:"?", start_cyl, end_cyl, psize );
	    });

	  
	/////////////////////////////////////////////////////////
	// is there a reusable swap slot?
	  
	list<map> swap_slots_only = filter( map slot, base_slots, 
				       ``( slot["type"]:"" == "swap" ));
	swap_slots_only = sort(map p_x, map p_y, swap_slots_only, 
			       ``(p_x["size"]:0 > p_y["size"]:0 ));

	map swap_slot = $[];

	if ( size(swap_slots_only) >= 1 ) 
	    swap_slot = swap_slots_only[0]:$[];

	/////////////////////////////////////////////////////////
	// is there a reusable boot slot?
	  
	list<map> boot_slots_only = 
	    filter( map slot, base_slots, 
		    ``( slot["type"]:""=="linux" && 
			slot["size"]:0>=8*1024*1024 && 
			slot["size"]:0<=100*1024*1024));
	boot_slots_only = sort(map p_x, map p_y, boot_slots_only, 
			       ``(p_x["size"]:0 > p_y["size"]:0));

	/////////////////////////////////////////////////////////
	// LOOK FOR POSS
	/////////////////////////////////////////////////////////

	// look for possibilities to partitioning in three
	// modes:
	// "use_free" : this is the mode, I like most: Try to install
	//              Linux without changeing the rest of my system
	// "reuse"    : use old linux partitions
	// "use_win"  : try to get space by resizing windows
	//              win HAS TO BE the LAST MODE! we made 
	//              irreversible changes to slot-db

	list<string> modes = [ "use_free", "reuse", "use_win" ];
	if( disk["readonly"]:false )
	    {
	    modes = [ "reuse" ];
	    }

	foreach( string mode, modes,
	    ``{
	    map boot_reuse_slot = $[];

	    if( size(boot_slots_only) >= 1 && mode != "use_free" ) 
		{
		boot_reuse_slot = boot_slots_only[0]:$[];
		}
	    else
		{
		boot_reuse_slot = $[];
		}

	    y2debug( "OUT: //////////// MODE == %1 //////////////////", mode);

	    /////////////////////////////////////////////////////////
	    // be sure "use_win" is the last mode!
	    //
	    // Now we change the slots a little bit ...
	    //
	    // if I have      [win_free 100MB] [free 200BM]  I make
	    // one big slot   [  win_free 300MB           ]
	    // only if freeslot is too little

	    if( mode == "use_win" )
		{
		boolean melted           = false;
		list<map>    new_base_slots   = [];
		map     old_slot         = $[ "type":"other" ];
		boolean first_slot       = true;
		boolean melted_last_slot = false;

		foreach( map slot, base_slots,
		    ``{
		    if( old_slot["type"]:"" == "win_resize" &&
			slot["type"]:"" == "free" &&
			slot["size"]:-1 <= 1000000000 )
			{
			// melt the two slots
			old_slot["end_cyl"] = slot["end_cyl"]:-1;
			old_slot["size"] = 
			    old_slot["size"]:-1 + slot["size"]:-1;

			new_base_slots   = add( new_base_slots, old_slot );
			melted_last_slot = true;
			melted           = true;
			}
		    else
			{
			if ( !melted_last_slot && !first_slot ) 
			    new_base_slots = add( new_base_slots, old_slot );
			melted_last_slot = false;
			}

		    first_slot = false;
		    old_slot   = slot;
		    });

		if( !melted_last_slot && !first_slot ) 
		    new_base_slots = add( new_base_slots, old_slot );

		if ( melted )
		    {
		    y2debug("OUT: SLOTS MELTED !");
		    base_slots = new_base_slots;
		    boot_slot_list = get_boot_slot_list( base_slots );
		    }
		}


	    /////////////////////////////////////////////////////
	    // look how many primary partitions we can create and 
	    // which number they will get
	    integer free_primary = size(free_pri_extd_nr_list);

	    integer second_pri        = -1;
	    integer first_pri         = -1;
	    integer third_pri         = -1;

	    if ( free_primary >= 1 )
		{
		first_pri = free_pri_extd_nr_list[0]:-1;
		if( free_primary >= 2 )
		    {
		    second_pri = free_pri_extd_nr_list[1]:-1;
		    if( free_primary >= 3 )
			{
			third_pri = free_pri_extd_nr_list[2]:-1;
			}
		    }
		}

	    integer first_free_logical = 5 + (size(logical_list));
	    integer max_logical = Partitions::MaxLogical(dev);
	    y2milestone( "first_free_logical %1 max_logical:%2", 
	                 first_free_logical, max_logical );

	    // ap disk_info = $[ "dev":dev,
	    //                "first_free_logical":first_free_logical,
	    //                "first_pri"         :first_pri,  
	    // 			not valid if reuse!!!!
	    //                "second_pri"        :second_pri,
	    //                "min_nb_boot_cyl"   :min_nb_boot_cyl];
	    //
	    // y2milestone( "disk_prop_info: %1", disk_info );


	    /////////////////////////////////////////////////////
	    // for every partition of this disk do ...
	    //---------------------------------------------------
	    //
	    // DO THE CENTRAL ALGORITHM ... see README.auto_partitiong
	    //
	    // find partition proposals, and add every proposal as hit 
	    // to the hitlist
	    //
	    /////////////////////////////////////////////////////

	    foreach( map slot, base_slots,
		``{
		integer end_cyl    = slot["end_cyl"]:-1;
		integer start_cyl  = slot["start_cyl"]:-1;
		integer psize      = slot["size"]:1;
		string  stype      = slot["type"]:"other";
		integer slotnb     = slot["slotnb"]:-1;
		boolean is_primary = slot["p_or_l"]:"" == "primary";

		y2debug( "OUT: -- Working on slot %1", slotnb);

		if( psize > Partitions::minimal_needed_disksize &&
		    // not && mode=free see testsuite diffs!
		    ( (stype=="free") || 
		      ((stype=="win_resize") && (mode=="use_win")) || 
		      ((stype=="linux")      && (mode=="reuse"))))
		    {
		    // end of boot partition if I spilt the base slot 
		    // into two parts
		    integer split_boot_end = start_cyl + min_nb_boot_cyl;
		    /////////////////////////////////////////////
		    //     !!!!!! have a look at this !!!!!!
		    /////////////////////////////////////////////
		    free_primary    = size(free_pri_extd_nr_list);
		    integer curr_second_pri     = second_pri;
		    integer curr_first_pri      = first_pri;
		    integer curr_third_pri      = third_pri;
		    if( stype == "linux" )
			{
			// in mode reuse, I can reuse the primary 
			// base-slot, so I have "one primary more"
			free_primary = free_primary + 1;
			curr_third_pri      = second_pri;
			curr_second_pri     = first_pri;
			curr_first_pri      = -1;
			}

		    //////////////////////////////////////
		    // Do I need a boot partition?
		    //////////////////////////////////////
		    if( need_boot || end_cyl>Partitions::BootCyl() )
			{
			// yes I need a boot partition
			if( is_primary )
			    {
			    //////////////////////////////////
			    // base-slot is a primary-slot

			    if( !i_have_extended && extended_allowed )
				{
				y2debug( "OUT: test of primary slot no extd  %1", slotnb);

				// if I have two or more primary free
				//   b1: yes, if, start_cyl +3 < 1024   
				//            then I create two extd 
				//            partitions in slot
				//   b2: yes  if I have a free boot-slot 
				//            it is always a primary-slot!
				//
				// if I have one primary free
				//   b1: yes, if, start_cyl +3 < 1024   
				//            then I create two extd 
				//            partitions in slot
				//   b2: no! if I have a free boot-slot 
				//            its primary-slot! but I 
				//            NEED TO MAKE ANOTHER PARTITION
				// if I have no  primary free -> no way 
				//    cause I can not create a partition

				y2debug( "OUT: cr one %1 split %2 ", 
					 free_primary>0, 
					 split_boot_end<Partitions::BootCyl());
				y2debug( "OUT: cr two %1 HavePL %2", 
					 free_primary>1, 
					 HaveBootSlot( "p_or_l", slotnb, mode, 
						       boot_slot_list));
				y2debug( "OUT: currReu %1 R %2 HavepR %3",
					 (stype == "linux"),  
					 (mode == "reuse"),
					 HaveBootSlot( "reuse", slotnb, mode, 
						       boot_slot_list));
				y2debug( "OUT: cr one %1 R %2 HavepR %3", 
					 free_primary>0,  (mode == "reuse"),
					 HaveBootSlot( "reuse", slotnb, mode, 
					               boot_slot_list));

				if( free_primary>0 && 
				    split_boot_end<Partitions::BootCyl() )
				    {
				    AddHit( mode, slot, "2p-nE-2pri-split",
					    $[], curr_first_pri, "extd", 
					    "boot_split", "need_boot", -1,
					    "root_split", swap_slot, 
					    boot_reuse_slot, curr_second_pri, 
					    free_primary );
				    }

				if( (stype == "linux") && (mode == "reuse") && 
				    HaveBootSlot( "reuse", slotnb, mode, 
						  boot_slot_list))
				    {
				    AddHit( mode, slot, "2p-nE-2pri-RRhave",
					    GetBootSlot( "reuse", slotnb, mode, 
							 boot_slot_list),
					    -1, "extd", "no_boot_split", 
					    "need_boot", -1, "root_split", 
					    swap_slot, boot_reuse_slot, 
					    curr_first_pri, free_primary );
				    }

				if( free_primary>0 && (mode == "reuse") && 
				    HaveBootSlot( "reuse", slotnb, mode, 
						  boot_slot_list))
				    {
				    AddHit( mode, slot, "2p-nE-2pri-Rhave",
					GetBootSlot( "reuse", slotnb, mode, 
							 boot_slot_list),
					    curr_first_pri, "extd", 
					    "no_boot_split", "need_boot", 
					    -1, "root_split", swap_slot, 
					boot_reuse_slot, curr_second_pri, 
					free_primary );
				    }

				if( free_primary>1 && 
				    HaveBootSlot( "p_or_l", slotnb, mode, 
						  boot_slot_list) )
				    {
				    AddHit( mode, slot, "2p-nE-2pri-have", 
					    GetBootSlot( "p_or_l", slotnb, mode,
							 boot_slot_list),
					    curr_first_pri, "extd", 
					    "no_boot_split", "need_boot", 
					    curr_second_pri, "root_split", 
					    swap_slot, boot_reuse_slot, 
					    curr_third_pri, free_primary );

				    }
				}
			    // Try without an extended 
			    // if I have no  primary free -> no way 
			    //          I cannot create the roor partition
			    // if I have one primary free
			    //    b1: no way, cause I need second 
			    //          partition and the split requires 
			    //          a second possible primary partition
			    //    b2: yes if there is a free boot-slot 
			    //          in the extended partition
			    //          -> I need a boot partition, so it 
			    //             must be in the extended partition
			    // if I have two or more free primary
			    //    b1: yes, if, start_cyl +3 < 1024
			    //    b2: yes, if I have a free boot-slot 
			    //             primary or not is not important

			    y2debug( "OUT: test of primary slot extd %1", 
				     slotnb);
			    y2debug( "OUT: cr one %1 HaveL %2 ", 
				     free_primary>0, 
				     HaveBootSlot("logical", slotnb, mode, 
						  boot_slot_list) );
			    y2debug( "OUT: cr two %1 split %2", 
				     free_primary>1, 
				     split_boot_end<Partitions::BootCyl() );
			    y2debug( "OUT: cr two %1 HavePL %2",
				     free_primary>1, 
				     HaveBootSlot( "p_or_l", slotnb, mode, 
						   boot_slot_list) );
			    y2debug( "OUT: currReu %1 R %2 HavepR %3", 
				     (stype == "linux"), (mode == "reuse"),
				     HaveBootSlot( "reuse", slotnb, mode,
						   boot_slot_list));
			    y2debug( "OUT: cr one %1 R %2 HavepR %3", 
				     free_primary>0, (mode == "reuse"),
				     HaveBootSlot( "reuse", slotnb, mode,
						   boot_slot_list) );


			    if( (stype == "linux") && (mode == "reuse") &&
			        extended_allowed &&
				HaveBootSlot( "reuse", slotnb, mode, 
					      boot_slot_list))
				{
				AddHit( mode, slot, "2p-E--RRhave", 
					GetBootSlot( "reuse", slotnb, mode,
						     boot_slot_list),
					-1, "extd", "no_boot_split", 
					"need_boot", -1, "no_root_split", 
					swap_slot, boot_reuse_slot, 
					curr_first_pri, free_primary );
				}

			    if( free_primary>0 && (mode == "reuse") && 
			        extended_allowed &&
				HaveBootSlot( "reuse", slotnb, mode, 
					      boot_slot_list))
				{
				AddHit( mode, slot, "2p-E--Rhave", 
					GetBootSlot( "reuse", slotnb, mode,
						     boot_slot_list),
					curr_first_pri, "extd", 
					"no_boot_split", "need_boot", -1, 
					"no_root_split", swap_slot, 
					boot_reuse_slot, curr_second_pri, 
					free_primary );
				}

			    if( free_primary>0 && 
			        first_free_logical<=max_logical &&
				HaveBootSlot("logical", slotnb, mode, 
					     boot_slot_list) )
				{
				AddHit( mode, slot, "2p-E-1pri-have", 
					GetBootSlot("logical", slotnb, mode,
						    boot_slot_list),
					curr_first_pri, "no_extd", 
					"no_boot_split", "need_boot", 
					first_free_logical, "no_root_split",
					swap_slot, boot_reuse_slot,
					curr_second_pri, free_primary );
				}

			    if( free_primary>1 && 
				split_boot_end < Partitions::BootCyl() )
				{
				AddHit( mode, slot, "2p-E-2pri-split", $[],
					curr_second_pri, "no_extd", 
					"boot_split", "need_boot", 
					curr_first_pri, "no_root_split",
					swap_slot, boot_reuse_slot,
					curr_third_pri, free_primary );
				}

			    if( free_primary>1 && 
				HaveBootSlot( "primary", slotnb, mode, 
					      boot_slot_list) )
				{
				AddHit( mode, slot, "2p-E-2pri-have", 
					GetBootSlot( "primary", slotnb, 
						     mode, boot_slot_list),
					curr_first_pri, "no_extd", 
					"no_boot_split", "need_boot", 
					-1, "no_root_split",
					swap_slot, boot_reuse_slot,
					curr_second_pri, free_primary );
				}
			    }
			else
			    {
			    y2debug( "OUT: test of logical slot %1", 
				     slotnb);
			    y2debug( "OUT: split %1", 
				     split_boot_end<Partitions::BootCyl() );
			    y2debug( "OUT: HaveL %1", 
				     HaveBootSlot("logical", slotnb, mode, 
						  boot_slot_list));
			    y2debug( "OUT: HaveP %1", 
				     HaveBootSlot("primary", slotnb, mode, 
						  boot_slot_list) );
			    y2debug( "OUT: less4 %1", free_primary>0 );

			    ///////////////////////
			    // base slot is logical

			    if( split_boot_end < Partitions::BootCyl() &&
			        first_free_logical+1<=max_logical )
				{
				AddHit( mode, slot, "2p-log-split", $[],
					first_free_logical, "no_extd", 
					"boot_split", "need_boot", 
					first_free_logical+1, "no_root_split", 
					swap_slot, boot_reuse_slot,
					first_free_logical+2, free_primary );
				}

			    if( (stype == "linux") && 
			        first_free_logical<=max_logical &&
				HaveBootSlot("logical", slotnb, mode, 
					     boot_slot_list) )
				{
				AddHit( mode, slot, "2p-log-log-have", 
					GetBootSlot("logical", slotnb, mode,
						    boot_slot_list),
					-1, "no_extd", "no_boot_split", 
					"need_boot", first_free_logical, 
					"no_root_split", swap_slot, 
					boot_reuse_slot, first_free_logical+1, 
					free_primary );
				}
			    if( mode != "reuse" && 
			        first_free_logical+1<=max_logical &&
				HaveBootSlot("logical", slotnb, mode, 
					     boot_slot_list) )
				{
				AddHit( mode, slot, "2p-log-log-have", 
					GetBootSlot("logical", slotnb, mode,
						    boot_slot_list),
					first_free_logical, "no_extd", 
					"no_boot_split", "need_boot", 
					first_free_logical+1, "no_root_split",
					swap_slot, boot_reuse_slot, 
					first_free_logical+2, free_primary );
				}


			    if( free_primary>0 && 
			        first_free_logical<=max_logical &&
				HaveBootSlot("primary", slotnb, mode, 
					     boot_slot_list) )
				{
				AddHit( mode, slot, "2p-log-1pri-have", 
					GetBootSlot("primary", slotnb, mode,
						    boot_slot_list),
					first_free_logical, "no_extd", 
					"no_boot_split", "need_boot", 
					curr_first_pri, "no_root_split",
					swap_slot, boot_reuse_slot, 
					first_free_logical+1, 
					free_primary );
				}

			    }
			}
		    else
			{
			///////////////////////////////////////////
			// no, only one partition needed
			///////////////////////////////////////////

			y2debug( "OUT: test of slot %1 %2 %3", slotnb, 
				 is_primary, free_primary>0);

			// ** it is a primary base-slot
			//    if I have no  primary free 
			//      no! I can not create the root partition
			//    if I have one or more free primary
			//      yes: I always can create the root partition
			//

			if ( is_primary && free_primary>0 )
			    {
			    AddHit( mode, slot, "1p-ne-pri", $[],
				    curr_first_pri, "no_extd", "no_boot_split",
				    "no_need_boot", -1, "no_root_split", 
				    swap_slot, boot_reuse_slot, curr_second_pri,
				    free_primary );
			    if( !i_have_extended && extended_allowed )
				{
				AddHit( mode, slot, "1p-e-pri", $[],
					curr_first_pri, "extd", "no_boot_split",
					"no_need_boot", -1, "root_split", 
					swap_slot, boot_reuse_slot, 
					curr_second_pri, free_primary );
				}
			    }

			// ** is the base-slot in an extended partition
			//    yes: I always can create the root partition

			if( !is_primary && first_free_logical<=max_logical )
			    {
			    AddHit( mode, slot, "1p-log", $[],
				    first_free_logical, "no_extd", 
				    "no_boot_split", "no_need_boot", -1,
				    "no_root_split", swap_slot, boot_reuse_slot,
				    first_free_logical+1, free_primary );
			    }
			}
		    }
		});
	    });
	});


    if( size(hitlist) > 0 )
	{
	/////////////////////////////////////////////////////////////////////
	// next step is find the best hit
	//    hit rating for the best proposal:
	//    all mode==free are better than win_reuse/reuse
	//    all mode==reuse better than win_reuse
	//
	//  one slot: if biggest slot <  1.5G  1p-pri == 1p-log      //win-mode!
	//  one slot: if biggest slot >= 1.5G  1p-pri <  1p-log
	//
	//  if size is > 2G or size_have <= size_split * 1.1
	//  -split is better than -have, because an own boot-slot will not 
	//  be used really good.
	//
	//  If I can make a swap partition:  size_ns = ns-proposal
	//  size_s
	//  450-800   size_ns >= size_s*1.2
	//  800-1.2   size_ns >= size_s*1.2
	//  1.2-1.6   size_ns >= size_s*1.3
	//  1.6-2     size_ns >= size_s*1.5
	//  >2        use swap
	//

	map<string,any> the_hit = GetTheBestHit( hitlist );

	if ( Mode::test () )
	    {
	    // OLNLY FOR DEBUG
	    foreach( map hit, hitlist, ``{
		y2debug( "OUT: ---------------- new hit-----------------");
		map<string,map> tmp_targetMap = filter( string key, map val, targetMap, ``(true));
		TargetChangesToRichText( (map<string,map>)HitToTargetMap( tmp_targetMap, (map<string,any>)hit ), 
		                         $[]);
		});

	    map<string,map> tmp_targetMap = filter( string key, map val, targetMap, ``(true));
	    y2debug( "OUT: ============== THE HIT =======================-");
	    TargetChangesToRichText( (map<string,map>)HitToTargetMap( tmp_targetMap, the_hit ), 
	                             $[]);
	    y2debug( "OUT: ---------------------------");
	    }


	/////////////////////////////////////////////////////////////////////
	// next step to create the new target map from hit

	tmptargetMap = (map<string,map>)HitToTargetMap( filter( string key, map val, targetMap, 
	                                       ``(true)), the_hit );
	tmptargetMap = Storage::SpecialBootHandling(tmptargetMap);
	}
    return( $[ "ok" : size(tmptargetMap)>0, "target" : tmptargetMap ] );
    }
  
define map proposal_s390( map<string,map> targetMap )
    ``{
    boolean found = false;
//    foreach( string dev, map disk, targetMap, 
//	``{
//	if( !found && find( dev, "/dev/dasd" )==0 && 
//	    size(disk["partitions"]:[])>0 )
//	    {
//	    found = true;
//	    targetMap[dev,"partitions",0,"format"] = true;
//	    targetMap[dev,"partitions",0,"mount"] = "/";
//	    targetMap[dev,"partitions",0,"used_fs"] = `reiser;
//	    targetMap[dev,"partitions",0,"fs_options"] = 
//		$["opt_blocksize":$["option_str":"-b", "option_value":"4096"]];
//	    }
//	});
    return( $[ "ok" : found, "target" : targetMap ] );
    };

define map do_proposal()
    ``{
    boolean done = false;
    if ( !Mode::test () )
	{
	// popup text
	string message = _("Analyzing Partitioning. One moment please ...");
	UI::OpenDialog(`opt(`decorated), `Label(message));
	}
    y2milestone( "FsidBoot %1 BootCyl %2 MinimalNeededBootsize %3 DefaultBootFs %4",
                 Partitions::FsidBoot(), Partitions::BootCyl(),
                 Partitions::MinimalNeededBootsize(), 
		 Partitions::DefaultBootFs() );

    map<string,map> target = eval(Storage::GetTargetMap());
    //target = SCR::Read(.target.yast2, "test_target_map_ol.ycp");
    map ret = $[];
    if( Arch::s390 () )
	{
	ret = proposal_s390( target );
	}
    else if( has_flex_proposal() || ProductFeatures::flexible_partitioning)
	{
	ret = do_proposal_flexible( target );
	y2milestone( "suggestion flex possible: %1", ret["ok"]:false);
	}
    else
	{
	ret = do_proposal_real( Partitions::NeedBoot(), target, true );
	y2milestone( "suggestion possible: %1", ret["ok"]:false);
	if( !ret["ok"]:false )
	    {
	    string use_disk = "";
	    list del_part = [];
	    list nodelpart = Partitions::do_not_delete;
	    foreach ( string dev, map disk, target, 
		``{
		y2milestone( "dev %1 ignore %2 use_disk %3 ro %4", dev, 
		             ignore_disk(dev,disk,false), use_disk, 
			     disk["readonly"]:false );
		if( !ignore_disk(dev,disk,false) && use_disk == "" && 
		    !disk["readonly"]:false && find( dev, "/dev/" )==0 )
		    {
		    use_disk = dev;
		    list keep = [];
		    del_part = maplist( map p, disk["partitions"]:[], 
					``{
					if( !contains( nodelpart, p["fsid"]:0 ))
					    {
					    p["delete"] = true;
					    }
					else
					    {
					    keep = add( keep, p );
					    }
					return( p );
					});
		    y2milestone( "keep %1", keep );
		    y2milestone( "del_part %1", del_part );
		    target[dev,"partitions"] = keep;
		    }
		});
	    y2milestone( "use_disk %1 del_part %2", use_disk, del_part );
	  
	    if( use_disk != "" )
		{
		ret = do_proposal_real( Partitions::NeedBoot(), target, false );
		}
	    if( ret["ok"]:false )
		{
		del_part = del_part + ret["target",use_disk,"partitions"]:[];
		ret["target",use_disk,"partitions"] = del_part;
		ret["target"] = Storage::DeleteDestroyedLvmVgs(ret["target"]:$[]);
		}
	    }
	}
    y2milestone( "suggestion possible: %1", ret );
    if ( !Mode::test () ) UI::CloseDialog();
    return( ret );
    }

}
  
