/**
 * File:
 *   lvm_lv_lib.ycp
 *
 * Module:
 *
 * Summary:  lib for lvm-configs logical volume management
 *
 * Authors:
 *   mike <mike@suse.de>
 *
 * $Id: lvm_lv_lib.ycp 20155 2004-11-03 16:35:04Z 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
 *----------------------------------------------------
 *
 */
{

textdomain "storage";
import "Storage";
import "Partitions";

include "partitioning/lvm_lib.ycp";
include "partitioning/lvm_pv_lib.ycp";
      
    //////////////////////////////////////////////////////////////////////
    // add a logical volume to the modify_targets stack
    //
    // 1:  $[  "use_module" : "lvm_ll"
    //         "type"       : "create_lv", 
    //         "name"       : "usr"
    //         "size"       : 12121
    //         "vgname"     : "system"
    //         "stripes"    : 1 ]           
    //
    //   !!!!!!! changes targetMap by reference !!!!!!
    // 	
    //////////////////////////////////////////////////////////////////////

define map addLogicalVolume( map Lv, map<integer,map> modify_targets, map<string,map> targetMap, 
                             string current_vg )
    ``{
    y2debug("create Lv: %1", Lv);
    /////////////////////////////////////////////////
    // new entry in execution stack "modify_targets"
    
    map new_create_lv = $[
			    "use_module" : "lvm_ll",      
			    "type"       : "create_lv",  
			    "name"       : Lv["nr"]:"",         
			    "size"       : Lv["lv_size"]:0,               
			    "vgname"     : current_vg,     
			    "stripes"    : Lv["stripes"]:1
	];           

    if( haskey( Lv, "stripesize" ) )
	{
	new_create_lv["stripesize"] = Lv["stripesize"]:0;
	}
    
    modify_targets = addTargetModification( modify_targets, new_create_lv );
    y2debug( "modify_targets: %1", modify_targets);


    /////////////////////////////////////////////////
    // change targetMap

    map  disk       = targetMap["/dev/"+current_vg]:$[];
    y2debug( "disk: %1", disk);
    list partitions = disk["partitions"]:[];

    y2debug("lv_size: %1, cyl_size   %2 ", Lv["lv_size"]:0, disk["cyl_size"]:1);
    partitions = add( partitions, Lv );
    targetMap["/dev/"+current_vg,"partitions"] = partitions;

    return( $[ "modify_targets":modify_targets, "targets":targetMap, "error":false ]);
    };
	

     //////////////////////////////////////////////////////////////////////
     // resize a logical volume to the modify_targets stack
     //
     // 1:  $[  "use_module" : "lvm_ll"
     //         "type"       : "resize_lv", 
     //         "name"       : "usr"
     //         "size"       : 12121
     //         "vgname"     : "system"
     //       ]           
     //
     //   !!!!!!! changes targetMap by reference !!!!!!
     // 	
     //////////////////////////////////////////////////////////////////////

define map resizeLogicalVolume( map Lv, map<integer,map> modify_targets, map<string,map> targetMap, 
                                string current_vg )
    ``{
    string volume_name = Lv["nr"]:"";
 
    /////////////////////////////////////////////////
    // new entry in execution stack "modify_targets"

    if( Lv["changed_size"]:false )
	{
	map new_create_lv = $[
			  "use_module" : "lvm_ll",      
			  "type"       : "resize_lv",  
			  "name"       : volume_name,
			  "size"       : Lv["lv_size"]:0,               
			  "vgname"     : current_vg
			  ];           

	modify_targets = addTargetModification( modify_targets, new_create_lv );
	y2debug( "EEE s %1", modify_targets);
	}


    /////////////////////////////////////////////////
    // change targetMap

    map  disk       = targetMap["/dev/"+current_vg]:$[];
    y2debug( "EEEV  s %1", disk);
    list<map> partitions = disk["partitions"]:[];

    y2debug("SSSIZ %1   %2 ", Lv["lv_size"]:0, disk["cyl_size"]:1);

    list new_partitions = filter(map part, partitions,
				 ``(part["nr"]:""!=volume_name));

    new_partitions = add( new_partitions, Lv );
    targetMap["/dev/"+current_vg,"partitions"] = new_partitions;

    return( $[ "modify_targets":modify_targets, "targets":targetMap, "error":false ]);
    };


     
     //////////////////////////////////////////////////////////////////////
     // edit a logical volume to the modify_targets stack
     // ! there must be already an create item
     // and this item will be changed!
     //
     // 1:  $[  "use_module" : "lvm_ll"
     //         "type"       : "create_lv", 
     //         "name"       : "usr"
     //         "size"       : 12121
     //         "vgname"     : "system"
     //         "stripes"    : 1 ]           
     //
     //    !!!!!!! changes targetMap by reference !!!!!!
     // !!!!!!! changes modify_targets by reference !!!!!!
     // 	
     //////////////////////////////////////////////////////////////////////

define map editLogicalVolume( map Lv, map<integer,map> modify_targets, map<string,map> targetMap, 
                              string current_vg)
    ``{
    /////////////////////////////////////////////////
    // changed entry in execution stack "modify_targets"
   
    map new_create_lv = $[
			  "use_module" : "lvm_ll",      
			  "type"       : "create_lv",  
			  "name"       : Lv["nr"]:"",
			  "size"       : Lv["lv_size"]:0,               
			  "vgname"     : current_vg,     
			  "stripes"    : Lv["stripes"]:1
	];           

    integer idx = GetModifyIdx( modify_targets, new_create_lv );
    if( idx==-1 )
	modify_targets = addTargetModification( modify_targets, new_create_lv );
    else
	modify_targets[idx] = new_create_lv;
    y2debug( "modify_targets: %1", modify_targets);

    /////////////////////////////////////////////////
    // change targetMap

    targetMap = (map<string,map>)Storage::SetPartition( targetMap, Lv );

    y2debug("lv_size: %1 ", Lv["lv_size"]:0 );

    return( $[ "modify_targets":modify_targets, "targets":targetMap, 
	       "error":false ]);
    };

     

     //////////////////////////////////////////////////////////////////////
     // remove a logical volume to the modify_targets stack
     //
     //   !!!!!!! changes targetMap by reference !!!!!!
     // 	
     //////////////////////////////////////////////////////////////////////

define map removeLogicalVolume( map Lv, map<integer,map> modify_targets, map<string,map> targetMap, 
                                string current_vg)
    ``{
    string  volume_name          = Lv["nr"]:"";
    map new_create_lv = $[
			  "use_module"       : "lvm_ll",      
			  "type"             : "remove_lv",  
			  "name"             : volume_name,
			  "vgname"           : current_vg,
			  "target_map_entry" : $[]
	];           

    integer modify_targets_index = GetModifyIdx( modify_targets, 
						 new_create_lv );
    
    // check if there is a create already,
    // if there is a create, delete this "create"
    // otherwise insert a remove

    if ( modify_targets_index == -1 )
	{
	/////////////////////////////////////////////////
	// new entry in execution stack "modify_targets"
   
	modify_targets = addTargetModification( modify_targets, new_create_lv );
	}
    else
	{
	// delete create entry  i.e 3
	modify_targets = removeTargetModification( modify_targets, 
						   modify_targets_index );
	}

    
    /////////////////////////////////////////////////
    // change targetMap

    targetMap = (map<string,map>)Storage::SetPartitionData( targetMap, Lv["device"]:"",
					   "delete", true );

    y2debug( "createLv: %1", Lv);
    y2debug( "modify_targets: %1", modify_targets);
    y2debug( "targetMap: %1" , targetMap);
    
    return( $[ "modify_targets":modify_targets, "targets":targetMap, "error":false ]);
    };

  
    //////////////////////////////////////////////////////////////////////
    //      
    // !!!! input: partition_list: must be aready those lvs that belong to current_vg
    // 
    // [  $["fsid":Partitions::fsid_lvm,
    //	  "fstype":"LVM",
    //	  "nr":"var",
    //	  "region":[255, 16],
    //	  "type":`primary],
    //	  $[
    //	   "fsid":131,
    //	   "fstype":"Linux native",
    //	   "nr":4, "region":[271, 844],
    //    ...
    //
    //  out: [ 10344343, 2223333 ]   [ used, avail ]
     
define list get_lv_size_info( map<string,map> targetMap, list<map> partition_list, 
			      string current_vg )
    ``{
    integer sum_byte_vg = 0;
    integer sum_byte_lv = 0;

    // first max vg size ...
    list<map> parts = get_possible_pvs( targetMap );
    sum_byte_vg = vg_size( parts, current_vg );

    // now size that is reserved  
    foreach( map part, partition_list, 
	     ``{ sum_byte_lv = sum_byte_lv + part["size_byte"]:0; });

    y2milestone( "get_lv_size_info sum_byte_vg=%1 sum_byte_lv=%2 vg:%3", 
                 sum_byte_vg, sum_byte_lv, current_vg );
    // result is [ reserved , (max - reserved) ] 
    return( [ sum_byte_lv, sum_byte_vg - sum_byte_lv ] );
    };
		

    ////////////////////////////////////////////////////////////////////////////////
    // Get all logical volumes and mounted partitions
    
define list<map> get_lvs_and_mounted_partitions( map<string,map> targetMap, 
						 boolean view_all_mnts,
						 string current_vg )
    ``{
    list<map> ret = [];
    integer pesize = targetMap["/dev/"+current_vg,"cyl_size"]:(4096*1024);
    y2milestone( "current_vg=%2 pesize=%1", pesize, current_vg );
    
    //////////////////////////////////////////////////////////////////////
    // add the devicename i.e /dev/hda1 or /dev/system/usr to partition list
    // and the device key  <subdevice>/<maindevice> i.e. 1//dev/hda
    
    targetMap = mapmap( string dev, map devmap, targetMap,
	``{
	boolean is_lvm_vg  = devmap["is_lvm_vg"]:false;
	integer cyl_size   = devmap["cyl_size"]:0;
					
	list partitions = maplist( map part, devmap["partitions"]:[],
	    ``{
	    integer bytes_of_part = 0;
	    integer nb_cyl = part["region",1]:0;
    
	    bytes_of_part = nb_cyl * cyl_size;

	    if( is_lvm_vg )
		{
		part["is_lv"] = true;
		part["lvm_name"] = devmap["name"]:"";
		}
	    else
		{
		if( bytes_of_part>200*1024 )
		    {
		    bytes_of_part = bytes_of_part - 200*1024;
		    }
		bytes_of_part = bytes_of_part/pesize;
		bytes_of_part = bytes_of_part * pesize;
		}
	    part["size_str"] = ByteToHumanStringWithZero(bytes_of_part);
	    part["size_byte"] = bytes_of_part;
		
	    part["maindev"] = dev;
	    part["devkey"] = sformat( "%2/%1", dev, part["nr"]:(any)"");
	    y2debug("devname %1 size %2 reg %3 pe %4", part["device"]:"",
	            part["size_byte"]:0, part["region",1]:0, pesize );
	    return( part );
	    });

	devmap["partitions"] = partitions;
	return( $[ dev: devmap ] );
	});

    ////////////////////////////////////////////////////////////
    // Look for all partitions:
    //
    // normal partition with mountpoint
    // logical volume

    if ( ! view_all_mnts )
	{
	// only to current vg depending vgs ...
	foreach( string dev, map devmap, targetMap,
	    ``{
	    ret = (list<map>)union( ret, filter( map part, devmap["partitions"]:[],
				      ``( !part["delete"]:false &&
					  part["is_lv"]:false &&
					  part["lvm_name"]:"" == current_vg )));
	    });
	}
    else
	{
	foreach( string dev, map devmap, targetMap,
	    ``{
	    ret = (list<map>)merge( ret, filter( map part, devmap["partitions"]:[],
				      ``( !part["delete"]:false &&
				          (part["mount"]:"" != "" ||
					   part["is_lv"]:false ))));
	    });
	}
    return( ret );
    };

    ////////////////////////////////////////////////////////////////////////////////
    // Get all existing lv names of a volume group
    
define list get_lv_names( map<string,map> targetMap, string current_vg )
    ``{
    list<map> part = filter( map e, targetMap["/dev/"+current_vg,"partitions"]:[],
                        ``(!e["delete"]:false));
    list ret = maplist( map e, part, ``(e["nr"]:"") );
    return( ret );
    };

    //////////////////////////////////////////////////////////////////////
    // partition list to widget table
    // in:
    // [  $["fsid":Partitions::fsid_lvm,
    //	  "fstype":"LVM",
    //	  "nr":"var",
    //	  "region":[255, 16],
    //	  "type":`primary],
    //	  $[
    //	   "fsid":131,
    //	   "fstype":"Linux native",
    //	   "nr":4, "region":[271, 844],
    //    ...
    //
    // out:
    // [
    //    `item(`id(1//dev/hda), "/dev/hda1 ",   " /var ",  "system", " 1G ", " LVM "),
    //	  `item(`id(2//dev/hda), "/dev/hda2 ",   " /usr ",  "system", " 2G ", " Linux ")
    // 	];

define list get_lv_widget_table( list<map> possPvList )
    ``{
    list    ret = [];

    possPvList = 
	sort( map x, map y, possPvList,
	    ``{
	    if( x["maindev"]:"" == y["maindev"]:"" )
		{
		return( x["nr"]:(any)"" < y["nr"]:(any)"" );
		}
	    else
		{
		return( x["maindev"]:"" < y["maindev"]:"" );
		}
	    });
    
    
    return( maplist( map partition, possPvList,
	     ``{
	     return(`item( `id(partition["devkey"]:"--"),
			       partition["device"]:"--",
			       partition["mount"]:"",
			       partition["lvm_name"]:"",
			       partition["size_str"]:"--",
			       partition["fstype"]:"--"
			       ));
		}
	     ));
    };



}
