/**
 * File:
 *   lvm_ui_dialogs.ycp
 *
 * Module: 
 *    configuration of lvm: lib for the user interface
 *    - contains only dialogs    
 *
 * Summary:
 *
 * Authors:
 *   mike <mike@suse.de>
 *
 *
 * $Id: lvm_ui_dialogs.ycp 22133 2005-03-02 10:16:36Z fehr $
 *
 */


{

textdomain "storage";

import "Mode";
import "Partitions";
import "FileSystems";
import "Storage";

import "Label";
import "Popup";

include "partitioning/custom_part_dialogs.ycp";
include "partitioning/custom_part_lib.ycp";
include "partitioning/lvm_lv_lib.ycp";
include "partitioning/lvm_ui_lib.ycp";

define void handle_max( integer stripe, string max_text )
    ``{
    y2milestone( "stripe %1", stripe );
    UI::ChangeWidget(`id("max_size"), `Enabled, stripe==1 );
    UI::ChangeWidget(`id("max_text"), `Value, stripe==1?max_text:"" );
    }
    
define map DlgCreateEditLogicaVolume( string create_or_edit, map<string,any> Lv,
				      integer max_size, string vgname,
				      list lvs, map<symbol,map> file_systems,
				      boolean installation, string dev,
				      integer pesize )

    ``{
    y2milestone( "dev=%1 pesize=%2 max_size=%3", dev, pesize, max_size );

    integer new_size     = Lv["region",1]:0 * pesize;
    y2milestone( "new_size %1", new_size );
    integer old_size     = Lv["ori_length"]:new_size;
    string  curr_size    = ByteToHumanStringWithZero(new_size);
    old_size = kmgt_str_to_byte(curr_size);
    string  volume_name  = Lv["nr"]:"";
    integer stripes      = Lv["stripes"]:1;
    integer stripesize   = Lv["stripesize"]:64;

    list stripes_poss = [
			  `item(`id(1), "1",  stripes == 1 ),
			  `item(`id(2), "2",  stripes == 2 ),
			  `item(`id(3), "3",  stripes == 3 ),
			  `item(`id(4), "4",  stripes == 4 ),
			  `item(`id(5), "5",  stripes == 5 ),
			  `item(`id(6), "6",  stripes == 6 ),
			  `item(`id(7), "7",  stripes == 7 ),
			  `item(`id(8), "8",  stripes == 8 )
			];

    list stripe_size = [
			  `item(`id(4),   "4",    stripesize == 4 ),
			  `item(`id(8),   "8",    stripesize == 8 ),
			  `item(`id(16),  "16",   stripesize == 16 ),
			  `item(`id(32),  "32",   stripesize == 32 ),
			  `item(`id(64),  "64",   stripesize == 64 ),
			  `item(`id(128), "128",  stripesize == 128 ),
			  `item(`id(256), "256",  stripesize == 256 ),
			  `item(`id(512), "512",  stripesize == 512 ),
                       ];
    
    string lv_size      = "";   
     
    string  heading        = "";
    boolean is_create_mode = false;
    boolean is_resize_mode = false;
    term    ui_volume_name = `Dummy();
    any     c_ret          = `cancel;
     
    // header for input field size of Logical volume 
    string size_txt = sformat(_("&Size: (e.g., %1 %2)"), 
			      ByteToHumanStringWithZero(4196*1024*1024),
			      ByteToHumanStringWithZero(210*1024*1024));
    if( create_or_edit != "create" )
	{
	max_size = max_size+new_size;
	y2milestone( "new max_size=%1", max_size );
	}
    y2milestone( "new_size %1", new_size );
    // header for input field maximum allowd size
    string max_text = sformat(_("max = %1 "), 
			      ByteToHumanStringWithZero(max_size));


    if( create_or_edit == "create" )
        {
	// popup heading 
	heading        = _("Create Logical Volume");
	is_create_mode = true; 
	ui_volume_name = `VBox( `TextEntry(`id("volume_name"),
					   // label text
					   _("Logical volume &name "),
					   volume_name),
				 // label text
				`Left(`Label(_("(e.g. var, opt)")))
			      );
	}
    else if ( create_or_edit == "edit" )
        {
	// popup heading 
	heading = _("Edit Logical Volume");
	is_create_mode = false;
			   // display name of current volume group
	// display name of current volume group
	ui_volume_name = `VBox( `Label(""),
				// label text
				`HBox(`Label( _("Logical volume name: ")),
				      `Heading(`opt(`outputField), volume_name ),
				      `HStretch()
				     ));
	}
    else if ( create_or_edit == "resize" )
	{
	// popup heading 
	heading = _("Edit Logical Volume");
	is_create_mode = false;
	is_resize_mode = true;
	// display name of current volume group
	ui_volume_name = `VBox( `Label(""),
				// label text
				`HBox(`Label( _("Logical volume name: ")),
				      `Heading(`opt(`outputField), volume_name ),
				      `HStretch()
				     )
			      );
	stripes_poss = [ `item(`id(1), "-", true) ];
	stripe_size = [ `item(`id(1), "-", true) ];
	}
    else
	{
	// internal error message 
	heading = _("INTERNAL ERROR");
	}

    y2milestone( "is_create_mode %1 is_resize_mode %2", is_create_mode,
                 is_resize_mode );
 
    UI::OpenDialog(
	`opt(`decorated ),
	`HBox(`HWeight(30, 
	          `HBox(
		        `HSpacing(1),
		        `HStretch(),
			`VBox(
			      `Heading(heading),
			      `VStretch(),
			      `VSpacing(1),
			      `HBox(
				    FormatDlg( Lv, file_systems ),
				    `HStretch(),
				    `HSpacing(2),
				    `VBox(
					  `Top(`Left(ui_volume_name)),
					  `Top(`VBox( `TextEntry(`id("size"), size_txt, curr_size),
						      `HBox(
							    // set size to maxsize
							    `Left(`Label( `id("max_text"), max_text )),
							    // button text
							    `PushButton( `id("max_size"), _("ma&x")))
						      
					      )),
					  `VStretch(),
					  `Left(`ComboBox( `id("stripes"), `opt(`hstretch,`notify),
							   // button text
							   _("Stri&pes"), stripes_poss )),
					  `VStretch(),
					  `Left(`ComboBox( `id("stripesize"), `opt(`hstretch,`notify),
							   // button text
							   _("Stripe &Size"), stripe_size )),
					  `VStretch(),
					  `VSpacing(1),
					  `ReplacePoint( `id(`mount_dlg_rp), 
					                 MountDlg(Lv, []))
					  )
				    ),
			      `VStretch(),  
			      `VSpacing(1),
			      `HBox(
				    // Ok button
				    `PushButton(`id(`ok), `opt(`default), Label::OKButton()  ),
				    // Cancel button
				    `PushButton(`id(`cancel), Label::CancelButton() )
				   )
			      ),
			`HStretch(),
			`HSpacing(1)
			)
	       )));


      // configure main dialog for the first call

      if( is_create_mode )
	  {
	  UI::ChangeWidget( `id("volume_name"), `ValidChars, 
			    FileSystems::nchars + "-._:" );
	  }
      UI::ChangeWidget( `id("stripes"), `Enabled, !is_resize_mode );
      UI::ChangeWidget( `id("stripesize"), `Enabled, 
                        !is_resize_mode && stripes>1 );
      handle_max( stripes, max_text );
  
      ////////////////////////////////////////////////////////////////////
      // User mainloop for dialog
      ////////////////////////////////////////////////////////////////////
      
      boolean input_is_ok = true;
      map<string,any> retval = eval(Lv);

      retval = HandlePartWidgetChanges( true, `ok, file_systems, Lv, retval );

      repeat
      {
	    input_is_ok  = true;
	    
	    c_ret = UI::UserInput();

	    /////////////////////////////////////////////////////////
	    if( c_ret == "stripes")
		{
		stripes = (integer)UI::QueryWidget(`id("stripes"), `Value);
	        UI::ChangeWidget( `id("stripesize"), `Enabled, 
				  !is_resize_mode && stripes>1 );
		handle_max( stripes, max_text );
		c_ret = `again;
		continue;
		}

	    /////////////////////////////////////////////////////////
	    // stripes
	    if( c_ret == "max_size")
		{
		UI::ChangeWidget(`id("size"), `Value, ByteToHumanStringWithZero(max_size));
		c_ret = `again;
		continue;
		}

	    if( c_ret != `cancel )
		{
		retval = HandlePartWidgetChanges( false, c_ret, file_systems,
		                                  Lv, retval );
		}
	    
	    if( is_create_mode ) 
		{
		volume_name = (string)UI::QueryWidget( `id("volume_name"), 
		                                       `Value );
		volume_name = deletechars( volume_name, " \t" );
		}

	    stripes = (integer)UI::QueryWidget(`id("stripes"), `Value);
	    stripesize = (integer)UI::QueryWidget(`id("stripesize"), `Value);
	    lv_size = (string)UI::QueryWidget(`id("size"),    `Value);
	   
	    y2debug("STRI ---- i%1i", stripes);
	    if( c_ret==`ok )
		{
		new_size = kmgt_str_to_byte(lv_size);
		
		if ( !check_max_size(new_size, max_size) )
		    {
		    input_is_ok = false;
		    c_ret = `again;
		    continue;
		    }
		y2milestone( "new_size %1 old_size %2", new_size, old_size );

		if( !check_ok_fssize(new_size, retval) )
		    {
		    input_is_ok = false;
		    c_ret = `again;
		    continue;
		    }

		if( is_resize_mode && !retval["format"]:false && 
		    new_size!=old_size )
		    {
		    if( !CheckResizePossible( true, true, new_size-old_size,
		                              retval["used_fs"]:`unknown,
		                              retval["mount"]:"" ))
			{
			UI::ChangeWidget(`id("size"), `Value, curr_size );
			c_ret = `again;
			continue;
			}
		    }

		if ( is_create_mode )
		    {
		    if( !icheck_volume_name(volume_name) )
			{
			input_is_ok = false;
			// error popup text
			// xgettext:no-c-format
			Popup::Error(_("Check your volume name. 
Use names like \"opt\" or \"var\" ...
Do not use ;/\`',!\"%#"));
			UI::SetFocus(`id("volume_name"));
			c_ret = `again;
			continue;
			}
		    else 
			{
			if( contains( lvs, volume_name ) )
			    {
			    input_is_ok = false;
			    // error popup text
			    Popup::Error(sformat(_("A logical volume named \"%1\" already exists
in volume group \"%2\". Choose another name
or cancel this dialog.
"), volume_name, vgname ));
			    UI::SetFocus(`id("volume_name"));
			    c_ret = `again;
			    continue;
			    }
			}   
		    }

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

		ret_mp = CheckCryptOk( retval );
		if( !ret_mp["ok"]:false )
		    input_is_ok = false;
		else
		    retval = ret_mp["map"]:$[];
		}

	    /////////////////////////////////////////////////////////
	    retval["changed_size"] = new_size!=old_size;
	    retval["stripes"] = stripes;
	    if( stripes>1 )
		{
		retval["stripesize"] = stripesize;
		}
	    retval["nr"] = volume_name;
	    retval["device"] = Storage::GetDeviceName( "/dev/"+vgname, 
	                                               volume_name );
	    if( new_size!=old_size )
		{
		retval["region"] = [0, (new_size+pesize-1)/pesize ];
		retval["lv_size"] = retval["region",1]:0 * pesize;
		retval["size_byte"] = retval["region",1]:0 * pesize;
		if( is_resize_mode && !haskey( retval, "ori_length"))
		    {
		    retval["ori_length"] = old_size;
		    }
		}
	    
      } until ( (c_ret==`ok&&input_is_ok) || c_ret == `cancel );

      UI::CloseDialog();
      
      y2milestone( "retval=%1", retval );
      
      if (c_ret != `cancel && input_is_ok )
      {
	  return( retval );
      }
      else
      {
	  return( nil );
      }
    };
    


 //////////////////////////////////////////////////////////////////////////////
 // Dialog "Create a Volume Group
 //////////////////////////////////////////////////////////////////////////////
	 
define map HandleEditLv( map<string,map> targetMap, map<integer,map> modify_targets, string id )
    ``{
    map ret = $[];
    string maindev = Storage::GetMainDevKey( id);
    string subdev  = Storage::GetSubDevIndex( id );
    string device  = Storage::GetDeviceName( maindev, subdev );
    integer pesize = targetMap[maindev,"cyl_size"]:(4*1024*1024);

    map<symbol,map> fs = FileSystems::GetAllFileSystems(true, true);
    map<string,any> Lv = (map<string,any>)Storage::GetPartition( targetMap, device );

    // if Lv is a lvm partition
    if( size(Lv)>0 )
	{
	string tmp_vg = substring( maindev, 5);
	list size_list = 
	    get_lv_size_info( targetMap,
			      get_lvs_and_mounted_partitions( targetMap, false,
			                                      tmp_vg ), 
			      tmp_vg );
	integer max_size    = size_list[1]:0;
	integer used_size   = size_list[0]:0;

	if( Lv["create"]:false )
	    {
	    map createLv = DlgCreateEditLogicaVolume( "edit", Lv, max_size,
						      tmp_vg, [], fs,
						      Stage::initial (), device,
						      pesize );

	    // has an error occured
	    if ( size(createLv)>0 )
		{
		ret = editLogicalVolume( createLv, modify_targets, targetMap, 
		                         tmp_vg );
		}
	    }
	else
	    {
	    map createLv = DlgCreateEditLogicaVolume( "resize", Lv, max_size,
						      tmp_vg, [], fs,
						      Stage::initial (), device,
						      pesize );
	    // has an error occured
	    if ( size(createLv)>0 )
		{
		ret = resizeLogicalVolume( createLv, modify_targets, targetMap,
					   tmp_vg );
		}
	    }
	}
    else
	{
	// Popup text
	Popup::Error(_("You can only edit logical volumes."));
	}
    y2milestone( "ret %1", ret );
    return( ret );
    }

define map HandleRemoveLv( map<string,map> targetMap, map<integer,map> modify_targets, string id )
    ``{
    map ret = $[];
    string maindev = Storage::GetMainDevKey(id);
    string subdev  = Storage::GetSubDevIndex(id );
    string tmp_vg =  substring( maindev, 5);
    string device = Storage::GetDeviceName(maindev, subdev);
    map Lv = Storage::GetPartition( targetMap, device );
    if( size(Lv)==0 || Lv==nil )
	{
	// Popup text
	Popup::Error(_("You can only remove logical volumes."));
	}
    else
	{
	// Popup text
	string message = sformat( _("Remove the logical volume %1?"), 
	                          device );

	if( Popup::YesNo( message ))
	    {
	    y2debug( "Lv:  %1", Lv);
	    y2debug( "modify_targets:  %1", modify_targets );
	    y2debug( "targetMap: %1", targetMap);
	    y2debug( "vgname:  %1", tmp_vg );
	    map deleteLV = removeLogicalVolume( Lv, modify_targets, targetMap,
	                                        tmp_vg );

	    // has an error occured
	    if( !deleteLV["error"]:false )
		{
		ret = (map)eval(deleteLV);
		}
	    }
	}
    return( ret );
    }


define map HandleRemoveVg( map<string,map> targetMap, map<integer,map> modify_targets, 
			   string current_vg )
    ``{
    map ret = $[];
    integer count = size(get_lv_names(targetMap, current_vg));
    if( count > 0 )
	{
	// Message popup
	Popup::Message(sformat(
_("The volume group \"%1\" contains at least one logical 
volume.  It cannot be removed. Remove all logical volumes then
remove the volume group.
"), current_vg));
	}
    else
	{  
	// popup text
	if( Popup::ContinueCancel( sformat( _("Really remove the volume group \"%1\"?"), current_vg)))
	    {
	    y2milestone( " remove " );
	    ret = removeVolumeGroup( current_vg, targetMap, modify_targets );
	    }
	}
    return( ret );
    }

define map DlgCreateVolumeGroup( list vgm_list )
    ``{
    string vgname = "";
    string pesize = "";
    boolean old_metadata = false;
    boolean lvm2 = SCR::Read(.lvm.version) == 2;

    y2milestone( "lvm2 %1", lvm2 );

    term Lvm2Type = `Empty();

    if( lvm2 )
	{
	Lvm2Type = `CheckBox( `id("lvm1"), 
	                      _("Use &Old LVM1 Compatible Metadata Format"), 
			      false );
	}
   
    UI::OpenDialog(
	`opt(`decorated ),
	`HBox(
	    `HSpacing(2),
	    `VBox(
		  // popup header
		  `Heading(_("Create a Volume Group")),
		  // popup description
		  `Label( _("Now we have to create a volume group.
Typically you don't have to change anything,
but if you are an expert, feel free to change
our defaults:")),
		  // label text
		  `TextEntry( `id("vgname"), _("Volume Group &Name:"), 
		              size(vgm_list)==0?"system":""),
		  // label text
		  `TextEntry(`id("pesize"), _("&Physical Extent Size"), "4M"),
		  Lvm2Type,
		  `VSpacing(1),
		  `HBox(
			// Ok button
			`PushButton(`id(`ok), `opt(`default), 
			             Label::OKButton()  ),
			// Cancel button
			`PushButton(`id(`cancel), Label::CancelButton() )
		       ),
		  `VSpacing(0.5)
		 ),
	    `HSpacing(2)
	    )
	);

    any     ret         = nil;
    boolean input_is_ok = false;
      
    repeat
	{
	ret = UI::UserInput();

	vgname = (string)UI::QueryWidget(`id("vgname"),  `Value);
	vgname = deletechars( vgname, " \t" );
	pesize = (string)UI::QueryWidget(`id("pesize"),  `Value);
	if( UI::WidgetExists( `id("lvm1") ))
	    {
	    old_metadata = (boolean)UI::QueryWidget( `id("lvm1"), `Value );
	    }

	if( ret != `cancel )
	    {
	    input_is_ok = true;
	     
	    if( !icheck_pesize(pesize) )
	        {
		// error popup text
		Popup::Error(_("The data entered is invalid.
Insert a physical extent size from
8KB to 512MB in powers of 2, for example, \"4M\" or \"512K\"
"));
		input_is_ok = false;
		}

	    if( !icheck_vgname(vgname) )
		{
		// error popup text
		Popup::Error(_("The data entered is invalid.
Insert a group name like \"system\" or \"test\".
Do not use ;/`, in your group name.
"));
		input_is_ok = false;
		}
	  
	    if( contains( vgm_list, vgname ) )
		{
		// error popup text
		Popup::Error(sformat(_("The volume group \"%1\" already exists.
Choose a different name
or cancel this dialog.
"), vgname ));
		input_is_ok = false;
		}
	    }
	  
	} until( input_is_ok || ret == `cancel );

    UI::CloseDialog();
	     
    if (ret == `ok )
	{
	map ret = $[ "vgname" : vgname, "pesize" : pesize_str_to_byte (pesize) ];
	if( lvm2 )
	    {
	    ret["lvm2"] = !old_metadata;
	    }
	return( ret );
	}
    else
	{
	return( $[] );
	}
    };

}
