/**
 * Module: 		auto_part_prepare.ycp
 *
 * Authors: 		Andreas Schwab (schwab@suse.de)
 *			Klaus Kämpf (kkaempf@suse.de)
 *
 * Purpose: 		This module preparse the raw targetMap to
 *			cover the whole disk, including unpartitioned
 *			areas as 'dummy' partitions.
 *
 * $Id: auto_part_prepare.ycp 19964 2004-10-26 15:37:35Z fehr $
 *
 */
{
textdomain "storage";
import "Storage";
import "Partitions";
import "Mode";

define list<map<string, any> > prepare_partitions( map target, list<map<string, any> > partitions )
    ``{
    // --------------------------------------------------------------
    // The size of a unit (eg. one cylinder)
    integer  bytes_per_unit = target["cyl_size"]:1;
    y2debug("bytes_per_unit: %1", bytes_per_unit);

    // The size of the disk in units
    integer disk_size = target["cyl_count"]:1;
    y2debug("disk_size: %1", disk_size);
    
    size_of_boot = Partitions::MinimalNeededBootsize();

    // The minimum size needed to install a minimal system
    minimal_size = 160 * 1024 * 1024 + size_of_boot + size_of_swap;

    // The minimum size needed to install a default system
    integer required_size = 950 * 1024 * 1024 + size_of_boot + size_of_swap;

    // filter out all "create" paritions, they will be re-created at exit
    //   (this ensures a 'clean' partition list if this dialogue is re-entered

    partitions = filter (map<string, any> pentry, partitions, ``(!pentry["create"]:false));

    // reset all "delete" paritions, they will be re-created at exit
    //   (this ensures a 'clean' partition list if this dialogue is re-entered

    partitions = maplist (map<string, any> pentry, partitions, ``(add (pentry, "delete", false)));

    // The region that describes the full disk
    full_region = [ 0, disk_size ];

    //-------------------------------------------------------------------------
    // The action
    //-------------------------------------------------------------------------

    // First sort the partitions on the starting cylinder
    partitions = sort( map<string, any> p1, map<string, any> p2, partitions,
		       ``(start_of_region (p1["region"]:[])
			  < start_of_region(p2["region"]:[])));

    // now check if automatic partitioning if feasible

    // unpartitioned disk -> yes

    can_do_auto = false;

    if( size(partitions)==0 ) 
	{
	// No partitions -> use the entire disk
	can_do_auto = true;
	unused_region = full_region;
	}

    // extended region with enough free space -> yes

    if( (!can_do_auto) && contains_extended(partitions) ) 
	{
	// Extended partition already exists -> look for free space at
	// the end of it
	unused_region = unused_extended_region (partitions);

	// check if this is enough
	if( (size_of_region(unused_region,bytes_per_unit) > required_size) && 
	    can_create_logical (partitions))
	    can_do_auto = true;
	}

    // no extended region, but primaries left
    //   if there is enough space after the last defined primary -> yes

    if( !can_do_auto && !contains_extended (partitions) && 
	num_primary(partitions) != max_primary ) 
	{
	map<string, any> last_partition = partitions[size(partitions)-1]:$[];
	if( ignored_partition( target, last_partition ))
	    last_partition = partitions[size(partitions)-2]:$[];
	list<integer> last_region = last_partition["region"]:[];
	integer last_used = end_of_region(last_region);

	if (last_used < disk_size) 
	    {
	    unused_region = [ last_used, disk_size-last_used ];
	    if (size_of_region (unused_region,bytes_per_unit) > required_size)
		can_do_auto = true;
	    }
	}


    //-------------------------------------------------------------------------
    // Augment the partition list with a description for holes

    integer last_end = 0;
    integer free_nr = 0;

    // first the mid-disk holes

    partitions = flatten( maplist( map<string, any> pentry, partitions, 
	``{
	list<map <string, any> > ret = [];
	list<integer> region = pentry["region"]:[];

	if( !ignored_partition( target, pentry ) &&
	    start_of_region (region) > last_end) 
	    {
	    free_nr = free_nr + 1;
	    ret = add (ret, $["type":`free,
			     "region": [ last_end,
				       start_of_region (region) - last_end ]]);
	    // if free space is directly located before extended partition
	    last_end = start_of_region (region);
	    }

	// if this partition is not the extended partition or a ignored
	//    use its end_of_region as last_end
	// on BSD-like partitions, partition # 3 is handled similary

	if( (pentry["type"]:`unknown != `extended) &&
	    !ignored_partition( target, pentry ) )
	    last_end = end_of_region (pentry["region"]:[]);
	return add (ret, pentry);
	}));

    // then the end-disk hole

    if (last_end < disk_size) 
	{
	free_nr = free_nr + 1;
	partitions = add (partitions,
			  $[ "type":`free,
			     "region": [ last_end, disk_size - last_end ]]);
	}

    // now the partitions list spans the whole disk
    if (Mode::test ()) y2milestone("all partitions: %1", partitions);

    //-------------------------------------------------------------------------
    // Create a checkbox for every real (primary or logical) partition
    // and any free space

    // give each partition a unique id

    integer ui_id = 0;
    partitions = maplist (map<string, any> pentry, partitions, 
	``{
	ui_id = ui_id + 1;
	return add (pentry, "ui_id", ui_id);
	});

    y2milestone( "unused_region %1", unused_region );

    return partitions;
    };
}
