/*
 *************************************************************
 *
 *     YaST2      SuSE Labs                        -o)
 *     --------------------                        /\\
 *                                                _\_v
 *           www.suse.de / www.suse.com
 * ----------------------------------------------------------
 *
 * Author:        Michael Hager <mike@suse.de>
 *
 * Description:   Partitioner for experts.
 *
 *
 * Purpose:
 *                      -Determing possible partitions.
 *                      -Ask the user which partition to use.
 *                      -Check the input and return error-messages.
 *                      -Writing user_settings with the selected partitions.
 *
 * user_settings:       used:   targets
 *
 * external function:   get_partition_info: get a list of current partitions
 *                      check4partitions:   read the disk-information
 *
 *
 *************************************************************

 $Id: inst_custom_part.ycp 22755 2005-03-23 12:15:03Z fehr $

HINTS: Always use
         lookup( part, "delete", false)
         lookup( part, "create", false)
       instead of
         lookup( part, "delete")
         lookup( part, "create")
       cause delete, create are not always set to  false

*/
{
  textdomain "storage";

  import "Arch";
  /* FIXME import "Bootloader";*/
  import "Installation";
  import "Mode";
  import "Wizard";
  import "Storage";
  import "FileSystems";
  import "Partitions";
  import "Package";
  
  import "Label";
  import "Popup";
  import "String";
  import "Storage";
  import "StorageDevices";
  import "ProductFeatures";

  list    hitlist = [];
  boolean hiterror = false;

  include "partitioning/partition_defines.ycp";
  include "partitioning/propose_part_util.ycp";
  include "partitioning/loop.ycp";
  include "partitioning/lvm_ui_dialogs.ycp";
  include "partitioning/lvm_pv_lib.ycp";
  include "partitioning/raid_lib.ycp";
  include "partitioning/raid_ui.ycp";
  include "partitioning/custom_part_lib.ycp";
  include "partitioning/custom_part_dialogs.ycp";
  include "partitioning/custom_part_check_generated.ycp";
  include "partitioning/evms_lib.ycp";

  
  // Which columns show the main window have
  boolean showT_dev 		  = true;      // show /dev/hda1
  boolean showT_id 		  = false;     // s390 show FD01
  boolean showT_cyl 		  = true;      // show start and endcyl
  boolean showT_size 		  = true;      // show size of partition
  boolean showT_format 		  = true;      // show format flag
  boolean showT_fs 		  = true;      // show filesystem
  boolean showT_mount 		  = true;      // show mountpoint
  boolean showT_Used		  = true;      // show using entity 
  boolean showT_Label             = true;      // show assigned label
  
  boolean show_disk               = true;
  boolean edit_cylinder           = true;
  boolean bsd_label               = false;


  boolean button_resize 	  = true;    // Should the "Resize Partition"-Button be shown in main window
  boolean button_create 	  = true;    // Should the "Create Partition"-Button be shown in main window
  boolean button_delete 	  = true;    // Should the "Delete Partition"-Button be shown in main window
  boolean button_edit             = true;    // Should the "Edit   Partition"-Button be shown in main window
  boolean button_reread           = true;    // Should the "Reread Partition"-Button be shown in Expert menu
  boolean button_raid 	          = true;    // Should the "RAID"  -Button be shown in main window
  boolean button_loop 	          = true;    // Should the "LOOP"  -Button be shown in main window
  boolean button_lvm              = true;    // Should the "LVM"   -Button be shown in main window
                                             // Should the "EVMS"  -Button be shown in main window
  boolean button_evms             = ProductFeatures::evms_config;
  boolean button_expert           = true;    // Should the "EXPERT"-Button be shown in main window
  boolean button_delete_parttable = true;    // Should the "Delete partition table and disk label"
                                             // -Button be shown in Expert menu 
  boolean button_adapt_mp	  = false;   // Should the "Adapt mount points from 
                                             // existing /etc/fstab" -Button be shown in Expert menu
  
   boolean test_mode          = Mode::test ();
   string  boot_mode	      =	"fritz";
   /* FIXME string  boot_mode	      =	Bootloader::getLoaderType ();*/
   boolean immediate_prepdisk = Storage::immediate_prepdisk;
   string  focusline          = "";

   integer last_sel_disk = 0;


   

   ////////////////////////////////////////////////
   // Testmode, should be commented in release
   // test_mode   = true;
   // test_mode   = false;
   // Arch::architecture () = "ppc";
   // Arch::architecture () = "axp";
   ////////////////////////////////////////////////

   if( Arch::ppc () )
       {
       showT_cyl	 = false;
       bsd_label         = false;
       }

   if( Arch::s390 () )
       {
       showT_id = true;
       button_resize = false;
       button_loop = false;
       }

   if( Arch::alpha () )
       {
       bsd_label = (boot_mode == "aboot");
       }

   if( Arch::sparc () )
       {
       bsd_label = true;
       }

   if( Stage::initial () )
       {
       button_adapt_mp = true; 
       }
   if( Mode::repair () )
      {
      button_raid 	  = false;
      button_loop 	  = false; 
      button_lvm          = false;
      button_evms         = false;
      button_adapt_mp	  = false;
      }

  
   y2debug( "ARCHIT %1", Arch::architecture () );


   ////////////////////////////////////////////////////////////////////////
   //                          DEFINES                                   //
   ////////////////////////////////////////////////////////////////////////



    /*---------------------------------------------------------------------
     * Check if the numer is in the format <number>
     *
     * Returns true or false
     *----------------------------------------------------------------------
     */

define boolean IsNumber( string input )
    ``{
    integer n = 0;
    while (n < size(input))
	{
        string erg = filterchars(substring(input, n,1), "0123456789.");

        if (size(erg) != 1)
	    {
	    return(false);
	    }
        n = n + 1;
        }
    return(true);
    };
	
    /*---------------------------------------------------------------------
     * Check if the number is in the format [+]<number>[kKmMgGtT][bBoO]
     *
     * Returns true or false
     *----------------------------------------------------------------------
     */
define boolean IsCylNumber( string input )
    ``{
    if( substring( input, 0, 1) == "+")
        {
	input = substring( input, 1);
        }

    if( !IsNumber(input))
	{
	// check whether the last char is in "gGtTkKmM" or "bBoO"
	string last_char = substring( input, size(input)-1, 1);

	if( last_char == "b" || last_char == "B"  ||
	    last_char == "o" || last_char == "O" )
	    {
	    input = substring( input, 0, size(input)-1);
	    // check whether the last char is in "gGtTkKmM"
	    last_char = substring( input, size(input)-1, 1);
	    }

        string erg = filterchars(last_char, "kKmMgGtT");

        if( size(erg) != 1)
	    {
	    // the last isn't in "kKmMgGtT"
	    return( false );
	    }
	else
	    {
	    // the last is in "kKmMgGtT" check whether the rest is a number
	    return( IsNumber( substring(input, 0, size(input)-1)));
	    }
	}
    else
	{
	return( true );
	}
    };


     /*---------------------------------------------------------------------
     * Parse the end_partition String
     * Input:
     *  - start_cylinder,
     *  - end of partition in
     *    valid is [+]<number>[kKmMgGtT][bBoO]
     *    insert a valid string! consistency must be already checked
     * - size of a cylinder in byte
     *
     * Returns (endcylinder -startcylinder +1) as integer
     *----------------------------------------------------------------------
     */

define integer ToEndRegion( string start_cyl, string end_part, 
			    integer cyl_size )
    ``{
    boolean is_add = false;
    string input = end_part;

    if( substring( input, 0, 1) == "+")
	{
	input = substring( input, 1);
	is_add = true;
	}

    if ( !IsNumber(input))
	{
	is_add = true;  //  44k is the same as +44k

	// take last char
	string last_char = substring( input, size(input)-1, 1);

	// accept also +4kb or 7GB
	if( last_char == "b" || last_char == "B" || 
	    last_char == "o" || last_char == "O" )
	    {
	    input     = substring( input, 0, size(input)-1);
	    last_char = substring( input, size(input)-1, 1);
	    }

	//integer base     = tointeger(substring( input, 0, size(input)-1 ));
	float base     = tofloat(substring( input, 0, size(input)-1 ));

	if( last_char == "k" || last_char == "K" )
	    {
	    return( tointeger((base*1024.0)/tofloat(cyl_size) +1.0 ));
	    }
	if( last_char == "m" || last_char == "M" )
	    {
	    return( tointeger((base*1048576.0)/tofloat(cyl_size) +1.0 ));
	    }
	if( last_char == "g" || last_char == "G" )
	    {
	    return( tointeger((base*1073741824.0)/tofloat(cyl_size) +1.0 ));
	    }
	if( last_char == "t" || last_char == "T" )
	    {
	    return( tointeger((base*1099511627776.0)/tofloat(cyl_size) +1.0 ));
	    }

	y2error("Error in parsing end_cylinder" );
	return( tointeger(base) );
	}
    else
	{
	if (is_add)
	    {
	    return( tointeger(tofloat(input)) );
	    }
	else
	    {
	    return( tointeger(tofloat(input))-tointeger(start_cyl)+1 );
	    }
	}
    };


    /*---------------------------------------------------------------------
     * tests which Partition types on a disk can be created
     * for Intel-I386!
     *
     * Input: map disk    // (the map out of the targets map)
     *        string dev  // /dev/hda
     *
     *  Return value: [ <primary_poss>, <extended_poss>, <logical_poss> ]
     *  boolean primary_poss;   // Is a primary partition possible
     *  boolean extended_poss;  // Is a extended partition possible
     *  boolean logical_poss;   // Is a logical partition possible
     *----------------------------------------------------------------------
     * DESCRIPTION
     *
     * primary_part_is_possible  = false; // can I create a primary part ?
     * extended_part_is_possible = false; // can I create a extended part ?
     * logial_part_is_possible  = false; // ...
     *
     *
     *   if (one of the partitions <disk>1 <disk>2 <disk>3 <disk>4
     *       is not used )
     *   {
     *      primary_part_is_possible = true;
     *   }
     *
     *   if  primary_part_is_possible && (no extended partition exists)
     *   {
     *     extended_part_is_possible = true;
     *   }
     *
     *   if (extended partition already exists) && (extended partition has
     *                                       space left)
     *      && (not more than 15 logical parts already exist)
     *   {
     *     logial_part_is_possible = true;
     *   }
     *
     *
     *   At the same time is not possible, that both "logial_part_is_possible"
     *   and "extended_part_is_possible" are true
     *   so we have 6 possible situations
     *
     *   to show this we use
     *   "P" for primary_part_is_possible
     *   "E" for extended_part_is_possible
     *   "L" for logial_part_is_possible
     *
     *   "p" for primary_part_is_possible  == false
     *   "e" for extended_part_is_possible == false
     *   "l" for logial_part_is_possible  == false
     *
     *
     *   PE  : I can create a primary or exended part.
     *   PL  : Extended part. exist. I can create a primary or a logical
     *   Pel : only a priary is possible, when the extended part. has no space left
     *
     *   pE  : Not possible, if "E" is possible always "P" is possible too.
     *   pL  : only a logical is possible, if together 4 primary and extended
     *  partitions are already created
     *   pel : no partitions are possible
     *
     *----------------------------------------------------------------------
     */

define list CheckCreatePossibilities( string dev, map disk )
    ``{
    string type = substring(dev, 5, 2);

    boolean extended_exists      = false;

    symbol no_logical_cause     = `no_ext;
    symbol no_primary_cause     = `dev_full;
    symbol no_extended_cause    = `dev_full;

    boolean     primary_is_possible  = false;
    boolean     extended_is_possible = false;
    boolean     logical_is_possible  = false;

    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 )));

    if( (size(extended_list) + size(primary_list)) < disk["max_primary"]:4 )
	{
	primary_is_possible = true;
	}

    if( primary_is_possible && (size(extended_list) == 0) &&
        Partitions::HasExtended( disk["label"]:"") )
	{
	extended_is_possible = true;
	}

    if( size(extended_list) > 0 ) 
	{
	no_extended_cause = `already;
	extended_exists = true;
	}

    if( disk["max_primary"]:4 > 4 )
	{
	logical_is_possible = false;
	extended_is_possible = false;
	no_logical_cause = `impossible;
	no_extended_cause = `impossible;
	}

    if( extended_exists )
	{
	no_logical_cause = `no_extsp;

	// test if extended partition has space left == a slot exists
	boolean slot_exist = false;

	// Start-End of the extended partition

	integer start_ext_cyl = extended_list[0,"region",0]:0;
	integer end_ext_cyl   = extended_list[0,"region",1]:1 + start_ext_cyl-1;


	// logical_cyl_list = [ <start_cyl.firstLogPart> , <end_cyl.firstLogPart> , <start.nextLogPart> ,....., <end.lastLogPart>]
	//
	// example:  input: hda5:region [255,100] hda6:region[355,100] hda7[455,100]
	//           is al list generatated: logical_cyl_list = [255,354,355,454,455,555]
	//
	list logical_cyl_list = 
	    sort(flatten(maplist( map part, logical_list, 
				  ``([part["region",0]:0,
				      part["region",0]:0 + part["region",1]:1-1 ]))));

	// Look for a slot in the list of cylinders
	integer  n          = 0;

	if (size(logical_cyl_list) == 0 )
	    {
	    // no logical partitions exist
	    slot_exist = true;
	    }
	else
	    {
	    repeat
		{
		if( n == 0 )
		    {
		    // first
		    if( logical_cyl_list[0]:0 != start_ext_cyl ) 
			slot_exist = true;
		    }
		else if( n == (size(logical_cyl_list)/2))
		    {
		    // last
		    if( logical_cyl_list[size(logical_cyl_list)-1]:0 != 
		        end_ext_cyl ) 
			slot_exist = true;
		    }
		else
		    {
		    //check if between logical partition n-1 and n is a slot
		    if( (logical_cyl_list[2*n-1]:0 + 1) != (logical_cyl_list[2*n]:0 )) 
			slot_exist = true;
		    }

		n = n+1;
		} until ( n == ( (size(logical_cyl_list)/2 +1)) || slot_exist );
	    }

	if( slot_exist)
	    {
	    no_logical_cause     = `to_many;

	    y2debug( "Logical: %1 %2", type, logical_cyl_list);

	    if( type == "hd" )      // EIDE supports 63 partitions
		{
		if (size(logical_cyl_list)/2 < 59 ) logical_is_possible = true;
		}
	    if( type == "sd" )     // SCSI supports 15 partitions
		{
		if (size(logical_cyl_list)/2 < 11 ) logical_is_possible = true;
		}
	    else
		{
		logical_is_possible = true;
		}
	    }
	}

    return( [primary_is_possible, extended_is_possible, logical_is_possible,
	     no_primary_cause, no_extended_cause, no_logical_cause ]);
    };


    /*---------------------------------------------------------------------
     * Find bigest slot
     * return [start, end] or nil
     *---------------------------------------------------------------------
     */

define list GetSlot( string dev, map disk )
    ``{
    string type = substring(dev, 5, 2);
    list<map> global_list = filter( map part, disk["partitions"]:[], 
                               ``( part["type"]:`unknown != `logical && 
			           !part["delete"]:false ));

    if( bsd_label )
	{
	global_list  = filter( map part, global_list, ``( part["nr"]:0 != 3 ));
	}


    list global_cyl_list = 
	sort(flatten(maplist( map part, global_list, 
			      ``([part["region",0]:0,
				  part["region",0]:0 + part["region",1]:1-1 ]))));

    // Look for a slot in the list of cylinders
    integer  n          = 0;
    integer start_cyl   = 0;
    integer end_cyl     = disk["cyl_count"]:1 - 1;

    integer sl_start   = 0;
    integer sl_end     = 0;
    integer curr_start = 0;
    integer curr_end   = 0;

    boolean slot_exist = false;

    y2milestone( "global_cyl_list %1", global_cyl_list );

    if( size(global_cyl_list) == 0 )
	{
	// no partition exist
	return( [start_cyl, end_cyl]);
	}
    else
	{
	repeat
	    {
	    if( n == 0 )
		{
		// first
		curr_start  =  start_cyl-1;
		curr_end    =  global_cyl_list[0]:0;
		}
	    else if ( n == (size(global_cyl_list)/2))
		{
		// last
		curr_start = global_cyl_list[size(global_cyl_list)-1]:0;
		curr_end   = end_cyl+1;
		}
	    else
		{
		//check if between global partition n-1 and n is a slot
		curr_start = global_cyl_list[2*n-1]:0;
		curr_end   = global_cyl_list[2*n]:0;
		}

	    y2milestone( "n curr_start %1 curr_end %2", curr_start, curr_end );
	    if( curr_start+1 < curr_end )
		{
		slot_exist = true;

		y2debug( "A Slot at: %1 %2",  curr_start, curr_end );

		if( (curr_end-curr_start-2) >= (sl_end - sl_start) )
		    {
		    sl_start = curr_start+1;
		    sl_end   = curr_end-1;
		    }
		}
	    y2debug("SLOT- %1 %2 %3 %4", slot_exist, curr_start, curr_end, n );

	    n = n+1;
	    } until ( n == ( (size(global_cyl_list)/2 +1)));
	}

    if( slot_exist)
        {
	return( [sl_start, sl_end] );
        }
    else
	{
	return(nil);
	}
    };

    /*---------------------------------------------------------------------
     * test primary and extended slot
     * return [start, end] or nil
     * Input: start_cyl of the tested slot, /dev/hda1,  diskmap
     * return [max-end_cyl] or "nil" if its no valid start_cyl
     * todo: GetSlo TestSlot should be one function
     *---------------------------------------------------------------------
     */

define integer TestSlot( integer slot_start_cyl, string dev, map disk, 
			 boolean bsd_label )
    ``{
    string type = substring(dev, 5, 2);
    list<map> global_list  = filter( map part, disk["partitions"]:[], 
                                ``( part["type"]:`unknown != `logical && 
				    !part["delete"]:false ));

    if( bsd_label )
	{
	global_list  = filter( map part, global_list, ``( part["nr"]:0 != 3 ) );
	}

    list global_cyl_list = 
	sort(flatten(maplist( map part, global_list, 
			      ``([part["region",0]:0,
				  part["region",0]:0 + part["region",1]:1-1 ]))));

    // Look for a slot in the list of cylinders
    integer  n          = 0;
    integer start_cyl   = 0;
    integer end_cyl     = disk["cyl_count"]:1 - 1;

    integer sl_start   = 0;
    integer sl_end     = 0;
    integer curr_start = 0;
    integer curr_end   = 0;

    boolean slot_exist = false;


    if( size(global_cyl_list) == 0 )
	{
	y2debug( "Testing Slot : disk empty");
	if( start_cyl <= slot_start_cyl && slot_start_cyl <= end_cyl )  
	    return( end_cyl );
	}
    else
	{
	repeat
	    {
	    if( n == 0 )
		{
		// first
		curr_start  =  start_cyl-1;
		curr_end    =  global_cyl_list[0]:0;
		}
	    else if ( n == (size(global_cyl_list)/2))
		{
		// last
		curr_start = global_cyl_list[size(global_cyl_list)-1]:0;
		curr_end   = end_cyl+1;
		}
	    else
		{
		//check if between global partition n-1 and n is a slot
		curr_start = global_cyl_list[2*n-1]:0;
		curr_end   = global_cyl_list[2*n]:0;
		}

	    y2debug( "Testing Slot %1 < x < %2", curr_start, curr_end );
	    if( curr_start < slot_start_cyl && slot_start_cyl < curr_end )
		{
		// If the slot was found ...
		y2debug( "X Slot at: %1 %2 ",  curr_start, curr_end );
		//////////////////
		return( curr_end-1 );
		//////////////////
		}
	    y2debug("SLOT- %1 %2 %3 %4", slot_exist, curr_start, curr_end, n );

	    n = n+1;
	    } until ( n == ( (size(global_cyl_list)/2 +1)));
	}
    return(nil);
    };



    /*---------------------------------------------------------------------
     * Find bigest slot for logical
     * return [start, end] or nil
    /*---------------------------------------------------------------------
     */

define list GetLogicalSlot( string dev, map disk )
    ``{
    string type = substring(dev, 5, 2);

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

    //////////////////////////////////
    if (extended == nil)
	{
	return(nil);
	}
    //////////////////////////////////

    list global_cyl_list = 
	sort(flatten(maplist( map part, global_list, 
	                      ``([part["region",0]:0,
				  part["region",0]:0 + part["region",1]:1-1 ]))));

    // Look for a slot in the list of cylinders
    integer  n          = 0;
    integer start_cyl   = tointeger( extended["region",0]:0 );
    integer end_cyl     = start_cyl + tointeger(extended["region",1]:1)-1;

    integer sl_start   = 0;
    integer sl_end     = 0;
    integer curr_start = 0;
    integer curr_end   = 0;

    boolean slot_exist = false;


    if (size(global_cyl_list) == 0 )
        {
        // no partition exist
        return( [start_cyl, end_cyl]);
        }
    else
        {
        repeat
	    {
	    if( n == 0 )
		{
		// first
		curr_start  =  start_cyl-1;
		curr_end    =  global_cyl_list[0]:0;
		}
	    else if ( n == (size(global_cyl_list)/2))
		{
		// last
		curr_start = global_cyl_list[size(global_cyl_list)-1]:0;
		curr_end   = end_cyl+1;
		}
	    else
		{
		//check if between global partition n-1 and n is a slot
		curr_start = global_cyl_list[2*n-1]:0;
		curr_end   = global_cyl_list[2*n]:0;
		}

	    if( curr_start+1 < curr_end )
		{
		slot_exist = true;

		y2debug( "A Slot at: %1 %2  ",  curr_start, curr_end );

		if( (curr_end - curr_start -2) >= (sl_end - sl_start) )
		    {
		    sl_start = curr_start+1;
		    sl_end   = curr_end-1;
		    }
		}
	    y2debug("SLOT- %1 %2 %3 %4  ", slot_exist, curr_start, curr_end, n );

	    n = n+1;
	    } until ( n == ( (size(global_cyl_list)/2 +1)));
	}

    if (slot_exist)
        {
        return( [sl_start, sl_end] );
        }
    else
        {
        return(nil);
        }
    };


    /*---------------------------------------------------------------------
     * Check slot for logical partition
     * Input: start_cyl of the tested slot, /dev/hda5,  diskmap, in edit_mode or create_mode
     *
     * return [max-end_cyl] or nil if its no valisd start_cyl
     *
     * todo: GetLogicalSlot TestLogicalSlot should be one function
     *---------------------------------------------------------------------
     */

define integer TestLogicalSlot( integer slot_start_cyl, string dev, map disk)
    ``{
    string type = substring(dev, 5, 2);

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

    list global_cyl_list = 
	sort(flatten(maplist( map part, global_list, 
	                      ``([part["region",0]:0,
				  part["region",0]:0 + part["region",1]:1-1 ]))));

    // Look for the slot in the list of cylinders
    integer  n          = 0;
    integer start_cyl   = tointeger( extended["region",0]:0 );
    integer end_cyl     = start_cyl + tointeger( extended["region",1]:1-1 );

    integer sl_start   = 0;
    integer sl_end     = 0;
    integer curr_start = 0;
    integer curr_end   = 0;

    boolean slot_exist = false;


    if (size(global_cyl_list) == 0 )
        {
        if( start_cyl <= slot_start_cyl  && slot_start_cyl <= end_cyl )  
	  return( end_cyl );
        }
    else
        {
        repeat
	    {
	    if( n == 0 )
		{
		// first
		curr_start  =  start_cyl-1;
		curr_end    =  global_cyl_list[0]:0;
		}
	    else if ( n == (size(global_cyl_list)/2))
		{
		// last
		curr_start = global_cyl_list[size(global_cyl_list)-1]:0;
		curr_end   = end_cyl+1;
		}
	    else
		{
		//check if between global partition n-1 and n is a slot
		curr_start = global_cyl_list[2*n-1]:0;
		curr_end   = global_cyl_list[2*n]:0;
		}

	    y2debug( "Testing Slot %1  < x < %2  ", curr_start, curr_end );

	    if( curr_start < slot_start_cyl && slot_start_cyl < curr_end )
		{
		// If the slot was found ...
		y2debug( "X Slot at:  %1 %2 ",  curr_start, curr_end );
		//////////////////
		return( curr_end -1);
		//////////////////
		}
	    y2debug("SLOT- %1 %2 %3 %4", slot_exist, curr_start, curr_end, n );

	    n = n+1;
	    } until ( n == ( (size(global_cyl_list)/2 +1)));
        }
    return(nil);
    };


    /*---------------------------------------------------------------------
     * returns for nonnegative numbers a string with a minimum of 4 characters:
     * 1      -> "   1"
     * 22     -> "  22"
     * 145    -> " 145"
     * 2134   -> "2134"
     * 34111 -> "34111"
     *----------------------------------------------------------------------
     */
define string to4string( integer nb )
    ``{
    if ( nb < 10 )   return( sformat( "   %1", nb ));
    if ( nb < 100 )  return( sformat( "  %1",  nb ));
    if ( nb < 1000 ) return( sformat( " %1",   nb ));
    return( sformat( "%1", nb ));
    };


    /*---------------------------------------------------------------------
     * Fill the selection box with ID 'selbox_id' inside widget tree
     * 'widget' with disk and partition info from 'all_disks'.
     *
     *  Return value:
     * term contents = `VBox(`Label("Partitions"),
     *                        `Table(`header("Device", "Start", "End", "Size", "F", "Type", "Mount", "RAID" , "LVM" ),
     *                               [
     *                                `item(`id("/dev/hda"),    "/dev/hda",      "8.5 GB",   " ", "Seagate ST 48012", " ",	  "1",  "1115"	,"",	""),
     *                                `item(`id("1//dev/hda"), "  /dev/hda1",   "509.8 MB", " ", "FAT16",            " ",	  "1",  "65"	,"",	""),
     *                                `item(`id("2//dev/hda"), "  /dev/hda2",   "666.7 MB", " ", "NTFS",             " ",	  "66", "150"	,"",	""),
     *                                `item(`id("3//dev/hda"), "  /dev/hda3",   "5.5 GB",   " ", "Extended",         " ",	  "301","1024"	,"",	""),
     *                                `item(`id("4//dev/hda"), "  /dev/hda5",   "7.8 MB",   "F", "Linux ",           "/boot",	  "301","302"	,"",	""),
     * 				      `item(`id("5//dev/hda"), "  /dev/hda6",   "7.8 MB",   "", "Linux LVM ",         "",         "303","304"	,"",	"system"),
     *				      `item(`id("6//dev/hda"), "  /dev/hda7",   "7.8 MB",   "", "Linux RAID ",        "",         "305","307"	,"/dev/md1",	""),
     *                               ] )) ;
     *
     *  PPC: without Start End
     *
     *----------------------------------------------------------------------
     */

define list FillPartitionList()
    ``{
     // fill in size_bytes for raid
     Storage::AddRaidSizeInfo();
     map<string,map>  targets 	= Storage::GetTargetMap();
     list<term> table_input 	= [];
     boolean log_mode 	= false;

     SCR::Write(.target.ycp,Storage::SaveDumpPath("targetMap_c"), targets );
     foreach( string disk_dev_name, map disk, targets,
	 ``{
	 boolean real_disk = Storage::IsRealDisk( disk_dev_name, disk );
	 boolean evms_vol  = find( disk_dev_name, "/dev/evms" )==0;
	 integer cyl_count     = disk["cyl_count"]:0;
	 integer cyl_size      = disk["cyl_size"]:1000000;
	 string  vendor        = disk["vendor"]:"";
	 string  model         = disk["model"]:"";
	 string  dev_size      = ByteToHumanString(cyl_count * cyl_size);
	 string  dev_start_cyl = to4string(0);
	 string  dev_nb_cyl    = to4string(cyl_count-1);
	       
	 if ( (model != "") && (vendor != "") ) 
	     vendor = vendor + "-" + model;
	 else 
	     vendor = vendor +       model;

	 // entry in column "Type" for a unknown disk
	 if( vendor == "" ) 
	     {
	     if (disk["bus"]:"" == "RAID")
		 {
		 vendor = "RAID "+disk_dev_name;
		 }
	     else if( disk["is_lvm_vg"]:false )
		 {
		 vendor = "LVM" + (disk["lvm2"]:false ? "2 " : "  ") +
		          substring( disk_dev_name, 5 );
		 }
	     else
		 // label text
		 vendor = sformat( _("DISK %1"), substring( disk_dev_name, 5 ));
	     }

	 boolean id_sw_raid_dev = (disk_dev_name == "/dev/md");

	 /////////////////////////////////////////////////////////////
	 // Insert line for the entire disk into selection box widget
	 // Look, if for the architecture disk, and Cylinder are shown
	       

	 /////////////////////////////////////////////////////////////
	 // if LVM device get new size
	 if( disk["is_lvm_vg"]:false )
	     {	
	     list<map> parts = get_possible_pvs( targets );
	     dev_size = (string)get_vg_size( parts, substring(disk_dev_name, 5), 
					     `string );
	     dev_nb_cyl    = " -- ";
	     dev_start_cyl = " -- ";
	     }
	       
	 if( show_disk && 
	     (real_disk || 
		 (disk["is_lvm_vg"]:false&&!disk["delete"]:false)) )
	     {
	     term a = `item(`id(disk_dev_name));

	     if( showT_dev )    a = add(a, disk_dev_name );
	     if( showT_id )     a = add(a, sformat( " (%1)", 
						    disk["bios_id"]:"" ) );
	     if( showT_size )   a = add(a, dev_size );
	     if( showT_format ) a = add(a, (disk["dasdfmt"]:false)?"X":" " );
	     if( showT_fs )     a = add(a, vendor);
	     if( showT_mount )  a = add(a, "" );
	     if( showT_cyl )    a = add(a, dev_start_cyl );
	     if( showT_cyl )    a = add(a, dev_nb_cyl    );
	     if( showT_Used )   a = add(a, "");
	     if( showT_Label  ) a = add(a, "");
	      
	     table_input = add( table_input, a );
	     }

	 /////////////////////////////////////////////////////////////
	 // Now we come to the partitions ...

	 list<map> partitions = disk["partitions"]:[];

	 foreach( map partition, partitions,
	     ``{
	     // dont show "system partitions"
	     string fstype = partition["fstype"]:"";
	     boolean hide = partition["delete"]:false;
	     if( size(filter( string v, Partitions::not_shown_partitions,
			      ``(issubstring(fstype, v)) ))>0 )
		 {
		 hide = true;
		 }
	     if( disk["is_lvm_vg"]:false && disk["delete"]:false )
		 {
		 hide = true;
		 }
	     if( !hide && find( partition["device"]:"", "/dev/evms/" )==0 )
		 {
		 string d1 = "/dev/" + substring( partition["device"]:"", 10 );
		 if( find( d1, "/lvm/" )>0 )
		     {
		     d1 = "/dev/" + substring( d1, 9 );
		     }
		 hide = size(partition["mount"]:"")==0;
		 if( hide )
		     {
		     hide = size(Storage::GetPartition( targets, d1 ))>0 ||
		            !partition["evms_native"]:false;
		     }
		 }
	     if( !hide || log_mode )
		 {
		 string id = Storage::GetSubDevKey( disk_dev_name, 
						    partition["nr"]:(any)0);

		 //////////////////////////////////////////////////////////
		 // Format Devicename:

		 string   part_dev_name   = "";
		 string   part_id         = "";

		 part_dev_name = partition["device"]:"";

		 ////////////////////////////////////////////////////////////
		 // Format other Colums:

		 integer  start_cyl       = partition["region",0]:0;
		 integer  nb_cyl          = partition["region",1]:0;
		 symbol   type            = partition["type"]:`unknown;
		 boolean  format          = partition["format"]:false;
		 boolean  crypt_fs        = partition["loop_fs"]:false && partition["crypt"]:"" != "none";
		 symbol   used_fs         = partition["used_fs"]:`unknown;
		 string   mount_point     = partition["mount"]:"";
		 string   filesystem_name = "";
		 string   used_by   	  = partition["raid_name"]:"";
		 string   label           = partition["label"]:"";

		 if( size( partition["lvm_group"]:"")>0 )
		     {
		     used_by = "LVM " + partition["lvm_group"]:"";
		     }
		 else if( size( partition["evms_vol"]:"")>0 )
		     {
		     used_by = "EVMS " + partition["evms_vol"]:"";
		     }

		 filesystem_name = partition["fstype"]:"";

		 if( format && partition["fsid"]:0 == Partitions::fsid_native)
		     {
		     string fs_name =  FileSystems::GetName( used_fs, "Ext2" );
		     filesystem_name = filesystem_name + " (" + fs_name + ") ";
		     }

		 string format_flag      = "";
		 if ( format ) format_flag = "F";
		 if ( crypt_fs ) format_flag = "C" + format_flag;

		 if( log_mode )
		     {
		     string       ori_str = "";
		     boolean del = partition["delete"]:false;
		     boolean cre = partition["create"]:false;
		     integer ori = partition["ori_nr"]:0;
		     if ( del == nil)    format_flag = format_flag + " dn";
		     if ( del == true )  format_flag = format_flag + " dT";
		     if ( del == false ) format_flag = format_flag + " dF";
		     if ( cre == nil)    format_flag = format_flag + " cn";
		     if ( cre == true )  format_flag = format_flag + " cT";
		     if ( cre == false ) format_flag = format_flag + " cF";
		     if ( ori == nil)    
			 ori_str = " o- ";
		     else 		   
			 ori_str = sformat( " o%1 ", ori );
		     format_flag = format_flag + ori_str;
		     }

		 string bytes_of_part = "";

		 if( id_sw_raid_dev )
		     {
		     bytes_of_part = raid_size_str( targets, partition);
		     y2debug( "--RAID: %1 -- %2", id_sw_raid_dev, bytes_of_part);
		     }
		 else
		     {
		     bytes_of_part = ByteToHumanString( nb_cyl * cyl_size);
		     }

		 /////////////////////////////////////////////////////
		 // Insert line for this partition into selection box widget
		 //
		 // Start- and EndCly are shown (intel) or not (ppc) ...

		 term a = `item(`id(id));

		 if( showT_dev )    a = add(a, part_dev_name );
		 if( showT_id )     a = add(a, part_id );
		 if( showT_size )   a = add(a, bytes_of_part);
		 if( showT_format ) a = add(a, format_flag);
		 if( showT_fs )     a = add(a, filesystem_name);
		 if( showT_mount )  
		     {
		     string tmp = mount_point;
		     if( partition["noauto"]:false && 
			 !partition["active"]:false )
			 {
			 tmp = tmp + " *";
			 }
		     a = add(a, tmp );
		     }
		 if( showT_cyl )
		     {
		     if( real_disk )
			 {
			 a = add(a, to4string(start_cyl));
			 integer num = start_cyl + nb_cyl - 1;
			 a = add(a, to4string(num));
			 }
		     else
			 {
			 a = add(a, " -- ");
			 a = add(a, " -- ");
			 }
		     }
		 if( showT_Used )   a = add(a, used_by);
		 if( showT_Label )  a = add(a, label);

		 table_input = add( table_input, a );
		 }
	     else
		{
		// as deleted marked
		// y2debug( "ddddddddddddd----");
		}
	     });
         });

    // order should be md, then loop, then LVM, then EVMS
    map disk_order = $[ "/dev/md" : 0, "/dev/loop" : 1, "/dev/evms" : 3 ];
    integer num1 = -1;
    integer num2 = -1;

    return sort( term lineA, term lineB, table_input, ``(
	{
	boolean ret = false;
	map disk1 = Storage::GetDiskPartition( lineA[1]:"" );
	map disk2 = Storage::GetDiskPartition( lineB[1]:"" );

	//y2milestone( "FillPartitionList disk1 %1 disk2 %2", disk1, disk2 );

	ret = disk1["disk"]:"" < disk2["disk"]:"";

	boolean normal1 = Storage::IsRealDisk( disk1["disk"]:"", 
	                                       targets[disk1["disk"]:""]:$[] );
	boolean normal2 = Storage::IsRealDisk( disk2["disk"]:"", 
	                                       targets[disk2["disk"]:""]:$[] );
	//y2milestone( "FillPartitionList normal1 %1 normal2 %2", normal1, normal2 );

	if( normal1 != normal2 )
	    {
	    ret = normal1;
	    }
	else if( disk1["disk"]:"" == disk2["disk"]:"" )
	    {
	    if( (is( disk1["nr"]:(any)0, string ) &&
	         is( disk2["nr"]:(any)0, string )) ||
	        (is( disk1["nr"]:(any)0, integer ) &&
	         is( disk2["nr"]:(any)0, integer )))
		{
		ret = disk1["nr"]:(any)0 < disk2["nr"]:(any)0;
		}
	    else
		{
		ret = is( disk1["nr"]:(any)0, string );
		}
	    }
	else
	    {
	    string d1 = disk1["disk"]:"";
	    string d2 = disk2["disk"]:"";
	    if( find( d1, "/dev/evms/" ) == 0 )
		{
		d1 = "/dev/evms";
		}
	    if( find( d2, "/dev/evms/" ) == 0 )
		{
		d2 = "/dev/evms";
		}
	    num1 = disk_order[d1]:2;
	    num2 = disk_order[d2]:2;
	    //y2milestone( "num1 %1 num2 %2", num1, num2 );
	    if( num1!=num2 )
		{
		ret = num1 < num2;
		}
	    else
		{
		ret = disk1["disk"]:"" < disk2["disk"]:"";
		}
	    }
	//y2milestone( "FillPartitionList ret %1", ret );
	return ret;
	}));
    };

/*-------------------------------------------------------------------
 *
 *    Now check start an end cylinder
 *    caution: there is no differenc in edit and create cause the partition, which is to edited,
 *    is not in the disk map!
 *
 *    Check:
 *    A. Is start_cyl ist a number?  no-> try again
 *    B. is start_cyl valid ( can the partition start there?) no -> try again
 *          (when this is tested, the maximal possible end cylinder is computed, too)
 *    C.    Now we check the syntax of the endCylinder
 *    D.    If the syntax is valid, the requested end cylinder is checked
 *    E.  If it is not valid, the user gets a popup and the maximal possible end cylinder is set
 *
 *    returns  [<symbol>, <value>]
 *
 *             [`ok,  <effektive end cyl>]
 *             [`max, <max-value as str> ]   // case E
 *             [`error, 0]
 *-------------------------------------------------------------------
 */

define list TestStartEndCyl( string str_start_cyl, string str_end_part, 
			     string dev, map disk, symbol type, 
			     integer cyl_size, boolean bsd_label )
    ``{
    integer	max_end_cyl   = 0;
    string    max_end_str   = "";
    symbol    input         = `ok;
    integer   int_start_cyl = tointeger(str_start_cyl);
    integer   int_end_cyl   = 0;

    ////////////////////////////////// STEP A /////////////////////
    if (!IsNumber( str_start_cyl ))
	{
	input = `error;
	// error popup text
	Popup::Error(_("Wrong input for the start of the partition. 
Enter the start cylinder (e.g., 77).
"));
	}
    else
	{
	////////////////////////////// STEP B /////////////////////

	integer      int_start_cyl = tointeger(str_start_cyl);

	if ( type == `logical ) 
	    max_end_cyl = TestLogicalSlot( int_start_cyl, dev, disk );
	else 
	    max_end_cyl = TestSlot( int_start_cyl, dev, disk, bsd_label );  // primary && extended
	if (max_end_cyl == nil)
	    {
	    // error popup text
	    Popup::Error(_("You entered an invalid value. Please try again."));
	    input = `error;
	    }

	if ( input == `ok )
	    {
	    ////////////////////////// STEP C /////////////////////
	    if (!IsCylNumber(str_end_part))
		{
		input = `error;
		// error popup text
		Popup::Error(_("The value for the partition end is invalid.

Enter the end cylinder number (e.g., 77), an offset (e.g., +122),
or specify the size of the partition directly (e.g., +100M or 1.8GB )
"));
		}
	    else
		{
		////////////////////// STEP D /////////////////////

		int_end_cyl = int_start_cyl + 
			      ToEndRegion( str_start_cyl, str_end_part, 
					   cyl_size ) - 1;

		if( int_end_cyl > max_end_cyl || int_end_cyl < int_start_cyl)
		    {
		    ////////////////// STEP E /////////////////////

		    // error popup text, %1, %2, %3 is replaced by numeric value
		    string text = sformat( _("
The value of the end cylinder %1 was not valid. 
Value must be between %2 and %3.

YaST2 can automatically use the maximum allowed value
or select \"No\" and enter a correct value yourself.

Should YaST2 use the maximum allowed value? 
"),
                                          int_end_cyl, int_start_cyl, 
					  max_end_cyl );
		    boolean ans = Popup::YesNo( text );

		    if( ans )
		        {
			max_end_str = sformat("%1", max_end_cyl);
			input = `max;
			}
		    else
		        {
			input = `error;
			}
		    }
		}
	    }
	}
    // END Check

    if ( input == `ok )  return( [`ok,  int_end_cyl ]);
    if ( input == `max ) return( [`max, max_end_str ]);

    // if  ( input == `error )
    return( [`error, 0]);
    };



/*---------------------------------------------------------------------
 * Checks if the mountpoint is valid
 * - /proc /mnt /lost+found contain Installation::sourcedir are not allowd
 * - double entries are not allowed ( mountpoints with no / and "" are always allowed )
 *
 *----------------------------------------------------------------------

/**
 * Dialog: "Create a partition Dialog"
 * @parm new_val map that contains a partition
 * @parm file_systems filesystem definitions
 * @parm tilte	title string
 * @parm dev device string for the new/edit partition
 * @parm disk a map with the disk data  CAUTION: in Edit-Mode, the edited partition, must not be in this map!!
 * @parm bsd_label
 * @parm edit_size flag
 * @parm cyl_size
 * @return map modified partition or nil by cancel
 */

define map<string,any> EditOrCreatePartDlg( map<string,any> cur_val, 
                                            map<symbol,map> file_systems, 
					    string title, map disk, 
					    boolean bsd_label, 
					    boolean edit_size, 
					    integer cyl_size, 
					    boolean installation )

    ``{
    boolean create = cur_val["create"]:false;
    string dev = cur_val["device"]:"";

    string helptextCR = getEditOrCreateHelptext( cur_val, true );

    //////////////////////////////////////////////////////////////////////
    // Now create "main" dialog with all elements needed
    //////////////////////////////////////////////////////////////////////

    //////////////////////////////////////////////////////////////////////
    // right side of the main dialog
    term field_dlg_right = 
	`VBox(
	     `Top( SizeDlg( cur_val, cyl_size, edit_size )),
	     `VSpacing(1),
	     `ReplacePoint( `id(`mount_dlg_rp), MountDlg( cur_val, [] ))
	     );



      ////////////////////////////////////////////////////////////////////
      // left side of the main dialog
      term field_dlg_left = 
	  `Top( `ReplacePoint( `id( `format_dlg_rp), 
			       FormatDlg( cur_val, file_systems) ));

      ////////////////////////////////////////////////////////////////////
      // Open main dialog for editing and creation of partitions
      ////////////////////////////////////////////////////////////////////
      UI::OpenDialog( `opt(`decorated  ),
		  `HBox(
			`HWeight(30, `RichText( helptextCR )),
			`HStretch(),
			`HSpacing(1),
			`HWeight(70,`VBox(
				       `Heading( title),
				       `VSpacing(1),
				       `VStretch(),
				       `HBox(
					     field_dlg_left,
					     `HSpacing(2),
					     field_dlg_right
					     ),
				       `VSpacing(1),
				       `VStretch(),
				       `HBox(
					     `PushButton(`id(`ok), `opt(`default),  Label::OKButton()   ),
					     `PushButton(`id(`cancel),  Label::CancelButton() )
					     )
				       )
				),
			`HSpacing(1),
			`HStretch()
			)
		);


      map<string,any> retval = eval(cur_val);
      symbol ret = `ok;

      retval = HandlePartWidgetChanges( true, ret, file_systems, cur_val, 
                                        retval );

      repeat
	 {
	 ////////////////////////////////////////////////////////////
	 // Check the User input
	 ret = (symbol)UI::UserInput();
	 y2milestone( "UserInput ret:%1", ret );

	 if ( ret != `cancel )
	    {
	    retval = HandlePartWidgetChanges( false, ret, file_systems, cur_val,
	                                      retval );
	    }

	 ////////////////////////////////////////////////////////////
	 // if the user has pushed the button ok
	 if ( ret == `ok )
	    {
	    /////////////////////////////////////////////////////////
	    // save mountpoint
	   retval["mount"] = String::CutBlanks( (string)UI::QueryWidget(`id(`mount_point),
									`Value));

	    /////////////////////////////////////////////////////////
	    // add fstype to retval

	    integer fs_id = retval["fsid"]:0;

	    if( fs_id<256 )
		{
		retval["fstype"] = "";
		foreach( symbol file_system_name, map file_system_map, file_systems, ``{
		     if( file_system_map[`fsid]:Partitions::fsid_native == 
		         fs_id )
			 retval["fstype"] = file_system_map[`fstype]:"";
		     });

		 if( retval["fstype"]:"" == "")
		     retval["fstype"] = Partitions::FsIdToString( fs_id );
		 }

	     if( create && edit_size )
		 {
		 ////////////////////////////////////////////////////
		 // Get start and end cyl and check if the user input 
		 // for start und end cyl are valid
		 list re = [];
		 string start_cyl = (string)UI::QueryWidget(`id(`start_cyl), `Value);
		 string end_part  = (string)UI::QueryWidget(`id(`end_part), `Value);

		 re = TestStartEndCyl( start_cyl, end_part, dev, disk, 
		                       retval["type"]:`primary, cyl_size,
				       bsd_label );

		 if( re[0]:`error == `error )
		     {
		     UI::SetFocus(`id(`end_part));
		     ret = `again;
		     continue;
		     }
		 if( re[0]:`error == `max )
		     {
		     end_part =  re[1]:"";
		     }

		 ////////////////////////////////////////////////////
		 // add start_cyl and end_part to region and add region 
		 // to retval
		 list region = [ tointeger( start_cyl ), 
		                 ToEndRegion( start_cyl, end_part, cyl_size )];

		 retval["region"] = region;
		 }

	    if( !check_ok_fssize( retval["region",1]:0 * cyl_size, retval ))
		{
		UI::SetFocus(`id(`end_part));
		ret = `again;
		continue;
		}

	     map ret_mp = CheckOkMount( dev, cur_val, retval );
	     retval = ret_mp["map"]:$[];
	     if( !ret_mp["ok"]:false )
		 {
		 if( ret_mp["field"]:`none != `none )
		     UI::SetFocus(`id(ret_mp["field"]:`none));
		 ret = `again;
		 continue;
		 }

	     //////////////////////////////////////////////////////////////
	     //  user changed fsid of existing partition
	     symbol par_type = cur_val["type"]:`empty;
	     y2milestone( "par_type %1", par_type );
	     if( retval["fsid"]:0 != cur_val["fsid"]:0 &&
		 (par_type==`primary||par_type==`logical||par_type==`extended)&&
		 !haskey( cur_val, "change_fsid") && 
		 !retval["create"]:false )
		 {
		 // popup text
		 boolean ok = Popup::YesNo(_("WARNING:
You have changed the FSID of an existing partition.
In some cases, this could have serious consequences, especially
if you change the FSID of a partition belonging to a different
operating system. Only proceed if you know exactly
what you are doing.
Do you really want to change the FSID?
"));

		 if (! ok )
		     {
		     UI::ReplaceWidget(`id(`fsid_dlg_rp), 
		                        FsidComboBox( cur_val, file_systems ));
		     UI::ChangeWidget(`id(`format), `CurrentButton, 
		                      `format_false );
		     ret = `again;
		     continue;
		     }

		 if( !haskey( cur_val, "change_fsid"))
		     {
		     retval["change_fsid"] = true;
		     retval["ori_fsid" ] = cur_val["fsid"]:0;
		     }
		 }


	     map ret_cr = CheckCryptOk( retval );
	     if( !ret_cr["ok"]:false )
		 {
		 ret = `retry;
		 }
	     else
		 {
		 retval = ret_cr["map"]:$[];
		 }


	     ////////////////////////////////////////////////////////
	     // modified partition and partition is mounted
		      
	     if( !installation && !arePartitionsEqual( cur_val, retval ) && 
	         !create )
		 {
		 string mounts = 
		     Partitions::MountedOn( dev, Partitions::CurMounted() );
		 if( mounts != "" ) 
		     {
		     if( ! UseChangedPartitionContinueCancelPopup()) 
			 {
			 ret = `cancel;
			 }
		     } 
		 }
	     }     
	 } until (  ret == `ok  || ret == `cancel );


      y2milestone( "ret:%1 retval=%2", ret, retval );
      
      UI::CloseDialog();

      if ( ret == `cancel )
	  {
	  return( nil );
	  }
      else
	  {
	  return( retval );
	  }
    }


     /**
      * Dialog: "Resize a partition Dialog"
      * @parm cur_val  map that contains a partition
      * @parm device   device name of the resized partition
      * @parm cyl_size size of a cylinder on the disk
      * @return map modified partition or nil by cancel
      */
define map ResizePartDlg( map cur_val, string device, map disk, map possible )
    ``{
    integer cyl_size = disk["cyl_size"]:0;
    boolean test_simple_ui = false;
    boolean win = Partitions::IsDosWinNtPartition( cur_val["fsid"]:0 );
    boolean swap = !win && cur_val["fsid"]:0==Partitions::fsid_swap;
    boolean simple_ui = false;
    integer cyl_after = 0;
    if( possible["extend"]:false )
	{
	cyl_after = Storage::FreeCylAfter( disk, cur_val );
	}
    integer av_space = cyl_after*cyl_size / (1024*1024);

    y2milestone( "ResizePartDlg dev:%1 cyl:%2 map:%3 win:%4 swap:%5",
		 device, cyl_size, cur_val, win, swap );
    y2milestone( "ResizePartDlg cyl_after:%1 av_space:%2", 
		 cyl_after, av_space );

    integer min_free = 0;
    integer new_size = 0;
    integer shrink_size = 0;
    integer new_min = 0;

    map df = $[];

    if( !swap && !cur_val["format"]:false )
	{
	df = FileSystems::GetFreeSpace( device, 0, cur_val["used_fs"]:`none, 
	                                true );
	if( size(df)==0 )
	    {
	    y2error( "failed GetFreeSpace %1 fs:%2", device, 
		     cur_val["used_fs"]:`none );
	    string tmp = sformat( 
_("It is not possible to resize partition %1 
because the file system could not be mounted
"), device );
	    Popup::Error( tmp );
	    return( nil );
	    }
	}
    else
	{
	df["used"] = 0;
	if( haskey( cur_val, "ori_length" ) && cur_val["resize"]:false )
	    {
	    df["df_free"] = cur_val["ori_length"]:0 * cyl_size;
	    }
	else
	    {
	    df["df_free"] = cur_val["region",1]:0 * cyl_size;
	    }
	df["free"] = df["df_free"]:0;
	}

    // label text
    string  unit = _("MB");
    integer factor = 1024*1024;
    integer afactor = 1;

    if( df["df_free"]:0 > 15*1024*factor )
	{
	factor = factor * 1024;
	afactor = 1024;
	unit = _("GB");
	}
    y2milestone( "ResizePartDlg factor:%1 afactor:%2", factor, afactor );

    if( haskey( cur_val, "win_max_length" ) && cur_val["resize"]:false )
	{
	new_min = cur_val["ori_length"]:0 - cur_val["win_max_length"]:0; 
	new_min = new_min*cyl_size / factor;
	}

    y2milestone( "ResizePartDlg min_lin:%1 df:%2", new_min, df );

    integer used = df["used"]:0 / factor;
    integer free = df["df_free"]:0 / factor;
    integer not_shrink_free = 0;

    // Labels for bar graph. "%1" will be replace with a numeric value.
    string bargraph_label_used  = "";
    string bargraph_label_free  = "";
    string bargraph_label_new   = "";
    if( win )
	{
	// label text %1 is replaced by a number
	bargraph_label_used  = _("Windows\nused\n%1 ") + unit;
	// label text %1 is replaced by a number
	bargraph_label_free  = _("Windows\nfree\n%1 ") + unit;
	// label text %1 is replaced by a number
	bargraph_label_new   = _("Linux\nsize\n%1 ") + unit;
	}
    else
	{
	// label text %1 is replaced by a number
	bargraph_label_used  = _("Space\nused\n%1 ") + unit;
	if( swap )
	    {
	    // label text %1 is replaced by a number
	    bargraph_label_free  = _("Swap\nspace\n%1 ") + unit;
	    }
	else
	    {
	    // label text %1 is replaced by a number
	    bargraph_label_free  = _("Space\nfree\n%1 ") + unit;
	    }
	// label text, %1 is replaced by a number 
	bargraph_label_new   = _("Unused\ndisk\n%1 ") + unit;
	}

    // Labels for input fields. "%1" will be replaced with the current unit (MB)
    string field_label_free = "";
    string field_label_new  = "";
    if( win )
	{
	// label text, %1 is replaced by a unit value ("MB")
	field_label_free = sformat( _("Windows free (%1)"), unit);
	// label text, %1 is replaced by a unit value ("MB")
	field_label_new  = sformat( _("Linux size (%1)"), unit);
	}
    else
	{
	// label text, %1 is replaced by a unit value ("MB")
	field_label_new  = sformat( _("Unused disk (%1)"), unit);
	if( swap )
	    {
	    // label text, %1 is replaced by a unit value ("MB")
	    field_label_free = sformat( _("Swap space (%1) "), unit);
	    }
	else
	    {
	    // label text, %1 is replaced by a unit value ("MB")
	    field_label_free = sformat( _("Space free (%1)"), unit);
	    }
	}

    if( win )
	{
	min_free = free / 10;
	if( df["df_free"]:0 != df["free"]:0 )
	    {
	    not_shrink_free = df["df_free"]:0 - df["free"]:0;
	    not_shrink_free = (not_shrink_free + factor - 1) / factor;
	    if( not_shrink_free > min_free )
		{
		min_free = not_shrink_free;
		}
	    }
	}
    else
	{
	min_free = (afactor==1)?5:1;
	}

    if( cur_val["used_fs"]:`none == `ntfs && 
        not_shrink_free > df["free"]:0/factor/5 )
        {
	string ptext = sformat( _("Your NTFS file system has %1 %3 free space available. Due to limitations in
the NTFS resizer, the file system can only be shrunk by up to %2 %3.
To be able to shrink the file system more, boot your Windows
system and run a disk defragmentation program under Windows to move
the used blocks of the file system towards the start of the partition.
"),
                                free, df["free"]:0/factor, unit );
        Popup::Message( ptext );
	}
    if( haskey( cur_val, "new_size" ) && cur_val["resize"]:false )
	{
	shrink_size = (df["used"]:0+df["df_free"]:0)/factor -
		      cur_val["new_size"]:0/afactor;
	y2milestone( "ResizePartDlg new_size:%1 shrink_size:%2", 
	             cur_val["new_size"]:0, shrink_size );
	if( shrink_size>df["free"]:0/factor )
	    {
	    shrink_size = df["free"]:0/factor;
	    }
	y2milestone( "ResizePartDlg shrink_size:%1", shrink_size );
	}
    av_space = av_space/afactor;

    y2milestone( "ResizePartDlg min_free:%1 free:%2 used:%3 shrink_size:%4 unit:%5", 
                 min_free, free, used, shrink_size, unit );

    string windows = "";
    if( win )
	{
	// label text 
	windows = _("Windows");
	}

    // Help text for partition resizing - 
    // common part for both graphical mode (with bar graphs) 
    // and non-graphical mode (text only).
    string helptext = sformat( _("<p>
Choose the new size for your %1 partition.
</p>"), windows );

    // help text (common to both modes), continued
    helptext = helptext + sformat( _("
<p>
The actual resizing will be performed only after you confirm all your
settings in the last installation dialog. Until then, your %1
partition will remain untouched.
</p>"), windows );

    // help text (common to both modes), continued
    helptext = helptext + _("
<p>
If you decide not to resize your partition, press  
<b>Do Not Resize</b>. This resets the values to the original
size of the partition.
</p>
");

    if( UI::HasSpecialWidget(`Slider   ) &&
	UI::HasSpecialWidget(`BarGraph ) && !test_simple_ui )
	{
	// help text, continued - graphical mode only
	// this text will be appended to the help text common to both modes.
	helptext = helptext + _("
<p>
The upper bar graph displays the current situation.
The lower bar graph displays the situation after the installation -- after
the partition resize.
</p>");
	// help text (graphical mode), continued
	helptext = helptext + _("
<p>
Drag the slider or enter a numeric value in either
input field to adjust the suggested value.
</p>");

	////////////////////////////////////////////////////////////////////////////////////////////
	// Open main dialog for resizing of partitions
	////////////////////////////////////////////////////////////////////////////////////////////
	term graph = nil;
	if( win || cyl_after==0 )
	    {
	    graph = `BarGraph( [ used, free ],
			       [ bargraph_label_used, bargraph_label_free ] );
	    }
	else
	    {
	    graph = `BarGraph( [ used, free, av_space ],
			       [ bargraph_label_used, bargraph_label_free,
				 bargraph_label_new ] );
	    }
	y2milestone( "ResizePartDlg graph=%1", graph );

	UI::OpenDialog( `opt(`decorated  ),
		    `HBox(
			  `HWeight(30, `RichText( helptext )),
			  `HStretch(),
			  `HSpacing(1),
			  `HWeight(70,`VBox(
			      `HSpacing(50),
			      `VStretch(),
			      `VSpacing(1),
			      // Headline above bar graph that displays current partition size
			      `Left( `Label( _("Now:")) ),
			      graph,
			      `VSpacing(1),
			      `VStretch(),
			      // Headline above bar graph that displays future partitions
			      `Left( `Label( _("After installation:") ) ),
			      `PartitionSplitter( `id(`linux_size), 
						  used, free+av_space,
						  shrink_size+av_space, new_min, min_free,
						  bargraph_label_used,
						  bargraph_label_free,
						  bargraph_label_new,
						  field_label_free,
						  field_label_new ),
			      // Button text
			      `HBox( `PushButton(`id(`rem_resize), _("&Do Not Resize") )),
			      `VSpacing(1),
			      `HBox(
				   `PushButton(`id(`ok), `opt(`default),  Label::OKButton()   ),
				   `PushButton(`id(`cancel),  Label::CancelButton() ))
			      ))));
	}
    else
	{
	simple_ui = true;
	// help text, continued - non-graphical mode only
	// this help text will be appended to the help text common to both modes.
	helptext = helptext + sformat( _("
<p>Enter a value for the size to which to shrink the %1 partition.
</p>"), windows );

	string used_label = "";
	if( win )
	    {
	    // Label text
	    used_label = _("Windows used");
	    }
	else
	    {
	    // Label text
	    used_label = _("Used");
	    }
	// help text (non-graphical mode), continued
	helptext = helptext + sformat(_("
<p>
<b>%1<b> is the size of the used part of your %2 partition.
</p>"), used_label, windows );

	// help text (non-graphical mode), continued
	helptext = helptext + _("
<p><b>Free</b> indicates the current free space (before shrinking)
of the partition.
</p>");

	UI::OpenDialog( `opt(`decorated  ),
		    `HBox(
			`HWeight(30, `RichText( helptext )),
			`HStretch(),
			`HSpacing(1),
			`HWeight(70,
			  `VBox(
			    `HBox(
				// Label for used part of the partition in non-graphical mode
				`HWeight(3, `Right(`Label(used_label+": "))),
				`HWeight(2, `Label(`opt(`outputField), sformat("%1", used ))),
				`HWeight(3, `Left(`Label( unit )))),
			    `VSpacing(0.5),
			    `HBox(
				// Label for free part of the partition in non-graphical mode
				`HWeight(3, `Right(`Label(_("Free: ")))),
				`HWeight(2, `Label(`opt(`outputField), sformat("%1", free ))), 
				`HWeight(3, `Left(`Label( unit )))),
			    `VSpacing(0.5),
			    `HBox(
				 // Edit field label for linux partition size in non-graphical mode
				`HWeight(3, `Right(`Bottom(`Label(_("New Size:"))))),
				`HWeight(2, `IntField( `id(`linux_size), "", 
						       used+min_free, used+free+av_space,
						       used+free-shrink_size)),
				`HWeight(3, `Left(`Bottom(`Label( unit ))))),
			    // Button text
			    `HBox( `PushButton( `id(`rem_resize), 
			                        _("&Do Not Resize") )),
			    `VSpacing(1),
			    `HBox(
				 `PushButton( `id(`ok), `opt(`default), 
				              Label::OKButton() ),
				 `PushButton( `id(`cancel), 
				              Label::CancelButton() ))
			   ))));
	}

    map retval = cur_val;
    any ret = `ok;

    repeat
	{
	/////////////////////////////////////////////////////////////
	// Check the User input
	ret = UI::UserInput();

	y2milestone( "ResizePartDlg ret=%1", ret );

	if( ret == `rem_resize )
	    {
	    if( simple_ui )
		UI::ChangeWidget( `id(`linux_size), `Value,  used+free );
	    else
	    UI::ChangeWidget( `id(`linux_size), `Value,  av_space );
	    }

	if( ret == `ok )
	    {
	    // Get the value the user adjusted. If s/he entered a value
	    // too big or too small this is automatically adjusted to the
	    // biggest/smallest value possible (by Qt).
	    shrink_size = (integer)UI::QueryWidget(`id(`linux_size), `Value);
	    if( simple_ui )
		{
		new_size = shrink_size;
		}
	    else
		{
		new_size = used + free + av_space - shrink_size;
		}
	    y2milestone( "ResizePartDlg Value:%1 New size:%2", shrink_size, new_size);
	    }
        if( ret == `ok )
	    {
	    if( (!simple_ui && shrink_size != av_space) ||
	        (simple_ui && shrink_size != used+free) )
		{
		retval["resize"] = true;
		retval["new_size"] = new_size*afactor;
		if( !haskey( retval, "ori_length" ))
		    {
		    integer ori_length = retval["region",1]:0;
		    retval["ori_length"] = ori_length;
		    }
		list new_reg = [ retval["region",0]:0, 
				 PartedSizeToCly( (tofloat(retval["new_size"]:0)*1024.0*1024.0),
						  cyl_size ) ];
		retval["region"] = new_reg;
		}
	    else
		{
		retval["resize"] = false;
		if( haskey( retval, "ori_length" ))
		    {
		    list new_reg = [ retval["region",0]:0, 
				     retval["ori_length"]:0 ];
		    retval["region"] = new_reg;
		    }
		}
	    }
	if( ret == `ok && !cur_val["format"]:false && retval["resize"]:false )
	    {
	    integer diff = retval["region",1]:0 - retval["ori_length"]:0;
	    y2milestone( "ResizePartDlg diff %1", diff );
	    if( !CheckResizePossible( false, false, diff,
				      cur_val["used_fs"]:`unknown,
				      cur_val["mount"]:"" ))
		{
		ret = `again;
		}
	    }
	y2milestone("ResizePartDlg ret = %1", retval );
	} 
    until( ret == `ok || ret == `cancel );

    UI::CloseDialog();

    if( ret == `cancel )
	{
	return( nil );
	}
    else
	{
	return( retval );
	}
    }



    /*---------------------------------------------------------------------
     * Display "Create a extended partition Dialog"
     *
     * return: nil bei cancel
     *         [fsid,format,mount,start_cyl,end_cyl] bei ok
     *
     *----------------------------------------------------------------------
     */
define map CreateEditExtendedPartDlg( map new_val, string title, string dev, 
                                      map disk, integer cyl_size, boolean edit, 
				      boolean bsd_label )  
    ``{
    string helptextCR = getCreateEditExtendedHelptext();

    /////////////////////////////////////////////////////////////////////////////////////////
    // title of the dialog
    term header = `Heading(title);

    UI::OpenDialog( `opt(`decorated ),
		    `VBox(
			 //`Heading(title),
			 header,
			 `VSpacing(0.5),
			 `HBox(
			       /// left side
			       `HWeight(50,`RichText( helptextCR )),
			       /// right side
			       // popup create partition: frame description Start/End Cylinder
			       `HWeight( 40,   SizeDlg( new_val , cyl_size, true) )
			       ),
			 `VSpacing(0.5),
			 `HBox(
			       // popup create partition:
			       `PushButton(`id(`ok), `opt(`default),  Label::OKButton()   ),
			       // popup create partition:
			       `PushButton(`id(`cancel), Label::CancelButton())
			       )
			 )
	          );

    UI::SetFocus(`id(`start_cyl));

    map     return_value    = $[];
    symbol  doit            = `cancel;
    repeat
        {
	//-------------------------------
	// Check the User input
	//-------------------------------
	doit = (symbol)UI::UserInput();

	if( doit != `cancel )
	    {
	    return_value = new_val;

	    list ret = [];
	    string start_cyl =  (string)UI::QueryWidget( `id(`start_cyl), `Value);
	    string end_part  =  (string)UI::QueryWidget( `id(`end_part), `Value);

	    ret = TestStartEndCyl( start_cyl, end_part, dev, disk, 
				   return_value["type"]:`primary, 
				   cyl_size, bsd_label );

	    if (ret[0]:`error == `error )
	    {
		doit = `again;
		continue;
	    }
	    if (ret[0]:`error == `max )
		{
		end_part =  ret[1]:"";
		}

	    //////////////////////////////////////////////////////////////
	    // add start_cyl and end_part to region and add region to return_value
	    list region = [ tointeger( start_cyl ), 
			    ToEndRegion( start_cyl, end_part, cyl_size )];

	    return_value["region"] = region;
	    }

        } until( doit == `cancel || doit == `ok );


    //------------------------------------------------------------------------------------
    // Check if the start end cylinder are changed: PopUp // todo change logical cylinders
    //------------------------------------------------------------------------------------
    if( doit != `cancel && edit &&
	return_value["region",0]:0 > new_val["region",0]:0 || 
	return_value["region",1]:0 != new_val["region",1]:0 )
	{
	// warning popup text
        Popup::Warning(_("You have changed the start or end cylinders.
Make sure all logical partitions 
fit into this new extended partition.
"));
	}

    UI::CloseDialog();

    if( doit == `cancel )
	{
        return( nil );
	}
    else
	{
        return( return_value );
	}
    };


    /*---------------------------------------------------------------------
     * Dialog choose disk
     * return /dev/xxx  or nil if cancel
     * what -> `create or `delete
     *---------------------------------------------------------------------
     */

define string ChooseDisk( map<string,map> targetMap, string heading, symbol what )
    ``{
    // Header Choose disk dialog
    term diskgroup  = `VBox();
    list<string> disks      = [];
    integer       n = 0;
    string txt = "";

    y2milestone( "ChooseDisk last_sel_disk:%1", last_sel_disk );

    foreach( string dev, map disk, targetMap, 
	``{
        if( Storage::IsRealDisk( dev, disk ) )
	  {
	  txt = sformat( "&%1: %2", n+1, dev );
	  diskgroup = add( diskgroup, `Left( `RadioButton( `id(dev), txt, 
	                                     n==last_sel_disk )));
	  n = n + 1;
	  disks = add ( disks, dev );
	  }
	});
    if( size(disks)>10 )
	{
	diskgroup = `VBox( `SelectionBox( `id(`disklist), _("Available &Disks"),
					  disks ));
	}
    else
	{
	diskgroup = `RadioButtonGroup( `id(`choosedisk), diskgroup );
	}

    if( size(disks) != 1 )
	{
	UI::OpenDialog( `opt(`decorated), `VBox(`Heading( heading ),
			`VSpacing(0.5),
			diskgroup,
			`VSpacing(0.5),
			`HBox(
			      // popup edit existing partition: OK
			      `PushButton(`id(`ok), `opt(`default), Label::OKButton() ),
			      // popup edit existing partition: Cancel
			      `PushButton(`id(`cancel), Label::CancelButton() )
			      )
			)
		      );
	if( UI::WidgetExists( `id(`disklist) ))
	    {
	    UI::ChangeWidget( `id(`disklist), `CurrentItem, 
	                      disks[last_sel_disk]:"" );
	    }
	symbol ret = (symbol)UI::UserInput();

	if( ret == `cancel)
	    {
	    UI::CloseDialog();
	    return( nil );
	    }
	else
	    {
	    string r = "";
	    y2milestone( "ChooseDisk exits %1", UI::WidgetExists( `id(`disklist)) );
	    if( !UI::WidgetExists( `id(`disklist) ))
		{
		r = (string)UI::QueryWidget(`id(`choosedisk), `CurrentButton);
		y2milestone( "ChooseDisk r %1", r );
		}
	    else
		{
		r = (string)UI::QueryWidget(`id(`disklist), `CurrentItem);
		}
	    UI::CloseDialog();
	    n=0;
	    if( what==`create && targetMap[r,"readonly"]:false )
		{
		Popup::Error( Partitions::RdonlyText( r, true ));
		return( nil );
		}
	    foreach( string dev, map disk, 
	             filter( string d, map e, targetMap, 
		             ``(Storage::IsRealDisk(d,e)) ),
		``{
		if( dev==r )
		    {
		    last_sel_disk = n;
		    }
		n = n+1;
		});
	    y2milestone( "ChooseDisk last_sel_disk:%1", last_sel_disk );
	    return(r);
	    }
	}
    else
	{
	// if there is only one disk: no
	return( disks[0]:"" );
	}
    };

define term RaidButton( integer num )
    ``{
    list item_list = [];
    item_list = add( item_list,
		     // menue entry text
		     `item( `id(`raid_wizard), _("&Create RAID ..") ));
    if( num>0 )
	item_list = add( item_list,
			  // menu entry text
			 `item( `id(`raid_settings), _("&Edit RAID")));
    // button text
    return( `MenuButton( _("&RAID...") , item_list  ));
    };

define term LoopButton( integer num )
    ``{
    list item_list = [];
    item_list = add( item_list,
		      // menue entry text
		     `item( `id(`loop_create), _("&Create Crypt File") ));
    if( num>0 )
	item_list = add( item_list,
			 // menue entry text
			 `item( `id(`loop_edit), _("&Edit Crypt File")));
    // button text
    return( `MenuButton( _("Cr&ypt File...") , item_list  ));
    };



    /*---------------------------------------------------------------------
     * Dialog choose primary extended or logical Partition
     * Input "PL", "PE" or "PEL"
     * return `primary or `logical or `extended or `none
     *---------------------------------------------------------------------
     */

define symbol ChoosePart( string usage )
      ``{
      term PL = `VBox(
		  // button text
		  `Left( `RadioButton( `id(`primary ), _("&Primary partition"), true )),
		  // button text
		  `Left( `RadioButton( `id(`logical ), _("&Logical partition"), false ))
		     );
      term PE = `VBox(
		  // button text
		  `Left( `RadioButton( `id(`primary ), _("&Primary partition"), true )),
		  // button text
		  `Left( `RadioButton( `id(`extended ), _("&Extended partition"), false ))
		     );
      term PEL = `VBox(
		  // button text
		  `Left( `RadioButton( `id(`primary ), _("&Primary partition"), true )),
		  // button text
		  `Left( `RadioButton( `id(`logical ), _("&Logical partition"), false )),
		  // button text
		  `Left( `RadioButton( `id(`extended ), _("&Extended partition"), false ))
		      );

      term                 current = PEL;        // default
      if ( usage == "PL" ) current = PL;
      if ( usage == "PE" ) current = PE;

      UI::OpenDialog( `opt(`decorated ), 
		      // heading in a popup dialog
                      `VBox(`Heading(_("Which type of partition do you want to create?") ),
		            `VSpacing(0.5),
			    `RadioButtonGroup( `id(`choosePL), current ),
			    `VSpacing(0.5),
			    `HBox(
				  // popup edit existing partition: OK
				  `PushButton(`id(`ok),  `opt(`default), Label::OKButton() ),
				  // popup edit existing partition: Cancel
				  `PushButton(`id(`cancel), Label::CancelButton()   )
				  )
			    )
		    );
      symbol ret = (symbol)UI::UserInput();

      if (ret == `cancel)
	  {
	  UI::CloseDialog();
	  return(`none);
	  }
      else
	  {
	  ret = (symbol)UI::QueryWidget(`id(`choosePL), `CurrentButton);
	  UI::CloseDialog();
	  return(ret);
	  }
    };


    /*---------------------------------------------------------------------
     * Make a output string for "you can not create a partition, because: "
     *---------------------------------------------------------------------
     */


define string FormatCauseLine( symbol cause )
    ``{
    if( cause == `no_ext )   
	// popup text
	return( _("No extended partition exists."));
    if( cause == `dev_full ) 
	// popup text
	return( _("There are already four primary and extended partitions."));
    if( cause == `no_extsp ) 
	// popup text
	return( _("No space is left in the extended partition."));
    if( cause == `to_many )  
	// popup text
	return( _("Too many logical drives already exist."));
    if ( cause == `no_space ) 
	// popup text
	return( _("No space remaining."));
    if ( cause == `already )  
	// popup text
	return( _("An extended partition already exists."));
    return( "---" );
    };


    /*---------------------------------------------------------------------
     * Make a output string for "you can not create a partition, because: "
     *---------------------------------------------------------------------
     */

define string FormatYouCannotCause( boolean primary_is_possible,
				    boolean extended_is_possible,
				    boolean logical_is_possible,
				    symbol  no_primary_cause,
				    symbol  no_extended_cause,
				    symbol  no_logical_cause )
    ``{
    string pri_line = "";
    string ext_line = "";
    string log_line = "";

    y2milestone( "prim:%1 ext:%2 log:%3 (%4 %5 %6)", primary_is_possible,
                 extended_is_possible, logical_is_possible, no_primary_cause,
		 no_extended_cause, no_logical_cause );

    if( primary_is_possible )	
	// popup text
	pri_line = _("Primary partition creation is possible\n");
    else
	// label text
	// example "No primary partition: No space left"
	pri_line = _("No primary partition:  ") + 
	           FormatCauseLine( no_primary_cause ) + "\n";

    if( logical_is_possible ) 
	// popup text
	log_line = _("Logical partition creation is possible\n");
    else
	if( no_logical_cause != `impossible )
	    // label text
	    // example "No logical partition: No space left
	    log_line = _("No logical partition:  ") +
		       FormatCauseLine( no_logical_cause ) +"\n" ;

    if ( extended_is_possible )	  
	// popup text
	ext_line = _("Extendend partition creation is possible\n");
    else
	if( no_logical_cause != `impossible )
	    // label text
	    // example "No extended partition: No space left
	    ext_line = _("No extended partition: ") + 
		       FormatCauseLine( no_extended_cause ) +"\n";

    return ( pri_line + ext_line + log_line );
    };


    /////////////////////////////////////////////////////////////////
    // MAIN:
    /////////////////////////////////////////////////////////////////

    symbol ret = nil;

    Storage::SetLvmUse( true );
    
    y2milestone( "Custom partitioner started" );

    SCR::Write(.target.ycp, Storage::SaveDumpPath("targetMap_s"), 
               Storage::GetTargetMap() );

    // delete pseudo partitions with `free from target_partitioner
    map<string,map> tg = Storage::GetTargetMap();
    foreach( string diskdev, map disk, tg,
	``{
	list<map> partitions = filter( map part, disk["partitions"]:[], 
	                          ``(part["type"]:`unknown != `free) );
	disk["partitions"] = partitions;
	tg[diskdev] = disk;
	});
    Storage::SetTargetMap( tg );

    list table_list = FillPartitionList();

    if( size(Storage::GetTargetBackup("custom_part"))==0 )
	{
	Storage::CreateTargetBackup("custom_part");
	}

    /////////////////////////////////////////////////////////////////
    ///              MAIN DIALOG

    term header = `header();

    // Column header
    if ( showT_dev )    header = add( header, _("Device"));
    // Column header
    if ( showT_id )     header = add( header, _("Id"));
    // Column header: centered / minimum = 11 characters /
    // fill with space if needed
    if ( showT_size )   header = add( header, `Right(_("     Size   ")));
    // Column header: centered / minimum = 3 characters /  
    // fill with space if needed
    if ( showT_format ) header = add( header, `Right(_(" F ")));
    // Column header
    if ( showT_fs )     header = add( header,  _("Type"));
    // Column header: centered / minimum = 7 characters /  
    // fill with space if needed
    if ( showT_mount )  header = add( header, _(" Mount "));
    // Column header: minimum = 5 characters   fill with space if needed
    if ( showT_cyl )    header = add( header, `Right(_("Start")));
    // Column header: minimum = 4 characters   fill with space if needed
    if ( showT_cyl )    header = add( header, `Right(_("End ")));
    // Column header 
    if ( showT_Used )   header = add( header, `Left(_("Used by")));
    // Column header 
    if ( showT_Label )  header = add( header, `Left(_("Label")));

    /////////////////////////////////////////////////////////////////
    //    MAIN LAYOUT
    // ---------------------------

    term buttonline_a = `HBox();

    // main dialog: Button Create partition
    if ( button_create ) buttonline_a = add( buttonline_a, `PushButton(`id(`create), _("&Create")) );
                                                           
    // main dialog: Button Edit partition
    if ( button_edit   ) buttonline_a = add( buttonline_a, `PushButton(`id(`edit),   _("&Edit"))   );

    // main dialog: Button Delete partition
    if ( button_delete ) buttonline_a = add( buttonline_a, `PushButton(`id(`delete), _("&Delete")) );

    // main dialog: Button Resize partition
    if ( button_resize ) buttonline_a = add( buttonline_a, `PushButton(`id(`resize), _("Re&size")) );


    
    list expert_item_list =[];
    if( button_reread ) 
	expert_item_list = 
	    add( expert_item_list , 
	         // menu entry text
		 `item( `id (`reread),  _("&Reread partition table")));
    if( button_adapt_mp ) 
	expert_item_list = 
	    add( expert_item_list, 
		 `item( `id (`adapt_mp), 
			// menu entry text
		        _("&Import mount points from existing /etc/fstab")));
    if ( button_delete_parttable ) 
	expert_item_list = 
	    add( expert_item_list,  
		 `item( `id (`delete_parttable),
			// menu entry text
		        _("Delete partition &table and disk label")));
    if( Arch::s390 () )
	{
	expert_item_list = 
	    add( expert_item_list,
		 `item( `id(`dasdfmt),
			// menu entry text
		        _("Execute dasd&fmt on the DASD Device")));
	buttonline_a = add( buttonline_a, `PushButton(`id(`dasdfmt), 
	                    _("dasd&fmt")) );
	}

    
    term buttonline_b = `HBox();
    
    if( button_lvm )   
	// main dialog: Button LVM
	buttonline_b = add( buttonline_b, `PushButton(`id(`lvm), _("&LVM...")));

    if( button_evms )   
	// main dialog: Button EVMS
	buttonline_b = add( buttonline_b, `PushButton(`id(`evms), _("E&VMS...")));

    // main dialog: Button RAID
    if( button_raid )  
	buttonline_b = 
	    add( buttonline_b, 
		 `ReplacePoint( `id(`raid_button),
			        RaidButton(size(tg["/dev/md","partitions"]:[]))));

    // main dialog: Button LOOP
    if( button_loop )  
	buttonline_b = 
	    add( buttonline_b, 
		 `ReplacePoint( `id(`loop_button),
			        LoopButton(size(tg["/dev/loop","partitions"]:[]))));

    if( button_expert) buttonline_b = 
	// main dialog: Menu-Button for Expert options 
	add( buttonline_b, `MenuButton ( _("E&xpert.."), expert_item_list ));


   


    term contents = `VBox( `VSpacing(0.5), 
                           `Table( `id(`table), `opt(`notify,`keepSorting), 
				   header, table_list ), 
			   buttonline_a, 
			   buttonline_b ) ;

    string help_text = "";
    if( Arch::s390 () )
	{
	help_text = getMainHelptextS390();
	}
    else
	{
	help_text = getMainHelptext(Stage::initial ());
	}

    // Main dialog: Header

    string back_label = "";
    string next_label = "";
    if( Stage::initial () )
	{
	back_label = Label::BackButton();
	next_label = Label::FinishButton();
	}
    else
	{
	back_label = Label::QuitButton();
	// button text
	next_label =  _("&Apply");
	Wizard::HideAbortButton();
	}

    // heading text 
    Wizard::SetContentsButtons(_("Expert Partitioner"), contents, help_text,
                               back_label, next_label );


   //////////////////////////////////////////////////////////////////
   ////  Loop for User Input ....
   //////////////////////////////////////////////////////////////////

    repeat
        {
        table_list = FillPartitionList();
        UI::ChangeWidget(`id(`table), `Items, table_list);

	///////////////////////////////////////////////////////
	// Now set the focus
	// (only for "show_disk" cause I use the disk line)

	if( show_disk )
	    {
	    UI::SetFocus( `id(`table));
	    y2milestone( "focusline %1", focusline );
	    if( size(focusline)>0 )
	        {
	        UI::ChangeWidget(`id(`table), `CurrentItem, focusline);
	        }
	    }

        ret = (symbol)Wizard::UserInput();

	y2milestone( "USERINPUT: %1", ret);


        /////////////////////////////////////////////////////////////
        ////  CREATE
        /////////////////////////////////////////////////////////////
        if( ret == `create)
	    {
            string maindev = 
	       ChooseDisk(Storage::GetTargetMap(), 
			  // popup text 
	                  _("On which disk would you like to create the partition?"),
			  `create  );

	    if( maindev == nil )
		{
		ret = `again;
		continue;
		}

	    symbol  create_type = `none;
	    map     curr_disk   = Storage::GetMainDev( maindev );

	    list possibilities = CheckCreatePossibilities( maindev, curr_disk );
	    y2milestone( "possibilities %1", possibilities );

	    boolean primary_is_possible  = possibilities[0]:false;
	    boolean extended_is_possible = possibilities[1]:false;
	    boolean logical_is_possible  = possibilities[2]:false;

	    symbol  no_primary_cause     = possibilities[3]:`no_space;
	    symbol  no_extended_cause    = possibilities[4]:`no_space;
	    symbol  no_logical_cause     = possibilities[5]:`no_space;

	    list log_slot = [];
	    list p_e_slot = [];

	    //////////////////////////////////////////////////////////
	    // Test if there is space left on the device
	    log_slot = GetLogicalSlot(maindev, curr_disk);
	    y2milestone( "log_slot %1", log_slot );
	    p_e_slot = GetSlot(maindev, curr_disk);
	    y2milestone( "p_e_slot %1", p_e_slot );

	    if ((log_slot == nil) && logical_is_possible ) 
		no_logical_cause  = `no_space;
	    if ((p_e_slot == nil) && primary_is_possible ) 
		no_primary_cause  = `no_space;
	    if ((p_e_slot == nil) && extended_is_possible) 
		no_extended_cause = `no_space;

	    if (log_slot == nil) 
		logical_is_possible  = false;
	    if (p_e_slot == nil) 
	        primary_is_possible  = false;
	    if (p_e_slot == nil) 
	        extended_is_possible = false;



	    /*----------------------------------------------------------------------
	    *   Intel/Fdisk  PPC/Fdisk
	    *
	    *   At the same time is not possible, that both "logial_part_is_possible"
	    *   and "extended_part_is_possible" are true
	    *   so we have 6 possible situations
	    *
	    *   to show this we use
	    *   "P" for primary_part_is_possible
	    *   "E" for extended_part_is_possible
	    *   "L" for logial_part_is_possible
	    *
	    *   "p" for primary_part_is_possible  == false
	    *   "e" for extended_part_is_possible == false
	    *   "l" for logial_part_is_possible  == false
	    *
	    *
	    *   PE  : I can create a primary or exended part.
	    *   PL  : Extended part. exist. I can create a primary or a logical
	    *   Pel : only a priary is possible, when the extended part. has no space left
	    *
	    *   pE  : Not possible, if "E" is possible always "P" is possible too.
	    *   pL  : only a logical is possible, if together 4 primary and extended
	    *          partitions are already created
	    *   pel : no partitions are possible
	    *
	    *   --------------------------------------------------------------------
	    *
	    *   BSD-Labeling:
	    *   "Pel" for primary_part_is_possible
	    *   "pel" for primary_part_is_possible  == false
	    *
	    *--------------------------------------------------------------------------*/

	    if( !primary_is_possible  && !extended_is_possible && 
	        !logical_is_possible )
		{
		// ------pel--------
		string text = "";

		if( curr_disk["label"]:"msdos" != "msdos" )
		    {
		    // popup text , %1 is replaced by a disk name e.g. /dev/hda
		    text = sformat( _("It is not possible to create a partition on %1 "), maindev);
		    }
		else
		    {
		    // popup text , %1 is replaced by a disk name e.g. /dev/hda
		    // %2 is replaced by an explanation
		    text = sformat( _("It is not possible to create a partition on %1

%2
"), maindev,
				    FormatYouCannotCause( primary_is_possible,
				                          extended_is_possible,
							  logical_is_possible,
							  no_primary_cause,
							  no_extended_cause,
							  no_logical_cause ));
		    }
		Popup::Warning(text);
		}
	    else if( !primary_is_possible && logical_is_possible )
		{
		//------pL----------
		create_type = `logical;
		}
	    else if( !primary_is_possible && extended_is_possible )
		{
		//------pE----------
		create_type = `extended;
		}
	    else if( primary_is_possible && !extended_is_possible && 
	             !logical_is_possible )
		{
		//------Pel----------
		create_type = `primary;
		}
	    else if ( primary_is_possible  && extended_is_possible )
		{
		//------PE----------
		create_type = ChoosePart("PE");   // maindev
		}
	    else if ( primary_is_possible  && logical_is_possible )
		{
		//------PL----------
		create_type = ChoosePart("PL");     // popup
		}
	    else
		{
		y2error("Error during partition check" );
		create_type = ChoosePart("PEL");   // popup
		}

	    if( create_type != `none )
		{
		list<map> partitions 	= curr_disk["partitions"]:[];
		integer curr_nr    	= 0;
		list<integer>    base   = [];
		list    slot       	= [];

		// search for the first possible dev nr
		if( create_type == `primary || create_type == `extended || 
		    create_type == `logical )
		    {
		    integer i = 1;
		    integer mx = curr_disk["max_primary"]:4;
		    slot = p_e_slot;
		    if( create_type == `logical )
			{
			i = 5;
			mx = curr_disk["max_logical"]:63;
			slot = log_slot;
			}
		    while( i<=mx )
			{
			base = add( base, i );
			i = i+1;
			}
		    if( bsd_label )
			{
			base = filter( integer p, base, ``(p!=3));
			}
		    y2milestone( "base %1", base );

		    //----------------------------------------------------------
		    // dev_nb List of numbers of  extende an primary partitions
		    // result: list of all free primaty|extended partition numbers

		    list<integer> dev_nb = 
			maplist( map part, 
			         filter( map pa, partitions, 
					         ``(!pa["delete"]:false)), 
				 ``(part["nr"]:0) );
		    list<integer> result = 
			filter( integer base_nr, base, 
				``( find( integer nr, dev_nb, 
				          ``(nr == base_nr)) == nil));
		    result = sort( result );

		    curr_nr = result[0]:0;
		    }


		//---------------------------------------------------
		// Present the Create-Popups ...
		//---------------------------------------------------

		string titleC = "";
		// %1 and %3 are not neccecary anymore, dur to the translation, i have not changed it.
		// Popup Create Partition: Description of partition %1 and %3 are free space,  %2 is for example "/dev/hda3"
		if ( create_type == `primary )  titleC = sformat( _("%1 Create a primary partition on %2 %3"),   "", maindev, "" );
		// Popup Create Partition: Description of partition %1 and %3 are many spaces,  %2 is for example "/dev/hda3"
		if ( create_type == `extended ) titleC = sformat( _("%1 Create an extended partition on %2 %3"), "", maindev, "" );
		// Popup Create Partition: Description of partition %1 and %3 are many spaces,  %2 is for example "/dev/hda3"
		if ( create_type == `logical )  titleC = sformat( _("%1 Create a logical partition on %2 %3"),   "", maindev, "" );

		map<string,any> new_val = 
		    $[
		    "create" : true,
		    "region" : [ slot[0]:0, slot[1]:0 - slot[0]:0+1 ],
		    "type"   : create_type,
		    "nr"     : curr_nr,
		    "device" : Storage::GetDeviceName( maindev, curr_nr )
		    ];


		if( create_type == `extended )
		    {
		    new_val = (map<string,any>)union( new_val , 
			$[
			"fsid"    : Partitions::fsid_extended_win,
			"used_fs" : `unknown,
			"fstype"  : "Extended"
			 ]);

		    new_val = 
			(map<string,any>)CreateEditExtendedPartDlg( new_val,
								    titleC,
								    maindev,
								    curr_disk,
								    curr_disk["cyl_size"]:1000000,
								    false,
								    bsd_label );
		    }
		else
		    {
		    string mount_point_proposal = 
			GetMountPointProposal( Storage::GetTargetMap(), [] );
		    symbol used_fs = Partitions::default_fs;
		    if( mount_point_proposal == Partitions::BootMount() )
			{
			used_fs = Partitions::DefaultBootFs();
			}
		    new_val = 
			(map<string,any>)union( new_val, 
			    $[
			    "format" : true,
			    "fsid"   : Partitions::fsid_native,
			    "mount"  : mount_point_proposal,
			    "used_fs": used_fs,
			     ]);

		    if( Mode::repair () )
			{
			new_val["format"] = false;
			new_val["mount" ] = "";
			}
		    
		    new_val = EditOrCreatePartDlg( new_val,
						   FileSystems::GetAllFileSystems(true, true ),
						   titleC,
						   curr_disk,
						   bsd_label,
						   edit_cylinder,
						   curr_disk["cyl_size"]:1000000,
						   Stage::initial ()
						 );
		    }

		if (new_val != nil)
		    {
		    // set focus to new partition
		    focusline = Storage::GetSubDevKey( maindev, curr_nr );
		    Storage::AddSubDev( focusline, new_val );
		    }
		}
	    }

      ///////////////////////////////////////////////////////////////
      ////  EDIT
      ///////////////////////////////////////////////////////////////

        if( ret == `edit || ret == `table )
	    {
	    any w_id = UI::QueryWidget(`id(`table), `CurrentItem);

	    // notify a line is selected
            if( w_id != nil )
		{
		string id = (string)w_id;
		focusline = (string)w_id;
		string maindevkey = Storage::GetMainDevKey(id); 
		string subdevkey = Storage::GetSubDevIndex(id); 
		y2milestone( "Chosen: %1 maindev: %2 subdev:\"%3\"", id, 
		             maindevkey, subdevkey );
            
		if( maindevkey == id )
		    {
		    if( (boolean)Storage::GetMainDevParam( id, "is_lvm_vg", false) )
			{
			ret = `lvm;
			}
		    else
			{
			TargetAllocationDlg(Storage::GetTargetMap()[id]:$[], id );
			}
		    }
		else if( Storage::IsSubDevLv( id ) )
		    {
		    map<string,map> tg =  Storage::GetTargetMap();
		    map<integer,map> mt =  (map<integer,map>)Storage::GetModifyTargets();
		    map ret = HandleEditLv( tg, mt, id );
		    Storage::SetTargetMap( ret["targets"]:tg );
		    Storage::SetModifyTargets( ret["modify_targets"]:mt );
		    }
		else if( maindevkey == "/dev/md" )
		    {
		    map<string,any> part = Storage::GetSubDev( id );
		    part = RaidExpertDlg( `settings, "/dev/md" + subdevkey,
					   part, Stage::initial (),
					   FileSystems::GetAllFileSystems(true,true),
					   false, Storage::GetTargetMap());
		    if( part!=nil && size(part)>0 )
			{
			Storage::SetSubDev( id, part );
			}
		    }
		else if( find( maindevkey, "/dev/evms" )==0 )
		    {
		    string dev = maindevkey+"/"+subdevkey;
		    map ad = edit_evms_volume( dev, Storage::GetTargetMap() );
		    // has the user cancelled the dialog?
		    if( ad["ok"]:false && size( ad["targets"]:$[] )>0 )
			{
			Storage::SetTargetMap( ad["targets"]:$[] );
			}
		    }
		else if( maindevkey == "/dev/loop" )
		    {
		    ret = `loop_edit;
		    }
		else
		    {
		    map new_val 	   = $[];
		    
		    string subdevindex = Storage::GetSubDevIndex(id);
		    integer number     = tointeger( subdevindex );
		    map<string,any> curr_disk      = Storage::GetMainDev( maindevkey );
		    map<string,any> curr_part      = Storage::GetSubDev( id );

		    
		    /////////////////////////////////////////////////////
		    // check if the partition can be deleted
		    
		    if( check_partition_edit( curr_part, bsd_label) != `edit )
			{
			ret = `again;
			continue;
			}
		    
		    if( test_mode )
			{
			y2debug("List: %1 %2", curr_disk["partitions"]:[], number);
			}

		    list<map> partitions_without_current = 
			filter( map p, curr_disk["partitions"]:[], 
				``(p["nr"]:(any)0!=number && 
				   !p["delete"]:false ));
		    map<string,any> disk_without_current = add( curr_disk, "partitions", 
						    partitions_without_current);
		    map<string,any> target_without_current = add( Storage::GetTargetMap(), 
						      maindevkey, 
						      disk_without_current );

		    //////////////////////////////////////
		    // There are three different Editors:
		    // - "normal"
		    // - extended
		    // - already existing
		    
		    y2debug( "current partition %1", curr_part );

		    if( Storage::IsSubDevExtended( id )  )
			{
			if( curr_part["create"]:false )
			    {
			    // header of the dialog edit a partition
			    string title = _("Edit an Extended Partition") + 
			                   " " + curr_part["device"]:"";
			    new_val = CreateEditExtendedPartDlg( curr_part,
								 title,
								 curr_part["device"]:"",
								 disk_without_current,
								     curr_disk["cyl_size"]:1000000,
								 true,
								 bsd_label
							       );
			    }
			else
			    {
			    // error popup text
			    Popup::Error( _("An already-existing extended partition cannot be changed.
Delete this partition then create a new one using 
the new parameters.
WARNING: All data on this partition will be lost."));
			    new_val = nil;
			    }
			}
		    else
			{
			string title = "";
			if( !curr_part["create"]:false )
			    {
			    // header of the dialog edit a partition
			    title = _("Edit Existing Partition");
			    }
			else
			    {
			    // header of the Dialog edit a partition
			    title = _("Edit partition ");
			    }
			title = title + curr_part["device"]:"";

			new_val = 
			    EditOrCreatePartDlg( curr_part,
						 FileSystems::GetAllFileSystems(true, true) ,
						 title, 
						 disk_without_current,
						 bsd_label, edit_cylinder,
						 curr_disk["cyl_size"]:1000000,
						 Stage::initial () );
			}
		    if( new_val != nil && size(new_val)>0 )   // not canceld    
			{ 
			Storage::SetSubDev( id, new_val );
			}	
		    }
	        }
	    else
	        {
                // popup text
                Popup::Message(_("To edit a partition, please select one in the main dialog.") );
	        }
	    }

        /////////////////////////////////////////////////////////////
        // DELETE
        /////////////////////////////////////////////////////////////
        if (ret == `delete)
	    {
	    string id = (string)UI::QueryWidget( `id(`table), `CurrentItem);
	    string maindevkey = Storage::GetMainDevKey(id);
	    string subdevkey = Storage::GetSubDevIndex(id); 
	    
	    if( ! Storage::IsKeyKey(id))
	    {
		ret = `again;
		continue;
	    }

	    map<string,map> tmap = Storage::GetTargetMap();
	    if( tmap[maindevkey,"readonly"]:false )
		{
		Popup::Error( Partitions::RdonlyText( maindevkey, true ));
		ret = `again;
		continue;
		}
	 
	    if( maindevkey == id )
		{
		if( Storage::IsMainDevMd(maindevkey))
		    {	
		    ret = `again;
		    continue;
		    }
		else if( Storage::IsMainDevVg(maindevkey ))
		    {
		    string current_vg = substring( maindevkey, 5 );
		    map<string,map> tg =  Storage::GetTargetMap();
		    map<integer,map> mt = (map<integer,map>)Storage::GetModifyTargets();
		    map ret = HandleRemoveVg( tg, mt, current_vg );
		    Storage::SetTargetMap( ret["targets"]:tg );
		    Storage::SetModifyTargets( ret["modify_targets"]:mt );
		    }
                // popup text %1 is replaced by a disk name e.g. /dev/hda
		else if( Popup::YesNo ( sformat(_("Do you really want to delete all partitions on %1?"), id )))
		    {
		    focusline = id;
		    map new_targetMap = deleteAllDevPartitions( tmap,
								id,
								Stage::initial (),
								bsd_label );
		    y2milestone( "new_targetMap %1", new_targetMap );
		    if( new_targetMap != nil && size(new_targetMap)>0 )
			{
			Storage::SetTargetMap( new_targetMap );
			}
		    }
		}
	    else if( Storage::IsSubDevLv(id))
		{
		map<string,map> tg =  Storage::GetTargetMap();
		map<integer,map> mt =  (map<integer,map>)Storage::GetModifyTargets();
		map ret = HandleRemoveLv( tg, mt, id );
		Storage::SetTargetMap( ret["targets"]:tg );
		Storage::SetModifyTargets( ret["modify_targets"]:mt );
		} 
            else
		{
                /////////////////////////////////////////////////////
                // delete algorithm:
                // if you find newly created (but until now not realy 
		// written) partition (sign: "create = true"): delete it
                // else there must be already existing partition: mark it 
		// with "delete = true"
		
		focusline          	= id;
		string  subdevindex	= Storage::GetSubDevIndex(id);
		map curr_disk  		= Storage::GetMainDev( maindevkey );
		map curr_part 		= Storage::GetSubDev( id );

		y2milestone( "delete main %1 part %2 subdevindex %3", 
		             maindevkey, curr_part, subdevindex );
		/////////////////////////////////////////////////////
		// check if the partition can be deleted
		
		symbol ret_delete = check_partition_delete( curr_disk, 
							    curr_part, 
							    bsd_label,
							    true,  // bsd_check
							    true,  // lvm_check
							    true ,
							    Stage::initial () ); 


		if( ret_delete == `immediate_prepdisk )
		    {
		    immediate_prepdisk = true;
		    }

		else if ( ret_delete == `no_delete )
		    {
		    ret = `again;
		    continue;
		    }

		if( Storage::IsSubDevExtended( id ) )
		    {
		    if( !check_extended_delete( maindevkey, curr_disk, 
		                                Stage::initial () ) )
			{
			ret = `again;
			continue;
			}
		    }

		/////////////////////////////////////////////////////
		// now delete partition!!
		
                // popup text, %1 is replaced by a device name e.g. /dev/hda1
		if( Popup::YesNo( sformat(_("Do you really want to delete partition %1?"), 
		                            curr_part["device"]:"" )))
		    {
		    if( maindevkey == "/dev/loop" && size(curr_part["fpath"]:"")>0 )
			{
			if( Mode::normal () && 
			    Popup::YesNo( sformat(_("\nShould the loop file %1 also be removed?
"), curr_part["fpath"]:"" )))
			    {
			    map<string,map> tg =  Storage::GetTargetMap();
			    tg = Storage::SetPartitionData( tg, 
			                                    curr_part["device"]:"",
							    "fpath_remove", 
							    true );
			    Storage::SetTargetMap( tg );
			    }
			}
		    Storage::DelSubDev( id );
		    focusline = Storage::GetIdSmaller( maindevkey, 
		                                       tointeger(subdevindex));
		    }
		if( maindevkey == "/dev/md" )
		    {
		    map raid = Storage::GetMainDev( maindevkey );
		    UI::ReplaceWidget( `id(`raid_button),
				       RaidButton(size(raid["partitions"]:[])) );
		    }
		if( maindevkey == "/dev/loop" )
		    {
		    map dev = Storage::GetMainDev( maindevkey );
		    UI::ReplaceWidget( `id(`loop_button),
				       LoopButton(size(dev["partitions"]:[])) );
		    }
		}
	    }


        /////////////////////////////////////////////////////////////
        // RESIZE
        /////////////////////////////////////////////////////////////
        if (ret == `resize)
	    {
	    string id = (string)UI::QueryWidget(`id(`table), `CurrentItem);
	    string maindevkey 	= Storage::GetMainDevKey( id);
	    map curr_part 	= Storage::GetSubDev( id );
	    map curr_disk  	= Storage::GetMainDev( maindevkey );
	    focusline = id;

	    map tmap = Storage::GetTargetMap();
	    if( tmap[maindevkey,"readonly"]:false )
		{
		Popup::Error( Partitions::RdonlyText( maindevkey, true ));
		ret = `again;
		continue;
		}
	 
	    y2milestone( "disk=%1", curr_disk );
	    y2milestone( "RESIZE id=%1 maindev=%2 part=%3", 
	                 id, maindevkey, curr_part );
	    map possible = Storage::IsResizable( curr_part );
	    if( id == maindevkey || 
	        size( curr_part["lvm_group"]:"") > 0 ||
	        size( curr_part["raid_name"]:"") > 0 ||
	        find( curr_part["device"]:"", "/dev/md" )==0 )
		{
                // popup text
		Popup::Message(_("
You cannot resize a disk device, an LVM volume group, an LVM physical volume,
or an MD Device.
"));
		}
	    else if( !curr_part["format"]:false &&
	        !possible["extend"]:false && !possible["shrink"]:false )
		{
                // popup text
		Popup::Message(_("
You cannot resize the selected partition because the file system
on this partition does not support being resized.
"));
                }
	    else if( Storage::IsSubDevLv(id))
		{
		map<string,map> tg =  Storage::GetTargetMap();
		map<integer,map> mt =  (map<integer,map>)Storage::GetModifyTargets();
		map ret = HandleEditLv( tg, mt, id );
		Storage::SetTargetMap( ret["targets"]:tg );
		Storage::SetModifyTargets( ret["modify_targets"]:mt );
		}
	    else if( curr_part["create"]:false )
		{
                // popup text
		Popup::Message(_("
You cannot resize the selected partition because this partition 
does not exist on your disk right now. It will be created 
by YaST2 later.

To change the size of this partition, use \"Edit\" instead 
of \"Resize\".
"));
		}
	    else
		{
		map new_val = (map)eval(curr_part);
		if( Mode::normal () && new_val["used_fs"]:`none == `ntfs )
		    {
		    Package::InstallAll( ["ntfsprogs"] );
		    }
		string dev = new_val["device"]:"";
		if( new_val["ori_nr"]:0 > 0 && new_val["ori_nr"]:0 != new_val["nr"]:0 )
		    {
		    dev = Storage::GetDeviceName( maindevkey, new_val["ori_nr"]:0 );
		    }
		new_val = ResizePartDlg( new_val, dev, curr_disk, possible );
		if( new_val != nil )
		    {
		    integer size_change = curr_part["region",1]:0 -
			                  new_val["region",1]:0;
		    y2milestone( "region old=%1 new:%2", curr_part["region"]:[],
		                 new_val["region"]:[] );
		    y2milestone( "size_change=%1", size_change );
		    if( size_change != 0 &&
		        Storage::CheckNextCreated( curr_disk, 
			                           curr_part["region"]:[0,0] ))
			{
			if( size_change < 0 )
			    {
			    // popup text
			    Popup::Message( _("
You decreased the size available for Linux parititons. 
Linux partition sizes have been adapted accordingly.
Check the new sizes in the partition list.
"));
                            Storage::AdaptResize( maindevkey, 
			                          curr_part["region"]:[0,0],
						  size_change );
			    }
			// popup text
			else if( Popup::YesNo( _("
You decreased a partition that is followed by a newly-created partition.
Should the newly-created partition be automatically increased to use the 
freed disk space?
")) )
			    {
                            Storage::AdaptResize( maindevkey, 
			                          curr_part["region"]:[0,0],
						  size_change );
			    }
			}
		    Storage::SetSubDev( id, new_val );
		    }
		}
	    }

	boolean ask_reread = true;
	
        /////////////////////////////////////////////////////////////
        // Delete partition table and disk label
        /////////////////////////////////////////////////////////////
	
        if( ret == `delete_parttable )
	    {
	    tg = Storage::GetTargetMap();
	    string maindev = ChooseDisk( tg,
	                                 // heading text
	                                 _("Delete partition table:"),
					 `delete );

	    // not cancel
	    if( maindev != nil )
		{
		if( DDZeroPartitionTable(maindev))
		    {		    
		    tg[maindev,"readonly"] = false;
		    Storage::SetTargetMap(tg);
		    // now reread partion table -> ret == `reread 
		    ask_reread = false;
		    ret = `reread;
		    }
		}
	    }

	if( Arch::s390 () && ret==`dasdfmt )
	    {
	    string id = (string)UI::QueryWidget(`id(`table), `CurrentItem);
	    string maindevkey 	= Storage::GetMainDevKey(id);
	    map tg = Storage::GetTargetMap();
	    map disk = tg[maindevkey]:$[];

	    y2milestone( "dasdfmt disk:%1", maindevkey );

	    if( Storage::IsKeyMainDevKey(id) && 
	        find( maindevkey, "/dev/dasd")==0 )
		{
		if( !disk["dasdfmt"]:false)
		    {
		    // popup text %1 is replaced by a dasd name e.g. /dev/dasda
		    boolean yn = Popup::YesNo(sformat(
_("Really execute dasdfmt on disk %1?
All data on this disk will be lost.
"),maindevkey));
		    y2milestone( "yn=%1", yn );
		    if( yn )
			{
			disk["dasdfmt"] = true;
			list<map> pl = filter( map p, disk["partitions"]:[],
					       ``(!p["create"]:false));
			pl = maplist( map p, pl, 
			    ``{
			    p["delete"] = true;
			    return(p);
			    });
			list pn = 
			    StorageDevices::GetS390Partitions( maindevkey,
							       disk, [] );
			pl = (list<map>)union( pl, pn );
			disk["partitions"] = pl;
			tg[maindevkey] = disk;
			Storage::SetTargetMap( tg );
			}
		    }
		else
		    {
		    Popup::Message( _("Flag to run dasdfmt for the disk removed.

Partitions currently present on this disk are displayed
again.
") );
		    disk["dasdfmt"] = false;
		    list<map> pl = filter( map p, disk["partitions"]:[],
					   ``(!p["create"]:false));
		    pl = maplist( map p, pl, 
			``{
			p["delete"] = false;
			return(p);
			});
		    disk["partitions"] = pl;
		    tg[maindevkey] = disk;
		    Storage::SetTargetMap( tg );
		    }
		}
	    else
		{
		// popup text 
		Popup::Error( _("No DASD disk selected.
Select the DASD disk for which dasdfmt should be executed."));
		}
	    }

	
        /////////////////////////////////////////////////////////////
        // REREAD
        /////////////////////////////////////////////////////////////

        if (ret == `reread)
	    {
	    boolean ret2 = true;

	    if( ask_reread ) 
		// popup text
		ret2 = Popup::YesNo(_("Do you really want to reread the partition table?\nAll current changes made in this dialog will be lost!")); 

	    if( ret2 )
		{
		Storage::ReReadTargetMap();
		}
	    }


	/////////////////////////////////////////////////////////////
        // Raid
        /////////////////////////////////////////////////////////////
	
        if( ret == `raid_wizard )
	    {
	    if( !check_raid_possible( Storage::GetTargetMap() ))
	        {
		ret = `again;
		continue;
		}
	    }

	if( ret == `loop_edit || ret == `loop_create )
	    {
	    string id = (string)UI::QueryWidget( `id(`table), `CurrentItem );
	    Storage::SetWizardKey( id );
	    if( ret == `loop_edit )
		{
		if( Storage::GetMainDevKey(id) != "/dev/loop" )
		    {
		    // popup text
		    Popup::Message( _("Select a loop device entry.") );
		    ret = `again;
		    continue;
		    }
		}
	    LoopSetup( ret==`loop_edit );
	    if( ret==`loop_create )
		{
		map dev = Storage::GetMainDev( "/dev/loop" );
		UI::ReplaceWidget( `id(`loop_button),
				   LoopButton(size(dev["partitions"]:[])) );
		}
	    }
	
	/////////////////////////////////////////////////////////////
        // LVM
        /////////////////////////////////////////////////////////////
	
        if (ret == `lvm)
	    {
	    if( ! check_lvm_possible( Storage::GetTargetMap() ) )
		{
		ret = `again;
		continue;
		}
	    else if( Mode::normal () )
		{
		Package::InstallAll( ["lvm2"] );
		}
	    }
	
	/////////////////////////////////////////////////////////////
        // Adapt mount points from existing /etc/fstab
        /////////////////////////////////////////////////////////////

        if (ret == `adapt_mp && Stage::initial () )
	    {
	    map<string,map> od = (map<string,map>)Storage::GetOndiskTarget();
	    list<list> fstab = scanAndReadExistingFstab( od );
	    y2milestone( "adapt_mp fstab %1", fstab );
	    list ti = maplist( list e, fstab, 
	                       ``(AddFstabToData( od, (list<map>)e)[1]:$[]));
	    y2milestone( "adapt_mp ti %1", ti );

	    integer idx = FstabAddDialog( ti );
	    if( idx>=0 )
		{
		od = (map<string,map>)Storage::GetOndiskTarget();
		y2milestone( "adapt_mp use fstab idx %1", idx );
		ti = AddFstabToData( od, (list<map>)fstab[idx]:[] );
		Storage::ResetOndiskTarget();
		Storage::SetTargetMap( ti[0]:$[] );
		}
	    }

        /////////////////////////////////////////////////////////////
        // End of Actions, Now check the returncode
        /////////////////////////////////////////////////////////////

        if (ret == `next || ret == `back || ret == `raid || ret == `lvm || 
	    ret == `raid_settings || ret == `raid_wizard || ret == `evms )
	    {
    	    symbol doagain = `next;

	    if( ret == `raid_wizard || ret == `raid_settings )
		{
		Storage::DisposeTargetBackup("raid");
		}

	    if( ret == `back )
		{
		boolean changed = Storage::GetTargetBackup("custom_part") !=
		                  Storage::GetTargetMap();
		y2milestone( "CheckBack ret=%1 changed=%2", ret, changed );
		if( changed )
		    {
		    // popup text %1 will be replaces with button text
		    string txt = sformat( _("You have changed the partitioning.
These changes are lost if you exit the main dialog with \"%1\".
Really quit the main dialog?
"), 
                                          deletechars(back_label,"&") );
		    if( !Popup::YesNo( txt ))
			{ 
			doagain = `again;
			}
		    }
		}
	    if( ret == `next )
		{
		boolean changed = Storage::GetTargetBackup("custom_part") !=
				  Storage::GetTargetMap();
		y2milestone( "CheckNext ret=%1 changed=%2", ret, changed );
		if( changed )
		    {
		    Storage::SetPartMode( "CUSTOM" );
		    }
		}
	    if ( ret == `next && !immediate_prepdisk )
		{
		list retval = check_created_partiton_table( Storage::GetTargetMap() , true, Stage::initial () );
		Storage::SetTargetMap( retval[0]:$[] );
	        doagain = retval[1]:`next;
		}

	    // write partition information
	    Storage::immediate_prepdisk = immediate_prepdisk;

	    if( (ret==`back || ret==`next) && doagain!=`again )
		{
		Storage::DisposeTargetBackup("custom_part");
		}

	    if( doagain == `again ) ret = `again;

            if( ret != `back )
		{
                if (ret == `apply) return `again;
		}
	    if( ret == `back && Storage::GetPartMode()=="NORMAL" )
		{
		Storage::SetPartMode( "CUSTOM" );
		}
	    }

	y2milestone( "end main loop ret %1", ret );
        } until (ret == `next || ret == `back || ret == `cancel ||
	         ret == `raid_wizard || ret == `raid_settings || 
	         ret == `evms || 
		 ret == `lvm || ret == `lvmlv || ret == `abort );
 
  Wizard::RestoreNextButton();
  if( (ret == `lvm || ret == `raid_wizard || ret == `raid_settings || 
       ret == `evms) &&
      !Stage::initial () )
      {
      Wizard::RestoreBackButton();
      }

  Wizard::RestoreHelp( help_text );
  SCR::Write(.target.ycp, Storage::SaveDumpPath("targetMap_e"), 
             Storage::GetTargetMap() );

  //next by installation
  if( Stage::initial () && ret == `next )
      ret = `instnext;

  //next in existing system
  if( !Stage::initial () && ret == `next )
      ret = `sysnext;

  if( ret == `back )
      ret = `backtoi;

  if( ret == `raid_settings || ret == `raid_wizard )
      Storage::Record();

  return ret;

}
