/**
 *
 * $Id: write_routines.ycp 22766 2005-03-23 15:43:06Z lslezak $
 *
 * File:
 *   write_routines.ycp
 *
 * Module:
 *   Sound
 *
 * Summary:
 *   API for writings sound configuration
 *
 * Authors:
 *   Dan Vesely <dan@suse.cz>
 *   Dan Meszaros <dmeszar@suse.cz>
 *
 *
 */

{
    textdomain "sound";

    import "Arch";
    import "Sound";
    import "HWConfig";
    include "sound/routines.ycp";

    /**
     * create special comment for given model
     * @param model card description
     * @param uniq_key unique key
     * @return string comment for the alias
     */

    define string createAliasComment(string model, string uniq_key) ``{
	string comment = "# " + uniq_key + ":" + model + "\n";
	return comment;
    }

    define string MergeOptions(map<string,string> options) {
	string ret = "";

	if (options != nil && size(options) > 0)
	{
	    foreach(string key, string val, options, {
		    if (key != nil && key != "" && val != nil)
		    {
			if (ret == "")
			{
			    ret = key + "=" + val;
			}
			else
			{
			    ret = ret + " " + key + "=" + val;
			}
		    }
		}
	    );
	}

	return ret;
    }

    // search hwcfg-static file with required string in comment of MODULE variable
    define string FindStaticHWConfig(string uniq) {
	string file = nil;

	// get all static configurations
	list<string> configs = HWConfig::ConfigFiles();
	configs = filter(string f, configs, {return regexpmatch(f, "^static-[0-9]*");});

	// search existing config file
	if (size(configs) > 0)
	{
	    integer greatest = -1;
	    boolean found = false;

	    // search existing config
	    foreach(string f, configs, {
		    if (!found)
		    {
			// read MODULE comment
			string comment = HWConfig::GetComment(f, "MODULE");

			if (comment != nil && comment != "")
			{
			    // search for sound alias and uniqID
			    if (regexpmatch(comment, uniq))
			    {
				file = f;
				found = true;
			    }
			}
		    }
		}
	    );
	}

	return file;
    }

    /**
     * Saves one '/etc/modules.conf' entry
     * @param entry card config
     * @return boolean success/failure
     */
    define boolean SaveOneModulesEntry (map entry) ``{

        path mod_alias	= add (.modprobe_sound.alias, entry ["alias"]:"off");
        path mod_alias_comment	=
            add ( add (.modprobe_sound.alias, entry ["alias"]:"off"),"comment");

	y2debug("entry: %1", entry);

	// save hwcfg config file
	string file = "";
	if (entry["bus"]:"" != "pci")
	{
	    y2milestone("The soundcard is not attached to PCI");

	    // get all static configurations
	    list<string> configs = HWConfig::ConfigFiles();
	    configs = filter(string f, configs, {return regexpmatch(f, "^static-[0-9]*");});
	    y2milestone("found static configs: %1", configs);

	    // search existing config file
	    if (size(configs) > 0)
	    {
		integer greatest = -1;
		boolean found = false;

		// search existing config
		foreach(string f, configs, {
			if (!found)
			{
			    // read MODULE comment
			    string comment = HWConfig::GetComment(f, "MODULE");

			    if (comment != nil && comment != "")
			    {
				y2debug("comment: %1", comment);
				y2debug("alias: %1", entry["alias"]:"");
				y2debug("unique_key: %1", entry["unique_key"]:"");
				// search for sound alias and uniqID
				if (regexpmatch(comment, entry["alias"]:"") && regexpmatch(comment, entry["unique_key"]:""))
				{
				    file = f;
				    found = true;
				    y2milestone("Found flags in file: %1", f);
				}
			    }

			    if (!found)
			    {
				// not found, check config number
				string num = regexpsub(f, "^static-([0-9]*)", "\\1");

				if (num != nil)
				{
				    integer num_i = tointeger(num);
				    if (num_i != nil && num_i > greatest)
				    {
					greatest = num_i;
				    }
				}
			    }
			}
		    }
		);

		if (file == nil || file == "")
		{
		    y2debug("file empty, greatest: %1", greatest);
		    // not found - create new config
		    file = sformat("static-%1", greatest + 1);
		}
	    }
	    else
	    {
		file = "static-0";
	    }
	}
	else
	{
	    file = "bus-pci-" + entry["bus_id"]:"";
	}
	y2milestone("using hwcfg file: hwcfg-%1", file);

        boolean ret = true;
        if (haskey (entry, "alias"))
        {
	    // set module name
	    ret = ret && HWConfig::SetValue(file, "MODULE", entry["module"]:"");
	    // set automatic start at boot
	    ret = ret && HWConfig::SetValue(file, "STARTMODE", "auto");

	    // TODO LATER: for now save options to modprobe.d only, later to hwcfg
	    // string options = MergeOptions(entry["options"]:$[]);
	    // ret = ret && HWConfig::SetValue(file, "MODULE_OPTIONS", options);

	    string modcomment = createAliasComment(entry["model"]: "", entry["unique_key"]:"");
	    string comment = "# YaST configured sound card " + entry["alias"]:"" + "\n" + modcomment;
	    ret = ret && HWConfig::SetComment(file, "MODULE", comment);

            ret = ret && SCR::Write(mod_alias, entry["module"]:"off");
	    ret = ret && SCR::Write(mod_alias_comment, modcomment);
        }
        return ret;
    }

    /**
     * saves modules options. this function has to collect parameters that use
     * different cards that use single module and create a coma separated list of values
     * @param save_info save info
     * @return void
     */

    define void SaveModulesOptions(list save_info) ``{

	path mod_options = .modprobe_sound.options;

	// create distinct list of all modules
	list mods = toset(maplist(map card, (list<map<string,any> >) save_info,
	    ``(card["module"]:"off")));

	foreach(string modname, (list<string>) mods, ``{
	    map res = Sound::CollectOptions(modname);
	    SCR::Write( add (mod_options, modname ), res);
	});
    }

    /**
     * removeOldAliases
     * @param als list with old aliases
     */
    define void removeOldEntries(list als) ``{
	maplist(string e, (list<string>) als, ``{
	    if (is_snd_alias(e) ||
		issubstring(e, "sound-service-") ||
		issubstring(e, "sound-slot-"))
		{
		    SCR::Write( add (.modprobe_sound.alias, e), nil);
		}
	});
    }

    /**
     * Remove sound configuration from /etc/modprobe.conf
     */
    define void RemoveOldConfiguration () ``{

	y2milestone ("removing old sound configuration from /etc/modprobe.conf (it was already saved to /etc/modprobe.d/sound)");

	path mod		= .modules;
	path mod_alias		= .modules.alias;
	path mod_options	= .modules.options;

	if (contains(SCR::Dir(mod), "alias"))
	{
	    list<string> als = (list<string>)SCR::Read(mod_alias);
	    foreach (string e, als, ``{
		if (is_snd_alias(e) ||
		    issubstring(e, "sound-service-") ||
		    issubstring(e, "sound-slot-") ||
		    e == "char-major-14" ||
		    e == "char-major-116")
		{
		    SCR::Write (add (mod_alias, e), nil);
		}
	    });
	}
	// remove also old options
	foreach (map card, Sound::modules_conf_b, ``{
	    string modname = card["module"]:"";
	    if (modname != "")
		SCR::Write (add (mod_options, modname ), nil);
	});
	SCR::Write (mod, nil);
    }

    define boolean RemoveHWConfig() {
	boolean ret = true;

	if (Sound::removed_info != nil)
	{
	    foreach(map info, Sound::removed_info, {
		    string bus = info["bus_hwcfg"]:"";
		    string bus_id = info["sysfs_bus_id"]:"";
		    string uk = info["unique_key"]:"";

		    if (bus == "pci")
		    {
			string file = "pci-" + bus_id;

			y2milestone("Removing file: %1", file);
			HWConfig::RemoveConfig(file);
		    }
		    else
		    {
			if (uk != nil && uk != "")
			{
			    string file = FindStaticHWConfig(uk);

			    if (file != nil)
			    {
				y2milestone("Removing file: %1", file);
				HWConfig::RemoveConfig(file);
			    }
			}
		    }
		}
	    );
	}
    }
    /**
     * Saves all '/etc/modprobe.d/sound' entries
     * @param save_info cards save info
     * @param system sytem dependent part
     * @return map return struct: $["return": boolean, "err_msg": string]
     */
    define map SaveModulesEntry (list save_info, list system) ``{

	path mod		= .modprobe_sound;
	path mod_alias		= .modprobe_sound.alias;
	path mod_options	= .modprobe_sound.options;
	SaveModulesOptions(save_info);

	list als=[];

        string err_msg = "";
	if (contains(SCR::Dir(mod), "alias"))
	{
	    als = (list)SCR::Read(mod_alias);
	}
	// remove old entries

	removeOldEntries (als);

	if (size(save_info) >0)
	{
	    if (!Sound::use_alsa)
	    {
		if (Arch::sparc ())
		{
		    string modname = save_info[0, "module"]:"off";
		    SCR::Write(add (mod_alias, "sound"), "sound-slot-0");
		}
	    }
	}

        if ((contains (maplist (map entry, (list<map<string,any> >)save_info,
		``(SaveOneModulesEntry (entry))), false)))
        {
            // Error message
            err_msg = err_msg + Sound::STRINGS["SaveModuleEntry"]:"";
            return $["return": false, "err_msg": err_msg];
        }

	// remove deleted sound cards
	RemoveHWConfig();

	// write the settings
	HWConfig::Flush();

	/* also this is not neccessary now... (?)
	if (size(save_info) > 0 && Sound::use_alsa)
	{

	    list oss_aliases = alsa_oss(size(save_info));
	    foreach(map a, (list<map<string,any> >)oss_aliases, ``{
		SCR::Write(add (mod_alias, a["alias"]:""), a["module"]:"");
	    });
	}
	*/
	SCR::Write(mod, nil);

	// now, when new configuration was succesfully written, we should remove
	// the old one from /etc/modprobe.conf...
	if (Sound::used_modprobe_conf)
	    RemoveOldConfiguration ();

        return $["return" : true, "err_msg" : ""];
    }

    /**
     * Save volume (for alsa it's alsactl store
     * @return boolean success/failure
     */
    define boolean SaveVolume () ``{
	return (boolean) SCR::Execute(.audio.alsa.store, 0, 0);
    }

    /**
     * saves rc values that are stored in map
     * @param rc map "variable" : "value", ....
     * @return string error string
     */
    define string SaveRCValues (map rc) ``{
	SCR::Write (.sysconfig.sound.LOAD_SEQUENCER, rc["LOAD_ALSA_SEQ"]:"no");
	return "";
    }


}
