/*
 *************************************************************
 *
 *     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_flexible.ycp 21828 2005-02-22 13:04:15Z fehr $
*/
{

textdomain "storage";

import "FileSystems";
import "ProductFeatures";

include "partitioning/partition_defines.ycp";

map read_partition_config( string fpath );
map read_partition_xml_config();
map get_gap_info( map disk, boolean add_exist_linux );
map add_cylinder_info( map conf, map gap );
map get_perfect_list( list ps, map g );
map process_partition_data( string dev, map solution );
map find_matching_disk( list<string> disks, map target, map conf );
map try_resize_windows( map disk );
map remove_possible_partitions( map disk, map conf );
map distribute_space( integer rest, list weights, list added, list ps );
void add_part_recursive( list ps, map g );
map normalize_gaps( list ps, map g );
integer do_weighting( list ps, map g );

symbol cur_mode = `free;
integer cur_weight = -10000;
map cur_gap = $[];

define string pinfo_name()
    ``{
    return( "/part.info" );
    }

define boolean has_flex_proposal()
    ``{
    boolean ret = (integer)SCR::Read( .target.size, pinfo_name() )>0;
    return( ret );
    }

define map try_add_boot( map conf, map disk )
    ``{
    boolean boot = 
	size(filter( map e, conf["partitions"]:[], 
		     ``(e["mount"]:""==Partitions::BootMount()))) > 0;
    boolean root = size(filter( map e, conf["partitions"]:[], 
				``(e["mount"]:""=="/"))) > 0;
    map tc = (map) eval(conf);
    if( !boot && root &&
	(disk["cyl_count"]:0 > Partitions::BootCyl() ||
	 Arch::ia64 () || Arch::ppc () || Arch::sparc ()) )
	{
	map pb = $[];
	pb["mount"] = Partitions::BootMount();
	pb["size"] = Partitions::MinimalNeededBootsize();
	pb["fsys"] = Partitions::DefaultBootFs();
	pb["id"] = Partitions::FsidBoot();
	pb["auto_added"] = true;
	pb["max_cyl"] = Partitions::BootCyl();
	tc["partitions"] = add( tc["partitions"]:[], pb );
	y2milestone( "boot added automagically pb %1", pb );
	}
    return( tc );
    }

define map do_flexible_disk( string dev, map disk )
    ``{
    y2milestone( "dev %1", dev );
    map ret = $[];
    ret["ok"] = false;
    map conf = read_partition_config( pinfo_name() );
    map solutions = $[];

    if( size(conf)>0 && Storage::IsRealDisk( dev, disk ))
	{
	y2milestone( "processing disk %1", dev );
	map tc = try_add_boot( conf, disk );
	cur_mode = `free;
	map gap = get_gap_info( disk, false );
	tc = add_cylinder_info( tc, gap );
	map sol = get_perfect_list( tc["partitions"]:[], gap );
	if( size(sol)>0 )
	    {
	    sol["disk"] = eval(disk);
	    ret["ok"] = true;
	    ret["disk"] = process_partition_data( dev, sol );
	    }
	}
    y2milestone( "ret %1", ret["ok"]:false );
    if( ret["ok"]:false )
	{
	y2milestone( "disk %1", ret["disk"]:[] );
	}
    return( ret );
    }


define map do_proposal_flexible( map<string,map> target )
    ``{
    map ret = $[];
    ret["ok"] = false;
    map conf = $[];
    if (ProductFeatures::flexible_partitioning)
        conf = read_partition_xml_config();
    else
        conf = read_partition_config( pinfo_name() );
    list<map> solutions = [];

    if( size(conf)>0 )
	{
	list<string> ddev = maplist( string k, map e, 
	                     filter( string l, map f, target, 
			             ``(Storage::IsRealDisk( l, f ))), ``(k));
	y2milestone( "ddev %1", ddev );
	map tc = $[];
	map<integer,any> dtmp = $[];
	foreach( map p, conf["partitions"]:[], 
	    ``{
	    integer dprio = p["disk"]:0;
	    if( haskey( dtmp, dprio ))
		{
		dtmp[dprio] = add( dtmp[dprio]:[], p );
		}
	    else
		{
		dtmp[dprio] = [ p ];
		}
	    });
	y2milestone( "dlist %1", dtmp );
	list dlist = maplist( integer k, any e, dtmp, ``(e) );
	y2milestone( "dlist %1", dlist );
	if( size(dlist)>size(ddev) )
	    {
	    integer idx = size(ddev);
	    while( idx<size(dlist) )
		{
		dlist[size(ddev)-1] = union( dlist[size(ddev)-1]:[], 
		                             dlist[idx]:[] );
		idx = idx+1;
		}
	    while( size(dlist)>size(ddev) )
		{
		dlist = remove( dlist, size(ddev) );
		}
	    y2milestone( "dlist %1", dlist );
	    }
	list save_dlist = (list) eval(dlist);
	repeat
	    {
	    integer count = 0;
	    repeat
		{
		list<string> td = eval(ddev);
		integer idx = 0;
		y2milestone( "start while count %1", count );
		while( idx<size(dlist) && count<size(dlist) )
		    {
		    y2milestone( "in while idx %1", idx );
		    tc = (map) eval(conf);
		    tc["partitions"] = eval( dlist[idx]:[] );
		    map md = find_matching_disk( td, target, tc );
		    y2milestone( "size(md) %1", size(md) );
		    if( size(md)>0 )
			{
			solutions = add( solutions, md );
			td = filter( string e, td, ``(e!=md["device"]:""));
			y2milestone( "new td %1", td );
			idx = idx+1;
			}
		    else
			{
			y2milestone( "no solution" );
			idx = size(dlist);
			td = eval(ddev);
			solutions = [];
			count = count + 1;
			if( size(dlist)>1 )
			    {
			    list tfi = dlist[0]:[];
			    dlist = remove( dlist, 0 );
			    dlist = add( dlist, tfi );
			    y2milestone( "new rotated dlist %1", dlist );
			    }
			}
		    }
		}
	    until( size(solutions)>0 || count>=size(dlist) );
	    if( size(solutions)==0 && size(dlist)>1 )
		{
		dlist = (list) eval(save_dlist);
		dlist[size(dlist)-2] = union( dlist[size(dlist)-2]:[],
					      dlist[size(dlist)-1]:[] );
		dlist = remove( dlist, size(dlist)-1 );
		y2milestone( "new truncated dlist %1", dlist );
		save_dlist = (list)eval(dlist);
		}
	    }
	until( size(solutions)>0 || size(dlist)<=1 );
	if( size(solutions)==0 &&
	    (size(conf["keep_partition_fsys"]:[])>0 ||
	     size(conf["keep_partition_id"]:[])>0 ||
	     size(conf["keep_partition_num"]:[])>0 ||
	     !conf["prefer_remove"]:false))
	    {
	    y2milestone( "desperate mode" );
	    tc = (map) eval(conf);
	    cur_mode = `desparate;
	    tc["keep_partition_fsys"] = [];
	    tc["keep_partition_id"] = [];
	    tc["keep_partition_num"] = [];
	    tc["prefer_remove"] = true;
	    map md = find_matching_disk( ddev, target, tc );
	    if( size(md)>0 )
		{
		solutions = add( solutions, md );
		}
	    }
	if( size(solutions)>0 )
	    {
	    foreach( map e, solutions,
		``{
		string disk = e["device"]:"";
		target[disk] = process_partition_data( disk, e );
		y2milestone( "solution disk %1 %2", disk, target[disk]:$[] );
		});
	    ret["ok"] = true;
	    target = Storage::SpecialBootHandling( target );
	    ret["target"] = Storage::DeleteDestroyedLvmVgs( target );
	    }
	}
    return( ret );
    }

define map find_matching_disk( list<string> disks, map target, map conf )
    ``{
    map<string,map> solutions = $[];

    cur_weight = -100000;
    cur_gap = $[];
    foreach( string k, disks,
	``{
	map e = target[k]:$[];
	y2milestone( "processing disk %1", k );
	y2milestone( "parts %1", conf["partitions"]:[] );
	map tc = try_add_boot( conf, e );
	cur_mode = `free;
	if( !tc["prefer_remove"]:false )
	    {
	    map gap = get_gap_info( e, false );
	    tc = add_cylinder_info( tc, gap );
	    map l = get_perfect_list( tc["partitions"]:[], gap );
	    if( size(l)>0 )
		{
		solutions[k] = eval(l);
		solutions[k,"disk"] = eval(e);
		}
	    cur_mode = `reuse;
	    map egap = get_gap_info( e, true );
	    if( size(egap["gap"]:[]) > size(gap["gap"]:[]) )
		{
		tc = add_cylinder_info( tc, egap );
		l = get_perfect_list( tc["partitions"]:[], egap );
		if( size(l)>0 && 
		    (!haskey(solutions,k) || 
		     (haskey( l, "weight" ) && 
		      l["weigth"]:0 > solutions[k,"weigth"]:0 )))
		    {
		    y2milestone( "solution reuse existing" );
		    solutions[k] = eval(l);
		    solutions[k,"disk"] = eval(e);
		    }
		}
	    cur_mode = `resize;
	    map rw = try_resize_windows( e );
	    if( size( filter( map p, rw["partitions"]:[],
			      ``(haskey(p, "winfo")) ))>0 )
		{
		egap = get_gap_info( rw, true );
		tc = add_cylinder_info( tc, egap );
		l = get_perfect_list( tc["partitions"]:[], egap );
		if( size(l)>0 && 
		    (!haskey(solutions,k) ||
		     (haskey( l, "weight" ) && 
		      l["weigth"]:0 > solutions[k,"weigth"]:0 )))
		    {
		    y2milestone( "solution resizing windows" );
		    solutions[k] = eval(l);
		    solutions[k,"disk"] = eval(rw);
		    }
		}
	    }
	else
	    {
	    cur_mode = `free;
	    map rp = remove_possible_partitions( e, tc );
	    map gap = get_gap_info( rp, false );
	    tc = add_cylinder_info( tc, gap );
	    map l = get_perfect_list( tc["partitions"]:[], gap );
	    if( size(l)>0 )
		{
		solutions[k] = eval(l);
		solutions[k,"disk"] = eval(rp);
		}
	    }
	});
    map ret = $[];
    if( size(solutions)>0 )
	{
	foreach( string k, map e, solutions,
	    ``{
	    y2milestone( "disk %1 weight %2", k, e["weight"]:0 );
	    });
	list<string> disks = maplist( string k, map e, solutions, ``(k) );
	disks = sort( string a, string b, disks, 
		      ``(solutions[a,"weight"]:0>solutions[b,"weight"]:0));
	y2milestone( "sorted disks %1", disks );
	ret = solutions[disks[0]:""]:$[];
	ret["device"] = disks[0]:"";
	}
    return( ret );
    }

define map process_partition_data( string dev, map solution )
    ``{
    map disk = solution["disk"]:$[];
    list<map> partitions = [];
    string value = "";
    boolean remove_boot = false;
    if( size( filter( map e, solution["partitions"]:[], 
              ``(e["mount"]:""==Partitions::BootMount() && 
	         e["auto_added"]:false)))>0 )
	{
	foreach( map e, solution["solution","gap"]:[],
	    ``{
	    foreach( list a, e["added"]:[],
		``{
		integer pindex = a[0]:0;
		if( solution["partitions",pindex,"mount"]:"" == "/" &&
		    disk["cyl_count"]:0 > Partitions::BootCyl() &&
		    e["end"]:0 <= Partitions::BootCyl() )
		    {
		    remove_boot = true;
		    }
		});
	    });
	}
    integer index = 0;
    if( remove_boot )
	{
	foreach( map e, solution["solution","gap"]:[],
	    ``{
	    list nlist = [];
	    foreach( list a, e["added"]:[],
		``{
		integer pindex = a[0]:0;
		if( solution["partitions",pindex,"mount"]:"" == 
		    Partitions::BootMount() )
		    {
		    integer rest = a[2]:0;
		    y2milestone( "remove unneeded %3 %1 cyl %2", 
		                 e["added"]:[], rest, Partitions::BootMount() );
		    list<list> nlist = filter( list l, e["added"]:[], ``(l[0]:0!=pindex));
		    if( size(nlist)>0 && !e["exists"]:false )
			{
			list weight = maplist( list l, nlist, ``(l[2]:0) );
			map r = $[];
			r = distribute_space( rest, weight, nlist, 
			                      solution["partitions"]:[] );
			nlist = eval(r["added"]:[]);
			solution["solution","gap",index,"cylinders"] = 
			    e["cylinders"]:0 - r["diff"]:0;
			}
		    solution["solution","gap",index,"added"] = eval(nlist);
		    y2milestone( "remove unneeded %2 %1", e["added"]:[],
		                 Partitions::BootMount() );
		    }
		pindex = pindex+1;
		});
	    index = index + 1;
	    });
	}
    index = 0;
    foreach( map e, solution["solution","gap"]:[],
	``{
	if( !e["exists"]:false && e["cylinders"]:0>0 )
	    {
	    integer increase = 0;
	    list<integer> weight = 
		maplist( list l, e["added"]:[], 
			 ``(solution["partitions",l[0]:0,"increasable"]:false ? 1 : 0) );
	    if( find( integer l, weight, ``(l>0) ) != nil ) 
		{
		map r = $[];
		r = distribute_space( e["cylinders"]:0, weight, e["added"]:[], 
		                      solution["partitions"]:[] );
		solution["solution","gap",index,"added"] = eval(r["added"]:[]);
		solution["solution","gap",index,"cylinders"] = 
		    e["cylinders"]:0 - r["diff"]:0;
		y2milestone( "increase increasable p %1 cyl %2", 
		             solution["solution","gap",index,"added"]:[],
		             solution["solution","gap",index,"cylinders"]:0 );
		}
	    }
        index = index + 1;
	});
    foreach( map e, solution["solution","gap"]:[],
	``{
	if( e["exists"]:false )
	    {
	    integer index = 0;
	    integer pindex = e["added",0,0]:0;
	    string mount = solution["partitions",pindex,"mount"]:"";
	    integer fsid = Partitions::fsid_native;
	    if( mount == "swap" )
		{
		fsid = Partitions::fsid_swap;
		}
	    if( solution["partitions",pindex,"id"]:0 != 0 )
		{
		fsid = solution["partitions",pindex,"id"]:0;
		}
	    foreach( map p, disk["partitions"]:[],
		``{
		if( !p["delete"]:false && p["nr"]:0 == e["added",0,1]:0 )
		    {
		    p["format"] = true;
		    p["mount"] = mount;
		    p["used_fs"] = solution["partitions",pindex,"fsys"]:`reiser;
		    value = solution["partitions",pindex,"fstopt"]:"";
		    if( size(value)>0 )
			{
			p["fstopt"] = value;
			}
		    else
			{
			p["fstopt"] = FileSystems::DefaultFstabOptions( p );
			}
		    value = solution["partitions",pindex,"fopt"]:"";
		    if( size(value)>0 )
			{
			p["format_opt"] = value;
			}
		    value = solution["partitions",pindex,"label"]:"";
		    if( size(value)>0 )
			{
			p["label"] = value;
			}
		    if( p["fsid"]:0 != fsid )
			{
			p["change_fsid"] = true;
			p["ori_fsid"] = p["fsid"]:0;
			p["fsid"] = fsid;
			}
		    disk["partitions",index] = p;
		    y2milestone( "reuse auto partition %1", p );
		    }
		index = index + 1;
		});
	    }
	else
	    {
	    list region = [ e["start"]:0, e["end"]:0-e["start"]:0+1 ];
	    map part = $[];
	    if( e["extended"]:false && e["created"]:0 > 0 )
		{
		part["create"] = true;
		part["nr"] = e["created"]:0;
		part["device"] = Storage::GetDeviceName( dev, part["nr"]:-1 );
		part["region"] = eval(region);
		part["type"] = `extended;
		part["fsid"] = Partitions::fsid_extended_win;
		part["fstype"] = Partitions::FsIdToString( part["fsid"]:0 );
		y2milestone( "extended auto partition %1", part );
		partitions = add( partitions, eval(part));
		}
	    foreach( list a, e["added"]:[],
		``{
		part = $[];
		integer pindex = a[0]:0;
		string mount = solution["partitions",pindex,"mount"]:"";
		integer fsid = Partitions::fsid_native;
		part["format"] = true;
		if( mount == "swap" )
		    {
		    fsid = Partitions::fsid_swap;
		    }
		if( solution["partitions",pindex,"id"]:0 != 0 )
		    {
		    fsid = solution["partitions",pindex,"id"]:0;
		    if( !haskey( solution["partitions",pindex]:$[], "fsys" ))
			{
			part["format"] = false;
			}
		    y2milestone( "partition id %1 format %2 part %3", fsid, 
		                 part["format"]:false, 
				 solution["partitions",pindex]:$[] );
		    }
		part["create"] = true;
		part["nr"] = a[1]:0;
		part["device"] = Storage::GetDeviceName( dev, part["nr"]:0 );
		region[1] = a[2]:0;
		part["region"] = eval(region);
		region[0] = region[0]:0 + region[1]:0;
		part["type"] = `primary;
		if( e["extended"]:false )
		    {
		    part["type"] = `logical;
		    }
		part["mount"] = mount;
		part["used_fs"] = 
		    solution["partitions",pindex,"fsys"]:`reiser;
		value = solution["partitions",pindex,"fstopt"]:"";
		if( size(value)>0 )
		    {
		    part["fstopt"] = value;
		    }
		else
		    {
		    part["fstopt"] = FileSystems::DefaultFstabOptions( part );
		    }
		value = solution["partitions",pindex,"fopt"]:"";
		if( size(value)>0 )
		    {
		    part["format_opt"] = value;
		    }
		value = solution["partitions",pindex,"label"]:"";
		if( size(value)>0 )
		    {
		    part["label"] = value;
		    }
		part["fsid"] = fsid;
		part["fstype"] = Partitions::FsIdToString( fsid );
		y2milestone( "auto partition %1", part );
		partitions = add( partitions, eval(part));
		});
	    partitions = sort( map a, map b, partitions, ``(a["nr"]:0<b["nr"]:0));
	    }
	});
    disk["partitions"] = union( disk["partitions"]:[], partitions );
    y2milestone( "disk %1", disk );
    return( disk );
    }

define map add_cylinder_info( map conf, map gap )
    ``{
    integer big_cyl = 4 * 1024 * 1024 * 1024;
    integer cyl_size = gap["cyl_size"]:1;
    conf["partitions"] = 
	sort( map a, map b, conf["partitions"]:[],
	      ``({
	      if( a["max_cyl"]:big_cyl != b["max_cyl"]:big_cyl )
		  return( a["max_cyl"]:big_cyl < b["max_cyl"]:big_cyl );
	      else
		  return( a["size"]:0 > b["size"]:0 );
	      }));
    y2milestone( "parts %1", conf["partitions"]:[] );
    integer sum = 0;
    conf["partitions"] = maplist( map p, conf["partitions"]:[],
	``{
	sum = sum + p["pct"]:0;
	p["cylinders"] = (p["size"]:0+cyl_size-1)/cyl_size;
	if( p["cylinders"]:0 == 0 )
	    {
	    p["cylinders"] = 1;
	    }
	return( p );
	});
    y2milestone( "sum %1", sum );
    y2milestone( "parts %1", conf["partitions"]:[] );
    if( sum>100 )
	{
	integer rest = sum - 100;
	conf["partitions"] = maplist( map p, conf["partitions"]:[],
	    ``{
	    if( haskey( p, "pct" ) )
		{
		integer pct = p["pct"]:0;
		integer diff = ((rest * pct) + sum/2) / sum;
		sum = sum - pct;
		rest = rest - diff;
		p["pct"] = pct - diff;
		}
	    return( p );
	    });
	}
    conf["partitions"] = maplist( map p, conf["partitions"]:[],
	``{
	if( haskey( p, "pct" ) )
	    {
	    integer cyl = gap["sum"]:0 / 100 * p["pct"]:0;
	    cyl = (cyl+cyl_size/2) / cyl_size;
	    if( cyl == 0 )
		{
		cyl = 1;
		}
	    p["want_cyl"] = cyl;
	    }
	if( p["max"]:0 > 0 )
	    {
	    integer cyl = (p["max"]:0+cyl_size-1) / cyl_size;
	    p["size_max_cyl"] = cyl;
	    if( p["want_cyl"]:0 > cyl )
		{
		p["want_cyl"] = cyl;
		}
	    }
	return( p );
	});
    y2milestone( "parts %1", conf["partitions"]:[] );
    return( conf );
    }

define map get_perfect_list( list ps, map g )
    ``{
    y2milestone( "ps %1", ps );
    y2milestone( "gap %1", g );
    if( size(g["gap"]:[])>0 &&
        ((g["extended_possible"]:false && 
	    size(g["free_pnr"]:[])>0 &&
	    size(ps)+1 <= size(g["ext_pnr"]:[])+size(g["free_pnr"]:[])) ||
	 (!g["extended_possible"]:false &&
	    size(ps) <= size(g["ext_pnr"]:[])+size(g["free_pnr"]:[]))) )
	{
	map lg = (map) eval(g);
	lg["gap"] = maplist( map e, lg["gap"]:[], 
	    ``{ 
	    e["orig_cyl"] = e["cylinders"]:0;
	    e["added"] = [];
	    return( e );
	    });
	lg["procpart"] = 0;
	list lp = (list) eval(ps);
	if( g["extended_possible"]:false && size(ps)+1>=size(g["free_pnr"]:[]))
	    {
	    y2milestone( "creating extended" );
	    integer index = 0;
	    foreach( map e, lg["gap"]:[], 
		``{
		if( !e["exists"]:false )
		    {
		    map gap = (map) eval(lg);
		    gap["gap",index,"created"] = gap["free_pnr",0]:1;
		    gap["free_pnr"] = remove( gap["free_pnr"]:[1], 0 );
		    gap["gap",index,"extended"] = true;
		    add_part_recursive( ps, gap );
		    }
		index = index+1;
		});
	    }
	else
	    {
	    y2milestone( "not creating extended" );
	    add_part_recursive( ps, lg );
	    }
	}
    map ret = $[];
    if( size(cur_gap)>0 )
	{
	ret["weight"] = cur_weight;
	ret["solution"] = eval(cur_gap);
	ret["partitions"] = eval(ps);
	}
    y2milestone( "ret weight %1", ret["weight"]:-1000000 );
    y2milestone( "ret solution %1", ret["solution","gap"]:[] );
    return( ret );
    }

define void add_part_recursive( list ps, map g )
    ``{
    y2milestone( "pindex %1", g["procpart"]:0 );
    y2milestone( "ps %1", ps );
    y2milestone( "gap %1", g );
    map lg = (map) eval(g);
    integer gindex = 0;
    integer pindex = lg["procpart"]:0;
    map part = ps[pindex]:$[];
    lg["procpart"] = pindex + 1;
    y2milestone( "p %1", part );
    foreach( map e, lg["gap"]:[], 
	``{
	y2milestone( "e %1", e );
	if( part["max_cyl"]:0 <= e["end"]:0 &&
	    part["cylinders"]:0 <= e["cylinders"]:0 &&
	    (!e["extended"]:false && size(lg["free_pnr"]:[])>0 ||
	      e["extended"]:false && size(lg["ext_pnr"]:[])>0))
	    {
	    map llg = (map) eval(lg);
	    if( e["exists"]:false )
		{
		llg["gap",gindex,"cylinders"] = 0;
		}
	    else
		{
		llg["gap",gindex,"cylinders"] = 
		    llg["gap",gindex,"cylinders"]:0 - part["cylinders"]:0;
		}
	    list addl = [ pindex ];
	    if( e["extended"]:false )
		{
		addl = add( addl, llg["ext_pnr",0]:5 );
		llg["ext_pnr"] = remove( llg["ext_pnr"]:[0], 0 );
		}
	    else
		{
		addl = add( addl, llg["free_pnr",0]:1 );
		llg["free_pnr"] = remove( llg["free_pnr"]:[0], 0 );
		}
	    llg["gap",gindex,"added"] = 
		add( llg["gap",gindex,"added"]:[], addl );
	    if( pindex+1 < size(ps) )
		{
		add_part_recursive( ps, llg );
		}
	    else
		{
		map ng = normalize_gaps(ps, llg);
		integer val = do_weighting( ps, ng );
		y2milestone( "val %1 cur_weight %2 size %3", val, cur_weight, 
		             size(cur_gap));
		if( val > cur_weight || size(cur_gap)==0 )
		    {
		    cur_weight = val;
		    cur_gap = (map)eval(ng);
		    }
		}
	    }
	gindex = gindex+1;
	});
    };

define map normalize_gaps( list ps, map g )
    ``{
    y2milestone( "gap %1", g );
    integer gindex = 0;
    integer pindex = 0;
    foreach( map e, g["gap"]:[],
	``{
	y2milestone( "e %1", e );
	if( e["exists"]:false )
	    {
	    if( size(e["added"]:[])>0 && size(e["added",0]:[])==2 )
		{
		e["added",0] = add( e["added",0]:[], e["orig_cyl"]:1 );
		}
	    }
	else
	    {
	    integer rest = e["cylinders"]:0;
	    integer needed = 0;
	    integer tidx = 0;
	    foreach( list p, e["added"]:[],
		``{
		tidx = p[0]:0;
		if( ps[tidx,"want_cyl"]:0 > ps[tidx,"cylinders"]:0 )
		    {
		    needed = needed + ps[tidx,"want_cyl"]:0 -
		             ps[tidx,"cylinders"]:0;
		    }
		});
	    y2milestone( "needed %1 rest %2", needed, rest );
	    if( needed > rest )
		{
                list tr = [];
		list weight = 
		    maplist( list l, e["added"]:[], 
			     ``({
			     integer idx = l[0]:0;
			     integer d = ps[idx,"want_cyl"]:0 - 
			                 ps[idx,"cylinders"]:0;
                             if( d>0 )
				 {
				 l = add( l, ps[idx,"cylinders"]:0 );
				 }
			     tr = add( tr, l );
			     return( d>0 ? d : 0 );
			     }));
	        y2milestone( "tr %1", tr );
		map r = $[];
		r = distribute_space( rest, weight, tr, ps );
		g["gap",gindex,"added"] = eval(r["added"]:[]);
		g["gap",gindex,"cylinders"] = e["cylinders"]:0 - r["diff"]:0;
		y2milestone( "partly satisfy %1 cyl %2", g["gap",gindex,"added"]:[],
			     g["gap",gindex,"cylinders"]:0 );
		}
	    else
		{
		g["gap",gindex,"cylinders"] = e["cylinders"]:0 - needed;
		}

	    pindex = 0;
	    foreach( list p, g["gap",gindex,"added"]:[], 
		``{
		if( size(p)<3 )
		    {
		    tidx = p[0]:0;
		    if( ps[tidx,"want_cyl"]:0 > ps[tidx,"cylinders"]:0 )
			{
			p = add( p, ps[tidx,"want_cyl"]:0 );
			}
		    else
			{
			p = add( p, ps[tidx,"cylinders"]:0 );
			}
		    g["gap",gindex,"added",pindex] = p;
		    y2milestone( "satisfy p %1 cyl %2", p, e["cylinders"]:0 );
		    }
		pindex = pindex+1;
		});
	    y2milestone( "added %1", g["gap",gindex,"added"]:[] );
	    }
	gindex = gindex + 1;
	});
    gindex = 0;
    foreach( map e, g["gap"]:[],
	``{
	if( !e["exists"]:false && e["cylinders"]:0>0 )
	    {
	    list<integer> weight = maplist( list l, e["added"]:[], 
	                           ``(ps[l[0]:0,"size"]:0==0 ? 1 : 0) );
	    if( find( integer l, weight, ``(l>0) ) != nil ) 
		{
		map r = $[];
		r = distribute_space( e["cylinders"]:0, weight, e["added"]:[], 
		                      ps );
		g["gap",gindex,"added"] = eval(r["added"]:[]);
		g["gap",gindex,"cylinders"] = e["cylinders"]:0 - r["diff"]:0;
		y2milestone( "increase max p %1 cyl %2", g["gap",gindex,"added"]:[], 
		             g["gap",gindex,"cylinders"]:0 );
		}
	    }
	gindex = gindex + 1;
	});
    gindex = 0;
    foreach( map e, g["gap"]:[],
	``{
	if( !e["exists"]:false && e["cylinders"]:0>0 && 
	    e["cylinders"]:0 < g["disk_cyl"]:0/20 )
	    {
	    list weight = maplist( list l, e["added"]:[], ``(l[2]:0) );
	    map r = $[];
	    r = distribute_space( e["cylinders"]:0, weight, e["added"]:[], ps );
	    g["gap",gindex,"added"] = eval(r["added"]:[]);
	    g["gap",gindex,"cylinders"] = e["cylinders"]:0 - r["diff"]:0;
	    y2milestone( "close small gap p %1 cyl %2", g["gap",gindex,"added"]:[], 
	                 g["gap",gindex,"cylinders"]:0 );
	    }
	gindex = gindex + 1;
	});
    y2milestone( "gap %1", g );
    return( g );
    };

define map distribute_space( integer rest, list weights, list added, list ps )
    ``{
    integer diff_sum = 0;
    integer sum = 0;
    integer index = 0;
    integer pindex = 0;
    y2milestone( "rest %1 weights %2 added %3", rest, weights, added );
    foreach( list p, (list<list>)added,
	``{
	pindex = p[0]:0;
	if( ps[pindex,"size_max_cyl"]:0==0 || ps[pindex,"increasable"]:false ||
	    ps[pindex,"size_max_cyl"]:0 > p[2]:0 )
	    {
	    sum = sum + weights[index]:0;
	    }
	index = index+1;
	});
    index = 0;
    y2milestone( "sum %1 rest %2 added %3", sum, rest, added );
    foreach( list p, (list<list>)added,
	``{
	pindex = p[0]:0;
	if( size(p)==3 && sum>0 &&
            (ps[pindex,"size_max_cyl"]:0==0 || ps[pindex,"increasable"]:false ||
	     ps[pindex,"size_max_cyl"]:0 > p[2]:0) )
	    {
	    integer diff = ((rest*weights[index]:0) + sum/2) / sum;
	    if( ps[pindex,"size_max_cyl"]:0>0 && 
	        !ps[pindex,"increasable"]:false &&
	        diff > ps[pindex,"size_max_cyl"]:0-p[2]:0 )
		{
		diff = ps[pindex,"size_max_cyl"]:0-p[2]:0;
		}
	    sum = sum - weights[index]:0;
	    rest = rest - diff;
	    added[index,2] = added[index,2]:0 + diff;
	    diff_sum = diff_sum + diff;
	    y2milestone( "sum %1 rest %2 diff %3 added %4", sum, rest, diff, 
	                 added[index]:[] );
	    }
	index = index+1;
	});
    map ret = $[ "added":added, "diff" : diff_sum ];
    y2milestone( "ret %1", ret );
    return( ret );
    }

define integer do_weighting( list ps, map g )
    ``{
    y2milestone( "gap %1", g["gap"]:[] );
    integer ret = 0;
    integer index = 0;
    if( cur_mode == `free )
	{
	ret = 0;
	}
    if( cur_mode == `reuse )
	{
	ret = ret - 100;
	}
    else if( cur_mode == `resize )
	{
	ret = ret - 1000;
	}
    else if( cur_mode == `desparate )
	{
	ret = ret - 1000000;
	}
    y2milestone( "after mode ret %1", ret );
    foreach( map e, g["gap"]:[],
	``{
	y2milestone( "added %1", e["added"]:[] );
	if( !e["exists"]:false && e["cylinders"]:0 > 0 )
	    {
	    ret = ret - 5;
	    if( e["cylinders"]:0 < g["disk_cyl"]:0/20 )
		{
		ret = ret - 10;
		}
	    }
	y2milestone( "after gaps %1", ret );
	foreach( list p, e["added"]:[], 
	    ``{
	    index = p[0]:0;
	    if( e["exists"]:false && ps[index,"mount"]:""=="swap" && 
	        e["swap"]:false )
		{
		ret = ret + 100;
		y2milestone( "after swap reuse %1", ret );
		}
	    if( ps[index,"want_cyl"]:0>0 )
		{
		integer diff = ps[index,"want_cyl"]:0 - p[2]:0;
		integer normdiff = diff * 100 / p[2]:0;
		if( diff < 0 )
		    {
		    normdiff = -normdiff;
		    }
		else if( diff > 0 )
		    {
		    normdiff = normdiff / 10;
		    }
		ret = ret - normdiff;
		ret = ret + ps[index,"want_cyl"]:0*g["cyl_size"]:1 / 
		            (100 * 1024 * 1024);
		y2milestone( "after pct parts %1", ret );
		}
	    if( ps[index,"size"]:0==0 )
		{
		ret = ret + p[2]:0 * g["cyl_size"]:1 / (50 * 1024 * 1024);
		y2milestone( "after maximizes parts %1", ret );
		}
	    if( ps[index,"size_max_cyl"]:0 > 0 && 
		ps[index,"size_max_cyl"]:0 < p[2]:0 )
		{
		integer diff = p[2]:0 - ps[index,"size_max_cyl"]:0;
		integer normdiff = diff * 100 / ps[index,"size_max_cyl"]:0;
		ret = ret - normdiff;
		y2milestone( "after maximal size %1", ret );
		}
	    });
	if( e["cylinders"]:0 > 0 )
	    {
	    ret = ret - (e["cylinders"]:0 * g["cyl_size"]:1) / (1024*1024*1024);
	    }
	});
    y2milestone( "ret %1", ret );
    return( ret );
    };

define map remove_possible_partitions( map disk, map conf )
    ``{
    list nodelpart = [ 0x12, 0xde, 257 ];
    map ret = (map)eval(disk);
    ret["partitions"] = maplist( map p, ret["partitions"]:[],
	``{
	integer fsid = p["fsid"]:0;
	if( (conf["remove_special_partitions"]:false ||
		!contains( nodelpart, fsid ) ) &&
	    p["type"]:`primary != `extended &&
	    !contains( conf["keep_partition_num"]:[], p["nr"]:0 ) &&
	    !contains( conf["keep_partition_id"]:[], fsid ) &&
	    !contains( conf["keep_partition_fsys"]:[], p["used_fs"]:`none ))
	    {
	    p["delete"] = true;
	    }
	return( p );
	});
    integer max_prim = Partitions::MaxPrimary(disk["label"]:"msdos");
    if( size( filter( map p, ret["partitions"]:[], 
		      ``(p["type"]:`primary == `extended)))>0 &&
	size( filter( map p, ret["partitions"]:[], 
		      ``(p["nr"]:0>max_prim && !p["delete"]:false) ))==0 )
	{
	ret["partitions"] = maplist( map p, ret["partitions"]:[],
	    ``{
	    if( p["type"]:`primary == `extended )
		{
		p["delete"] = true;
		}
	    return( p );
	    });
	}
    return( ret );
    };

define map try_resize_windows( map disk )
    ``{
    integer cyl_size = disk["cyl_size"]:1;
    map win = $[];
    map ret = (map)eval(disk);

    ret["partitions"] = maplist( map p, ret["partitions"]:[],
	``{
	integer fsid = p["fsid"]:0;
	if( Partitions::IsDosPartition( fsid ) ) 
	    {
	    integer psize = (p["region",0]:0 + p["region",1]:1 - 1) * cyl_size;
	    win = FileSystems::GetFreeSpace( p["device"]:"", psize, `fat32, 
	                                     false );
	    y2milestone( "win=%1", win );
	    if( win != nil && psize > 300*1024*1024 )
		{
		p["winfo"] = win;
		p["region",1] = (win["new_size"]:0 + cyl_size - 1) / cyl_size;
		y2milestone( "win part %1", p );
		}
	    }
	return( p );
	});
    return( ret );
    };

define list<map> get_gaps( integer start, integer end, list<map> part, 
		      boolean add_exist_linux )
    ``{
    y2milestone( "start %1 end %2 add_exist %3", start, end, add_exist_linux );
    list<map> ret = [];
    map entry = $[];
    foreach( map p, part, 
	``{
	integer s = p["region",0]:0;
	integer e = s + p["region",1]:1 - 1;
	entry = $[];
	y2milestone( "start %1 s %2 e %3", start, s, e );
	if( start < s )
	    {
	    entry["start"] = start;
	    entry["end"] = s-1;
	    ret = add( ret, eval(entry) );
	    }
	if( add_exist_linux && 
	    (p["fsid"]:0==Partitions::fsid_native || 
	     p["fsid"]:0==Partitions::fsid_swap) )
	    {
	    entry["swap"] = p["fsid"]:0==Partitions::fsid_swap;
	    entry["start"] = s;
	    entry["end"] = e;
	    entry["exists"] = true;
	    entry["nr"] = p["nr"]:0;
	    ret = add( ret, entry );
	    }
	start = e+1;
	});
    if( start < end )
	{
	entry = $[];
	entry["start"] = start;
	entry["end"] = end;
	ret = add( ret, entry );
	}
    y2milestone( "ret %1", ret );
    return( ret );
    }


define map get_gap_info( map disk, boolean add_exist_linux )
    ``{
    map ret = $[];
    list<map> gap = [];
    list<map> plist = filter( map p, disk["partitions"]:[], ``(!p["delete"]:false) );
    plist = sort( map a, map b, plist, ``(a["region",0]:0<b["region",0]:0) );
    list exist_pnr = sort( maplist( map e, plist, ``(e["nr"]:0) ));
    integer max_prim = Partitions::MaxPrimary(disk["label"]:"msdos");
    boolean has_ext = Partitions::HasExtended( disk["label"]:"msdos" );
    if( has_ext )
	{
	map ext = filter( map p, plist,
			  ``(p["type"]:`primary == `extended))[0]:$[];
	ret["extended_possible"] = size(ext)==0;
	if( size(ext)>0 )
	    {
	    gap = get_gaps( ext["region",0]:0, 
			    ext["region",0]:0 + ext["region",1]:1-1, 
			    filter( map p, plist, ``(p["nr"]:0>max_prim)),
			    add_exist_linux );
	    gap = maplist( map e, gap, 
		``{
		e["extended"]=true;
		return e;
		});
	    plist = filter( map p, plist, ``(p["nr"]:0<=max_prim));
	    }
	}
    else
	{
	ret["extended_possible"] = false;
	}
    gap = (list<map>)union( gap, 
		 get_gaps( 0, disk["cyl_count"]:1-1, plist, add_exist_linux ));
    integer av_size = 0;
    gap = maplist( map e, gap,
	``{
	e["cylinders"] = e["end"]:0 - e["start"]:0 + 1;
	e["size"] = e["cylinders"]:0 * disk["cyl_size"]:1;
	av_size = av_size + e["size"]:0;
	return( e );
	});
    gap = maplist( map e, gap,
	``{
	e["sizepct"] = (e["size"]:0 * 201 / 2) / av_size;
	if( e["sizepct"]:0 == 0 )
	    {
	    e["sizepct"] = 1;
	    }
	return( e );
	});
    ret["cyl_size"] = disk["cyl_size"]:1;
    ret["disk_cyl"] = disk["cyl_count"]:1;
    ret["sum"] = av_size;
    integer max_pnr = max_prim;
    integer pnr = 1;
    list free_pnr = [];
    y2milestone( "exist_pnr %1", exist_pnr );
    while( pnr<=max_pnr )
	{
	if( !contains( exist_pnr, pnr ) )
	    {
	    free_pnr = add( free_pnr, pnr );
	    }
	pnr = pnr + 1;
	}
    ret["free_pnr"] = free_pnr;
    list<integer> ext_pnr = [ 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
		    25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,
		    45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63];
    integer max_logical = disk["max_logical"]:15;
    if( max_logical<63 )
	{
	ext_pnr = filter( integer i, ext_pnr, ``(i<=max_logical));
	}
    if( !ret["extended_possible"]:false )
	{
	if( !has_ext )
	    {
	    ext_pnr = [];
	    }
	else
	    {
	    integer maxext = exist_pnr[size(exist_pnr)-1]:4;
	    pnr = 5;
	    while( pnr<=maxext )
		{
		ext_pnr = remove( ext_pnr, 0 );
		pnr = pnr+1;
		}
	    }
	}
    ret["ext_pnr"] = ext_pnr;
    ret["gap"] = gap;
    y2milestone( "ret %1", ret );
    return( ret );
    }

/**
 * Read partition data from XML control file
 * @return map flexible propsal map
 */
define map read_partition_xml_config()
    ``{

    map xmlflex = ProductFeatures::FlexiblePartitioning;
    y2debug("xml input: %1", xmlflex );

    map conf = $[];
    conf["prefer_remove"] = xmlflex["prefer_remove"]:true;
    conf["remove_special_partitions"] =
	xmlflex["remove_special_partitions"]:false;
    conf["keep_partition_id"] = [];
    conf["keep_partition_num"] = [];
    conf["keep_partition_fsys"] = [];

    foreach( string key, [ "keep_partition_id", "keep_partition_num"], ``{
	list num = [];
	list<string> nlist = splitstring(xmlflex[key]:"", ",");
	foreach( string n, nlist, ``{ num = union( num, [tointeger(n)] );});
	conf[key] = num;
    });

    list fsys = [];
    list<string> nlist = splitstring( xmlflex["keep_partition_fsys"]:"" , "," );
    foreach( string n, nlist,
	     ``{
	symbol fs = FileSystems::FsToSymbol(n);
	if( fs != `none )
	{
	    fsys = union( fsys, [ fs ] );
	}
    });
    conf["keep_partition_fsys"] = fsys;
    list partitions = [];
    foreach(map p, xmlflex["partitions"]:[],
	    ``{
	map partition = $[];

	if (p["disk"]:0 != 0)
	{
	    partition["disk"] = p["disk"]:0;
	}
	if (p["id"]:0 != 0)
	{
	    partition["id"] = p["id"]:0;
	}

	if (p["fstopt"]:"" != "")
	{
	    partition["fstopt"] = p["fstopt"]:"";
	}

	if (p["formatopt"]:"" != "")
	{
	    partition["fopt"] = p["formatopt"]:"";
	}

	partition["increasable"] = p["increasable"]:false;

	if (p["mount"]:"" != "")
	{
	    partition["mount"] = p["mount"]:"";
	}

	if (p["percent"]:-1 != -1)
	{
	    partition["pct"] = p["percent"]:100;
	}

	if (p["label"]:"" != "")
	{
	    partition["label"] = p["label"]:"";
	}

	if (p["maxsize"]:"" != "")
	{
	    partition["maxsize"] = kmgt_str_to_byte(p["maxsize"]:"");
	}

	if (p["fsys"]:"" != "")
	{
	    symbol fs = FileSystems::FsToSymbol(p["fsys"]:"");
	    if( fs != `none )
	    {
		partition["fsys"] = fs;
	    }
	}

	if (p["size"]:"" != "")
	{
	    string s = p["size"]:"";
	    if( tolower(s) == "auto" )
	    {
		partition["size"] = -1;
	    }
	    else if( tolower(s) == "max" )
	    {
		partition["size"] = 0;
	    }
	    else
	    {
		partition["size"] = kmgt_str_to_byte( s );
	    }

	}

	if( partition["size"]:0 == -1 && partition["mount"]:"" == "swap" )
	{
	    partition["size"] = 1024*1024*Partitions::SwapSizeMb(0);
	}
	if( partition["mount"]:"" == Partitions::BootMount() )
	{
	    if( partition["size"]:0 == -1 )
	    {
		partition["size"] = Partitions::MinimalNeededBootsize();
	    }
	    if( partition["fsys"]:`none == `none )
	    {
		partition["fsys"] = Partitions::DefaultBootFs();
	    }
	    if( partition["id"]:0 == 0 )
	    {
		partition["id"] = Partitions::FsidBoot();
	    }
	    partition["max_cyl"] = Partitions::BootCyl();
	}
	if( partition["size"]:0 == -1 )
	{
	    partition["size"] = 0;
	}

	y2debug("partition: %1", partition);
	if( size(partition["mount"]:"")>0 || partition["id"]:0 > 0 )
	{
	    partitions = add( partitions, partition );
	}


    });
    conf["partitions"] = partitions;
    if( size(partitions)==0 )
    {
	conf = $[];
    }
    else
    {
	conf["partitions"] = partitions;
    }
    y2milestone( "conf %1", conf );
    return( conf );



}


define map read_partition_config( string fpath )
    ``{
    integer pos = 0;
    string line = "";
    string rex = "";
    map conf = $[];

    conf["prefer_remove"] = true;
    conf["remove_special_partitions"] = false;
    conf["keep_partition_id"] = [];
    conf["keep_partition_num"] = [];
    conf["keep_partition_fsys"] = [];

    string cstring = (string) SCR::Read( .target.string, fpath );
    list<string> lines = filter( string e, splitstring( cstring, "\n" ), ``(size(e)>0) );
    rex = "[ \t]*#.*";
    y2milestone( "lines %1", lines );
    lines = filter( string e, lines, ``(!regexpmatch( e, "[ \t]*#.*" )));
    y2milestone( "lines %1", lines );
    list fnd = [];
    foreach( string key, [ "PREFER_REMOVE", "REMOVE_SPECIAL_PARTITIONS" ],
	``{
	rex = "[ \t]*" + key + "[ \t]*=";
	fnd = filter( string e, lines, ``(regexpmatch( e, rex )));
	y2milestone( "rex %1 fnd %2", rex, fnd );
	if( size(fnd)>0 )
	    {
	    line = deletechars( fnd[size(fnd)-1]:"", "\t " );
	    pos = findlastof( line, "=" );
	    if( pos > 0 )
		{
		conf[tolower(key)] = tointeger( substring( line, pos+1 ))>0;
		}
	    }
	});
    foreach( string key, [ "KEEP_PARTITION_ID", "KEEP_PARTITION_NUM" ],
	``{
	rex = "[ \t]*" + key + "[ \t]*=";
	y2milestone( "rex %1", rex );
	foreach( string l, filter( string e, lines, ``(regexpmatch( e, rex ))),
	    ``{
	    y2milestone( "line %1", l );
	    line = deletechars( l, "\t " );
	    pos = findlastof( line, "=" );
	    if( pos > 0 )
		{
		list num = [];
		list<string> nlist = splitstring( substring( line, pos+1 ), "," );
		foreach( string n, nlist, ``{ num = union( num, [tointeger(n)] );});
		conf[tolower(key)] = union( conf[tolower(key)]:[], num );
		}
	    });
	});
    list fsys = [];
    rex = "[ \t]*" + "KEEP_PARTITION_FSYS" + "[ \t]*=";
    foreach( string l, filter( string e, lines, ``(regexpmatch( e, rex ))),
	``{
	y2milestone( "line %1", l );
	line = deletechars( l, "\t " );
	pos = findlastof( line, "=" );
	if( pos > 0 )
	    {
	    list<string> nlist = splitstring( substring( line, pos+1 ), "," );
	    foreach( string n, nlist, 
		``{ 
		symbol fs = FileSystems::FsToSymbol(n);
		if( fs != `none )
		    {
		    fsys = union( fsys, [ fs ] );
		    }
		});
	    }
	});
    conf["keep_partition_fsys"] = fsys;
    list partitions = [];
    map part = $[];
    rex = "[ \t]*" + "PARTITION" + "[ \t][ \t]*";
    foreach( string l, filter( string e, lines, ``(regexpmatch( e, rex ))),
	``{
	y2milestone( "line %1", l );
	string par = "";
	string key = "";
	integer pos = find( l, "PARTITION" );
	line = substring( l, pos+10 );
	y2milestone( "line %1", line );
	pos = find( line, "=" );
	part = $[];
	while( pos!=-1 )
	    {
	    key = deletechars( substring( line, 0, pos ), " \t" );
	    line = substring( line, pos+1 );
	    if( substring( line, 0, 1 ) == "\"" )
		{
		line = substring( line, 1 );
		pos = find( line, "\"" );
		par = substring( line, 0, pos );
		line = substring( line, pos+1 );
		}
	    else
		{
		pos = findfirstof( line, " \t" );
		if( pos==nil )
		    {
		    par = line;
		    }
		else
		    {
		    par = substring( line, 0, pos );
		    line = substring( line, pos+1 );
		    }
		}
	    y2debug( "key %1 par \"%2\"", key, par );
	    if( key == "id" )
		{
		part[key] = tointeger(par);
		}
	    else if( key == "mount" )
		{
		part[key] = par;
		}
	    else if( key == "increasable" )
		{
		part["increasable"] = tointeger(par)>0 ? true : false;
		}
	    else if( key == "size" )
		{
		if( tolower(par) == "auto" )
		    {
		    part["size"] = -1;
		    }
		else if( tolower(par) == "max" )
		    {
		    part["size"] = 0;
		    }
		else
		    {
		    part["size"] = kmgt_str_to_byte( par );
		    }
		}
	    else if( key == "label" )
		{
		part[key] = par;
		}
	    else if( key == "maxsize" )
		{
		part["max"] = kmgt_str_to_byte( par );
		}
	    else if( key == "sizepct" )
		{
		part["pct"] = tointeger(par);
		}
	    else if( key == "disk" )
		{
		part[key] = tointeger(par);
		}
	    else if( key == "fsys" )
		{
		symbol fs = FileSystems::FsToSymbol(par);
		if( fs != `none )
		    {
		    part[key] = fs;
		    }
		}
	    else if( key == "fstopt" )
		{
		part[key] = par;
		}
	    else if( key == "formatopt" )
		{
		part["fopt"] = par;
		}
	    pos = find( line, "=" );
	    }
	y2milestone( "part %1", part );
	if( part["size"]:0 == -1 && part["mount"]:"" == "swap" )
	    {
	    part["size"] = 1024*1024*Partitions::SwapSizeMb(0);
	    }
	if( part["mount"]:"" == Partitions::BootMount() )
	    {
	    if( part["size"]:0 == -1 )
		{
		part["size"] = Partitions::MinimalNeededBootsize();
		}
	    if( part["fsys"]:`none == `none )
		{
		part["fsys"] = Partitions::DefaultBootFs();
		}
	    if( part["id"]:0 == 0 )
		{
		part["id"] = Partitions::FsidBoot();
		}
	    part["max_cyl"] = Partitions::BootCyl();
	    }
	if( part["size"]:0 == -1 )
	    {
	    part["size"] = 0;
	    }
	if( size(part["mount"]:"")>0 || part["id"]:0 > 0 )
	    {
	    partitions = add( partitions, part );
	    }
	});
    conf["partitions"] = partitions;
    if( size(partitions)==0 )
	{
	conf = $[];
	}
    else
	{
	conf["partitions"] = partitions;
	}
    y2milestone( "conf %1", conf );
    return( conf );
    }

}

