/*
 *************************************************************
 *
 *     YaST2      SuSE Labs                        -o)
 *     --------------------                        /\\
 *                                                _\_v
 *           www.suse.de / www.suse.com
 * ----------------------------------------------------------
 *
 * Author:        Michael Hager <mike@suse.de>
 *
 * Description:   utility part. proposal
 *                slot handling
 *
 *************************************************************

 $Id: propose_slot_util.ycp 15395 2004-03-04 16:27:34Z visnov $


*/
{
import "Partitions";
import "FileSystems";


  //////////////////////////////////////////////////////////////////////
  // get all the possible boot slots
  // ------------------------------------------------------------------
  //////////////////////////////////////////////////////////////////////

define map get_boot_slot_list( list<map> base_slots )
    ``{
    // todo: a free slot, which start_cyl +3 < Partitions::BootCyl() area
    // also a start cyl!
    list<map> boot_slots = 
        filter( map slot, base_slots, 
	        ``( slot["start_cyl"]:0+min_nb_boot_cyl<Partitions::BootCyl() && 
		    slot["size"]:1 >= Partitions::MinimalNeededBootsize() ));

    list<map> boot_slots_win = 
        filter( map slot, boot_slots, 
	        ``( slot["type"]:"" == "free" || 
		    slot["type"]:"" == "win_resize" ));
    list<map> boot_slots_reuse = 
        filter( map slot, boot_slots, 
	        ``( slot["type"]:"" == "free" || slot["type"]:""== "linux" ));
    list<map> boot_slots_reuse_only = 
        filter( map slot, boot_slots, ``( slot["type"]:"" == "linux" ));
    list<map> boot_slots_free = 
        filter( map slot, boot_slots, ``( slot["type"]:"" == "free" ));
	  
    return ( $[ "use_free"   : boot_slots_free,  
	        "use_win"    : boot_slots_win,
	        "reuse"      : boot_slots_reuse, 
	        "reuse_only" : boot_slots_reuse_only ] );
    };


  //////////////////////////////////////////////////////////////////////
  // get the slots from the partition list
  // ------------------------------------------------------------------
  // for further comment see:  see Step 2 in inst_part_proposal.ycp
  //////////////////////////////////////////////////////////////////////

define list<map> GetSlots( list<map> part_list, integer start_cyl, integer end_cyl,
		      integer cyl_size, boolean readonly, string dev )
    ``{
    integer last_border = 0;  // first not "slotted" cylinder.
    list<map>    slot_list   = [];

    y2milestone( "start:%1 end:%2 size:%3 readonly:%4", start_cyl, end_cyl, 
                 cyl_size, readonly );
    y2debug( "list:%1", part_list );

    last_border = start_cyl;

    // for every partition of this disk do ...
    foreach( map part, part_list, 
	``{
	integer old_last_border = last_border;
	integer begin_of_part = part["region",0]:0;
	integer end_of_part = begin_of_part + part["region",1]:1 - 1;

	y2debug( "last_border %1, begin %2, end %3", last_border, 
		 begin_of_part, end_of_part );

	//////////////////////////////////////////////////////////////
	// is there a gap between partitions -> create free slot
	//////////////////////////////////////////////////////////////
	if( last_border+1 < begin_of_part && !readonly )
	    {
	    // create freeslot
	    // example: last = 1 begin = 10 -> free = 1..9  
	    //          size = 10 - 1 * cylsize

	    integer psize  = ((begin_of_part - last_border-1)*cyl_size);
	    slot_list = 
		add( slot_list, $[ "type"      : "free",
				   "dev"       : dev,
				   "end_cyl"   : begin_of_part-1,
				   "start_cyl" : last_border,
				   "size"      : psize ] );
	    last_border = begin_of_part;
	    }

	// allow end of prevoius partition to be on same cylinder as
	// beginning of next one
	if( old_last_border > begin_of_part+1 )
	    {
	    y2error( "Partition order ? %1 %2", last_border, begin_of_part );
	    y2error( "slot_list %1", slot_list);
	    y2error( "part_list %1", part_list);
	    }

	/////////////////////////////////////////////////////////
	// create the slot for the current partition
	/////////////////////////////////////////////////////////
	integer nr     = part["nr"]:0;
	string  type   = "other";
	integer psize  = ((end_of_part - begin_of_part +1)*cyl_size);
	integer pstart =  begin_of_part;
	integer win_len = -1;
	integer win_max_len = -1;
	map     win_dat    = $[];

	integer fsid = part["fsid"]:0;
	if( size(part["winfo"]:$[])>0 && part["winfo","free"]:0>0 
	    /* && !part["winfo","ntfs"]:false */ )
	    {
	    win_dat = part["winfo"]:$[];
	    y2milestone( "win_dat=%1", win_dat );
	    if( psize>300*1024*1024 )
		{
		type    = "win_resize";
		psize   = win_dat["linux_size"]:-1;
		win_len = PartedSizeToCly( tofloat(win_dat["new_size"]:0), 
					   cyl_size );
		win_max_len = 
		    PartedSizeToCly( tofloat(win_dat["max_win_size"]:0), 
				     cyl_size );
		pstart  = begin_of_part + win_len;
		}
	    }
	if( fsid == Partitions::fsid_native )       type = "linux";
	if( fsid == Partitions::fsid_swap )         type = "swap";
	if( fsid == Partitions::fsid_extended )     type = "extended";
	if( fsid == Partitions::fsid_extended_win ) type = "extended";
	if( Partitions::PrepBoot() && fsid == Partitions::fsid_prep_chrp_boot )
	    type = "linux";
	if( fsid == Partitions::FsidBoot() && psize < 150*1024*1024 )
	    type = "linux";
	if( fsid == Partitions::fsid_gpt_boot )     
	    type = "linux";

	// for now, this auto mode does not handle raid/lvm

	map slot = $[ "type"      :     type,
		      "dev"       :     dev,
		      "nr"        :     nr,
		      "end_cyl"   :     end_of_part,
		      "start_cyl" :     pstart,
		      "size"      :     psize ];

	if( type == "win_resize" )
	    {
	    slot["win_size"] = win_dat["new_size"]:0;
	    slot["win_length"] = win_len;
	    slot["win_max_length"] = win_max_len;
	    slot["ntfs"] = win_dat["ntfs"]:false;
	    }
	slot_list = add( slot_list, slot );

	last_border = end_of_part +1;
	});

    //////////////////////////////////////////////////////////////
    // is there a gap between partitions -> create free slot
    //////////////////////////////////////////////////////////////
    if( last_border < end_cyl && !readonly )
	{
	// create freeslot
	// example: last = 1 end = 10 -> free = 1..10     
	//          size = 10 - 1 +1 * cylsize

	slot_list = add( slot_list, 
	                 $[ "type"   : "free",
			    "dev"    : dev,
			    "end_cyl": end_cyl,
			    "start_cyl": last_border,
			    "size"   : ((end_cyl - last_border +1)*cyl_size) ]);
	}
    y2milestone( "list:%1", slot_list );
    return( slot_list );
    };


//////////////////////////////////////////////////////////////////////
// Look if there is a boot slot
// type:: "p_or_l", "primary", "logical"

define boolean HaveBootSlot( string type, integer curr_slotnb, string mode,
                             map boot_slot_list )
    ``{
    // delete curr slot from boot slot if it is in there
    list<map> slots = [];

    if( mode == "use_free" ) slots = boot_slot_list["use_free"]:[];
    if( mode == "use_win" )  slots = boot_slot_list["use_win"]:[];
    if( mode == "reuse" )    slots = boot_slot_list["reuse"]:[];

    if( type == "reuse" )
	{
	type = "p_or_l";
	slots = boot_slot_list["reuse_only"]:[];
	}

    list b_slot = [];
    if ( type == "p_or_l" )
	{
	b_slot = filter( map slot, slots, ``(curr_slotnb!=slot["slotnb"]:-1 ));
	}
    else
	{
	b_slot = filter( map slot, slots, ``( curr_slotnb!=slot["slotnb"]:-1 && 
					   slot["p_or_l"]:"" == type ));
	}
    y2debug( "Have bootSlots: %1, %2", slots, b_slot );
    return( size(b_slot)>0 );
    };


//////////////////////////////////////////////////////////////////////
// search for the smallest boot slot

define map GetBootSlot( string type, integer curr_slotnb, string mode, 
                        map boot_slot_list )
    ``{
    // delete curr slot from boot slot if it is in there
    list<map> slots = [];

    if( mode == "use_free" ) slots = boot_slot_list["use_free"]:[];
    if( mode == "use_win" )  slots = boot_slot_list["use_win"]:[];
    if( mode == "reuse" )    slots = boot_slot_list["reuse"]:[];

    if( type == "reuse")
	{
	type = "p_or_l";
	slots = boot_slot_list["reuse_only"]:[];
	}
    
    if( type == "p_or_l" )
	{
	slots = filter( map slot, slots, ``(curr_slotnb != slot["slotnb"]:-1 ));
	}
    else
	{
	slots = filter( map slot, slots, 
	                ``( curr_slotnb != slot["slotnb"]:-1 && 
			    slot["p_or_l"]:"" == type ));
	}

    slots = sort( map slot_x, map slot_y, slots, 
                  ``(slot_x["size"]:0 < slot_y["size"]:0));

    return( slots[0]:$[] );
    };

}
