/**
 * File:	modules/AutoinstRAID.ycp
 * Module:	Auto-Installation
 * Summary:	RAID
 * Authors:	Anas Nashif <nashif@suse.de>
 *
 * $Id: AutoinstRAID.ycp 22485 2005-03-13 00:37:11Z nashif $
 */
{

    module "AutoinstRAID";
    textdomain "autoinst";

    import "Storage";
    import "Partitions";
    import "AutoinstStorage";

    include "partitioning/partition_defines.ycp";
    include "partitioning/raid_lib.ycp";


    global map<string, map> ExistingRAID = $[];

    global boolean old_available = false;

    map raid = $[];

    // Local variables
    list region = [0,0];

    // Temporary copy of variable from Storage
    map<string, map> targetMap = $[];


    /**
     * Constructor
     * @return void
     */
    global define void AutoinstRAID () {
        return;
    }

    /**
     * Initialize
     */
    global boolean Init ()
    {
	raid   = filter(string k, map v,
                AutoinstStorage::AutoTargetMap, ``(k  == "/dev/md"));
	
	if (size(raid) == 0)
	{
	    return false;
	}

	ExistingRAID	= filter(string k,map v, Storage::GetTargetMap(), ``(k == "/dev/md"));
	y2milestone("Existing RAID: %1", ExistingRAID );

	if (size(ExistingRAID) > 0 )
	    old_available = true;

	return true;
    }

    /**
     * Return existing MDs
     * @return list list of existing MDs
     */
    /*
    global define list ExistingMDs ( string md ) {
	return(filter( map part, get_possible_rds( Storage::GetTargetMap() ),  
                    ``( part["raid_name"]:"-1" == md )));
    }
    */


    map FindMatchingDevice(integer nr) {
        list<map> match = filter(map d, ExistingRAID["/dev/md", "partitions"]:[], 
                ``(d["nr"]:-1 == nr && !d["delete"]:false));
        return match[0]:$[];
    }


    /**
     * Return deleted MDs
     * @return list list of deleted MDs
     */
    global define list DeletedMDs ( string md ) {
	list<list<map> > ret = [];
	foreach( string dev, map devmap, Storage::GetTargetMap(),
		 ``{
	    ret = add( ret,
		       filter( map part, devmap["partitions"]:[],
			       ``(
				  part["raid_name"]:"" == md
				  &&
				  part["delete"]:false
				  &&
				  part["fsid"]:0 == Partitions::fsid_raid
				  )
			       )
		       );
	});

	return( flatten(ret) );
    }


    /**
     * Delete MDs
     * @return list list of deleted MDs
     */
    global define list DeleteMDs () {
	list to_bo_deleted = [];
	foreach( string dev, map devmap, Storage::GetTargetMap(), ``{
	    foreach( map part,  devmap["partitions"]:[], ``{
		if (part["old_raid_name"]:"" != "" && part["delete"]:false)
		{
		    to_bo_deleted= add(to_bo_deleted, part["old_raid_name"]:"");
		}
	    });
	});

	y2milestone("mds to delete: %1", to_bo_deleted);

	if (old_available)
	{
	    list<map> mds = Storage::GetTargetMap()["/dev/md","partitions"]:[];
	    list<map> new_mds = maplist( map md, mds ,``{
		if ( contains(to_bo_deleted, md["device"]:""))
		{
		    md["delete"] = true;
		}
		return (md);
	    });
	    y2milestone("new_mds: %1", new_mds );
	    map allmds =  targetMap["/dev/md"]:$[];
	    allmds["partitions"] = new_mds;
	    targetMap["/dev/md"] = allmds;
	    Storage::SetTargetMap(targetMap);
	}
    }


    /**
     * Remove MDs if desired
     * @return boolean
     */
    define boolean remove_possible_mds () {

        boolean prefer_remove = raid["/dev/md", "prefer_remove"]:false;
        if (old_available && prefer_remove)
        {
            list<map> existing_mds = ExistingRAID["/dev/md","partitions"]:[];
            list<map> modified_mds = maplist( map md, existing_mds ,``{
                    md["delete"] = true;
                    return (md);
                    });
            map<string, any> allmds =  (map<string, any>)ExistingRAID["/dev/md"]:$[];
            allmds["partitions"]	= modified_mds;
            Storage::AddMainDev("/dev/md",  allmds );
            // update our variable
            ExistingRAID["/dev/md"] = allmds;
        }
	y2milestone("ExistingRAID after delete: %1", ExistingRAID );
        return true;
    }

    /**
     * Create RAID Configuration
     * @return boolean
     */
    global define boolean Write() {

        remove_possible_mds ();
        list<map> raid_partitions = raid["/dev/md", "partitions"]:[];

	list<map> RaidList =  [];
        foreach ( map md, raid_partitions,  ``{

	    string use	= raid["/dev/md","use"]:"none";
	    string dev	= sformat("/dev/md%1", md["partition_nr"]:0);
	    
            map existing = FindMatchingDevice(md["partition_nr"]:0);
            
            if (existing != $[] && existing != nil )
            {
                existing["mount"] = md["mount"]:"";
		if (!haskey(md, "format"))
		    existing["format"]	= false;
		else
		    existing["format"] = md["format"]:false;

		if (md["format"]:false)
		    existing["used_fs"]	= md["filesystem"]:`ext2;

		existing["create"]	= false;
		RaidList=add(RaidList, existing );
            }
	    else
	    {
		md["device"]	= dev;

		if (md["loop_fs"]:false || md["crypt_fs"]:false)
		    md["crypt_key"] =   Storage::AddCryptToClassified( md["crypt_key"]:"");

		y2milestone("Working on %1", md);

		string chunk_size = "4";
		map options = md["raid_options"]:$[];
		string raid_type	= options["raid_type"]:md["raid_type"]:"raid1";

		if ( raid_type == "raid5" )
		    chunk_size = "128";

		if ( raid_type == "raid0" )
		    chunk_size = "32";


		if (!haskey(options, "raid_type"))
		    options["raid_type"] = raid_type;

		string sel_chunksize = options["chunk_size"]:"";

		if ( sel_chunksize != "" ) {
		    chunk_size = sel_chunksize;
		    options["chunk_size"]	= chunk_size;
		}

		if(  raid_type == "raid5" && options["parity_algorithm"]:"" == "" )
		    options["parity_algorithm"] = "left-symmetric";

		md["nr"] = md["partition_nr"]:0;


		// LVM on RAID
		if (md["lvm_group"]:"" != "")
		    md["fsid"]		= Partitions::fsid_lvm;
		else
		    md["fsid"]		= md["partition_id"]:Partitions::fsid_native;
            
		md["region"]		= [0 , 1];

		if (!haskey(md, "create")) {
		    md["create"]	= true;
		    md["status"]	= "create";
		}

		if (!haskey(md, "format"))
		    md["format"]	= false;

		if (md["format"]:false)
		    md["used_fs"]	= md["filesystem"]:`ext2;

		md["type"]		= `sw_raid;

		if (haskey(md, "raid_options"))
		    md=remove(md, "raid_options");

		RaidList=add(RaidList, union(md, options) );
	    }
	   
	});


        // Adjust Sizes
	RaidList= maplist( map md, RaidList,
			   ``({
			       integer len = raid_size_byte( Storage::GetTargetMap(), md);
			       md["region"] = [0, len / (1024 * 1024)];
			       return( md );
			   }));



        y2milestone("All RAID: %1", RaidList);


        map<string, any> RaidMap = 
            $[
            "cyl_count" : 1,                   
            "cyl_size" : 1024 * 1024,         
            "name" : Partitions::raid_name,
            "partitions" : RaidList,
            ];
	y2milestone("RaidMap: %1", RaidMap);

        if (old_available)
        {
            RaidMap["whole_disk"] = true;
            Storage::SetMainDev("/dev/md",  RaidMap );
        }
        else
        {
            RaidMap["whole_disk"] = true;
            Storage::AddMainDev("/dev/md",  RaidMap );
        }
	y2milestone("Targets: %1", Storage::GetTargetMap());
	return true;
    }


}

