/**
 * File:
 *   lvm_config_ui.ycp
 *
 * Module: 
 *    configuration of lvm in installed system
 * Summary:
 *
 * Authors:
 *   mike <mike@suse.de>
 *
 * $Id: lvm_config_ui.ycp 20937 2005-01-25 11:24:13Z fehr $
 *
 *
 *----------------------------------------------------
 * IMPORTANT: when you read this code notice:
 *
 * vg  = volume group
 * vgs = volume groups
 *
 * pv  = physical volume
 * pvs = physical volumes
 *
 * lv  = logical volume
 * lvs = logical volumes
 *----------------------------------------------------
 *
 */
{
    import "Arch";
    import "Storage";
    import "FileSystems";
    import "Partitions";
    import "Mode";
    
    textdomain "storage"; 

    import "Popup";
    include "partitioning/partition_defines.ycp";
    include "partitioning/custom_part_dialogs.ycp";
    include "partitioning/custom_part_lib.ycp";
    include "partitioning/custom_part_helptexts.ycp";
    include "partitioning/custom_part_dialogs.ycp";
    include "partitioning/lvm_ui_dialogs.ycp";
    include "partitioning/lvm_ui_lib.ycp";
    include "partitioning/lvm_lib.ycp";
    include "partitioning/lvm_lv_lib.ycp";
    include "partitioning/lvm_pv_lib.ycp";
  
   
    
define boolean CheckItemIsNotMounted( string id )
    ``{
    boolean ret = true;
    if( size(id)>0 )
	{
	string device = Storage::GetDeviceName( Storage::GetMainDevKey(id), 
	                                        Storage::GetSubDevIndex(id));
	string cmd = "mount | grep \"^" + device + " \"";
	y2milestone( "mounts cmd=%1", cmd );
	map bo = (map)SCR::Execute(.target.bash_output, cmd);
	string line = bo["stdout"]:"";
	y2milestone( "mounts line=%1", line );
	ret = size(line)<size(device);
	if( !ret )
	    {
	    line = substring( line, find( line, "on " )+3 );
	    y2milestone( "mounts line=%1", line );
	    line = substring( line, 0, findfirstof( line, " " ) );
	    y2milestone( "mounts line=%1", line );
	    // popup text
	    Popup::Message(sformat(_("Device %1 is already mounted at %2.  
A mounted file system cannot be added to a volume group."),
		 device, line ));
	    }
	}
    y2milestone( "mounts ret=%1", ret );
    return( ret );
    }

    string  current_vg       = "none";    
    string  vg_key = "";
    integer pesize = 4*1024*1024;

   

    boolean test_mode        = Mode::test ();
    map<integer,map> modify_targets   = $[];
    boolean view_all_mnts    = Storage::GetLvmViewAllMnt();
    map<string,map> targetMap = Storage::GetTargetMap();

    
    ////////////////////////////////////////////////
    // Testmode, should be commented in release
    // test_mode   = true;
    // test_mode   = false;
    // architecture = "ppc";
    // system_type = "prep";
    // architecture = "axp";
    ////////////////////////////////////////////////
    
    list    lvm_vgs      = get_vgs( targetMap );
    list<map> parts_lv 	 = get_lvs_and_mounted_partitions( targetMap, view_all_mnts, current_vg );
    list    table_lv 	 = get_lv_widget_table( parts_lv );
    list<map> parts_pv 	 = get_possible_pvs( targetMap );
    list    table_pv 	 = get_pv_widget_table( parts_pv );

    //////////////////////////////////////////////////////////////////////
    // First we typically have to create a volumegroup
    // check if there is already a lvm group
    //////////////////////////////////////////////////////////////////////
    
    if( size( lvm_vgs ) == 0 )
	{
	map vg = DlgCreateVolumeGroup( lvm_vgs );
	map addVG = addVolumeGroup( vg, targetMap, lvm_vgs, modify_targets );
	
	// has the user cancelled the dialog? 
	if( !addVG["cancelled"]:false )
	    {
	    targetMap       = addVG["targets"]:$[];
	    lvm_vgs         = addVG["lvm_vgs"]:[];
	    current_vg      = addVG["current_vg"]:"";
	    modify_targets  = addVG["modify_targets"]:$[];
	    }
	else
	    {
	    return( `back );
	    }
	}
    else
	{
	// there are already vgs ... select the first one
	current_vg = lvm_vgs[0]:""; 
	}

    vg_key = "/dev/" + current_vg;
    pesize = targetMap[vg_key,"cyl_size"]:(4*1024*1024);

    
    // Display current vg:
    new_vg_list( lvm_vgs );
    UI::ChangeWidget( `id(`vg), `Value, current_vg);


    //////////////////////////////////////////////////////////////////////
    // mainloop
    //////////////////////////////////////////////////////////////////////

    string  id          =  "";
    symbol  ret         = `next;
    integer max_size    = 0;
    integer used_size   = 0;
    list    size_list   = [];
    string  vg_size_str = "";

    Storage::SetModifyTargets( modify_targets );
    
    repeat
	{
        /////////////////////////////////////////////////////////////////
	// Show the current state:
	parts_pv 	 = get_possible_pvs( targetMap );
	table_pv 	 = get_pv_widget_table( parts_pv );
	string ti = (string)UI::QueryWidget(`id(`pv_table), `CurrentItem );
	UI::ChangeWidget( `id(`pv_table), `Items, table_pv );
	if( ti != nil )
	    UI::ChangeWidget( `id(`pv_table), `CurrentItem, ti );

        parts_lv = get_lvs_and_mounted_partitions( targetMap, view_all_mnts, 
						   current_vg );
	table_lv = get_lv_widget_table( parts_lv );
	ti = (string)UI::QueryWidget(`id(`lv_table), `CurrentItem );
	UI::ChangeWidget( `id(`lv_table), `Items, table_lv );
	if( ti != nil )
	    UI::ChangeWidget( `id(`lv_table), `CurrentItem, ti );

	string vg_size_str = (string)get_vg_size( parts_pv, current_vg, `string );
	y2debug( "**** %1", vg_size_str );
	UI::ChangeWidget( `id(`pv_size), `Value, vg_size_str);

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


        
	/////////////////////////////////////////////////////////////////
	// Size for BarGraph

	parts_lv = get_lvs_and_mounted_partitions( targetMap, false, 
	                                           current_vg );
	y2debug( "parts_lv=%1 current_vg=%2", parts_lv, current_vg );
	size_list = get_lv_size_info( targetMap,  parts_lv, current_vg );
	max_size  = size_list[1]:0;
	used_size = size_list[0]:0;
	y2debug( "list=%3, max_size=%1 used_size=%2", max_size, used_size, 
	         size_list );
	vg_size_str = ByteToHumanStringWithZero( max_size );

	if( UI::HasSpecialWidget( `BarGraph ))
	    {
	    UI::ChangeWidget( `id(`vg_size), `Labels,
			     [
			      sformat( "used\n%1", 
			               ByteToHumanStringWithZero(used_size)),
			      sformat( "free\n%1", 
			               ByteToHumanStringWithZero(max_size))
			     ] );
	    UI::ChangeWidget( `id(`vg_size), `Values, 
	                      [ used_size / 1048576, max_size / 1048576 ] );
	    }
	else
	    {
	    UI::ChangeWidget( `id(`vg_size), `Value, vg_size_str);
	    }

        /////////////////////////////////////////////////////////////////
        // Wait for User input

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

	y2milestone( "USERINPUT %1", ret );


        ////////////////////////////////////////
	// user has changed "view all mountpoints" checkbox
	////////////////////////////////////////
	
	if( ret == `viewmnt )
	    {
	    view_all_mnts = (boolean)UI::QueryWidget(`id(`viewmnt), `Value );
	    }


        ////////////////////////////////////////
	// user has changed the current volume group
	////////////////////////////////////////
	
	if( ret == `vg )
	    {
	    current_vg = (string)UI::QueryWidget( `id(`vg), `Value);
	    vg_key = "/dev/" + current_vg;
	    pesize = targetMap[vg_key,"cyl_size"]:(4*1024*1024);
	    y2debug("TTT %1", current_vg );
	    }

	
	////////////////////////////////////////
        // Add a new volume group:
        ////////////////////////////////////////

        if( ret == `vg_add_vg )
	    {
	    map vg = DlgCreateVolumeGroup( lvm_vgs );
            map addVG = addVolumeGroup( vg, targetMap, lvm_vgs, modify_targets );

            // has the user cancelled the dialog?
            if( !addVG["cancelled"]:false )
		{
                targetMap       = addVG["targets"]:$[];
		modify_targets  = addVG["modify_targets"]:$[];
		lvm_vgs         = addVG["lvm_vgs"]:[];
		current_vg      = addVG["current_vg"]:"none";
		}
	    }

	
	////////////////////////////////////////
	// Remove volume group:
	////////////////////////////////////////
	
	if( ret == `vg_remove_vg && current_vg != nil )
	    {
	    map r = HandleRemoveVg( targetMap, modify_targets, current_vg );
	    if( size(r)>0 )
		{
		targetMap       = r["targets"]:targetMap;
		modify_targets  = r["modify_targets"]:modify_targets;
		lvm_vgs         = get_vgs( targetMap );
		current_vg = lvm_vgs[0]:"";
		// Display current vg:
		new_vg_list( lvm_vgs );
		UI::ChangeWidget( `id(`vg), `Value, current_vg);
		y2milestone( " current_vg %1" , current_vg );
		}
	    }

	
	////////////////////////////////////////
	// Add a new physical volume:
	////////////////////////////////////////
	
	
	if( ret == `pv_add && current_vg != nil )
	    {
	    id = (string)UI::QueryWidget(`id(`pv_table), `CurrentItem );
	    y2debug( "WWW ID ADD GROUP %1", id);
	    
	    if( id!=nil && CheckItemIsNotPv(targetMap,id) && 
	        CheckItemIsNotMounted(id) )
		{
		map addPV = addPhysicalVolume( modify_targets, targetMap, 
		                               id,  current_vg );
            
		// has an error occured
		if( !addPV["error"]:false )
		    {
		    targetMap      = addPV["targets"]:$[];
		    modify_targets  = addPV["modify_targets"]:$[];
		    }
		}
	    }

	////////////////////////////////////////
	// Delete a new physical volume:
	////////////////////////////////////////
	
	if( ret == `pv_delete && current_vg != nil )
	    {
	    id = (string)UI::QueryWidget(`id(`pv_table), `CurrentItem );
	    
	    if( id!=nil && CheckItemIsPv(targetMap,id) )
		{
		map ttt = Storage::IdFromTarget( targetMap, id );
	        string vg = ttt["lvm_group"]:"";

		if( check_pv_delete( targetMap, id, vg ) == `nodelete )
		    {
		    ret = `again;
		    continue;
		    }

		map deletePV = removePhysicalVolume( modify_targets, targetMap,
		                                     id, vg );
            
		// has an error occured
		if( !deletePV["error"]:false )
		    {
		    targetMap      = deletePV["targets"]:$[];
		    modify_targets  = deletePV["modify_targets"]:$[];
		    }
		}
	    }

	
	////////////////////////////////////////
	// Add a new logical volume:
	////////////////////////////////////////
	
	if( ret == `lv_add )
	    {
	    if( max_size<pesize )
		{
		// popup text
		Popup::Message(sformat(_("There is no available space in the current volume group %1"), current_vg ));
		}
	    else
		{
		map<string,any> Lv = $[
			   "create"         :       true,
			   "used_fs"        :       `reiser,
			   "size"           :       max_size/4/pesize*pesize,
			   "stripes"        :       1,
			   "fs_options"     :       $[],
			   "format"         :       true,
			   "fsid"           :       Partitions::fsid_lvm,
			   "type"           :       `lvm,
			   "fstype"         :       "LV",
			   "mount"          :       GetMountPointProposal(targetMap , ["/boot"] )
		];

		if( Lv["lv_size"]:0 == 0 )
		    {
		    Lv["lv_size"] = max_size/pesize*pesize;
		    }

		map createLv = DlgCreateEditLogicaVolume( "create",
					       Lv,
					       max_size,
					       current_vg,
					       get_lv_names(targetMap,current_vg),
					       FileSystems::GetAllFileSystems(true,true),
					       false,
					       "", pesize
					       );
		
		// has an error occured
		if( size(createLv)>0 )
		    {
		    map ret = addLogicalVolume( createLv, modify_targets, 
		                                targetMap, current_vg );
		    
		    targetMap      = ret["targets"]:targetMap;
		    modify_targets = ret["modify_targets"]:modify_targets;
		    }
		}
	    }

	////////////////////////////////////////
	// Edit/Resize a new logical volume:
	////////////////////////////////////////
	
	
	if( ret == `lv_edit )
	    {
	    id = (string)UI::QueryWidget(`id(`lv_table), `CurrentItem );
	    y2milestone("id %1", id);

	    if ( id == nil )
		{
		// Popup text
		Popup::Error(_("No device selected.
Select the device to edit.
"));
		
		}
	    else
		{
		map ret = HandleEditLv( targetMap, modify_targets, id );
		targetMap = ret["targets"]:targetMap;
		modify_targets = ret["modify_targets"]:modify_targets;
		}
	    }

	////////////////////////////////////////
	// Delete a new logical volume:
	////////////////////////////////////////

	if( ret == `lv_delete )
	    {
	    id = (string)UI::QueryWidget(`id(`lv_table), `CurrentItem );
	    if( id == nil )
		{
		// Popup text
		Popup::Error(_("No device selected.
Select the device to remove.
"));
		}
	    else
		{
		map ret = HandleRemoveLv( targetMap, modify_targets, id );
		targetMap = ret["targets"]:targetMap;
		modify_targets = ret["modify_targets"]:modify_targets;
		}
	    }

	if( ret == `help )
	    {
	    // LVM Helptext headline
	    Popup::LongText( _("LVM Help"), `RichText( getLvmHelptext()), 
	                       70, 20 );
	    }
	
        ////////////////////////////////////////
	// Finish this step
	////////////////////////////////////////
	
	if( ret == `finish || ret == `apply )
	    {
	    y2milestone( "END___ %1", ret);
	    // due to lvm tools, we need a already created pv before
	    // creating a vg so we patch the execution stack

	    any check_ret = checkModifyTargets( modify_targets, targetMap );
	    y2milestone( "ENDx___ %1", ret);

	    if( check_ret == `next )
		{
	        y2milestone( "END__ %1", ret);
	        map procMod = processModifyTargets( modify_targets, targetMap );

	        targetMap       = procMod["targets"]:targetMap;
	        modify_targets  = procMod["modify_targets"]:modify_targets;
		
	        Storage::SetModifyTargets( modify_targets);
	        Storage::SetTargetMap( targetMap );
	        Storage::SetLvmViewAllMnt( view_all_mnts );
		}
	    }

	} until (ret == `finish || ret == `apply || ret == `abort);

    y2milestone( "END_ %1", ret);
    y2milestone( "modify_targets=%1", modify_targets );
	
    return ret;
}

// end
