/**
 *
 *
 * File:
 *   sound.ycp
 *
 * Module:
 *   Sound
 *
 * Authors:
 *   Dan Vesely <dan@suse.cz>
 *   Dan Meszaros <dmeszar@suse.cz>
 *   Jiri Suchomel <jsuchome@suse.cz>
 *
 * $Id: sound.ycp 20357 2004-11-18 13:37:56Z lslezak $
 *
 * Installation of the sound card. If the sound card was not auto-detected ask user.
 *
 *
 */

{
textdomain "sound";

y2milestone ("----------------------------------------");
y2milestone ("Sound module started");

import "Mode";
import "Directory";
import "Popup";
import "Sound";
import "Joystick";
import "Report";
import "CommandLine";
import "RichText";

include "sound/wizards.ycp";

integer arg_n = size (WFM::Args ()) - 1;
while (arg_n >= 0)
{
    if (WFM::Args(arg_n) == .test)
    {
        Mode::SetTest("test");
    }
    arg_n = arg_n - 1;
}

/* check for database existence */
if (Sound::use_alsa &&
    SCR::Read(.target.size, Directory::datadir + "/sndcards.ycp") == -1)
{
    // popup error message
    Report::Error (_("Sound card database not found. Please check your installation."));
    return nil;
}

// --------------------------------------------------------------------------
// --------------------------------- cmd-line handlers

/**
 * Print summary of basic options
 * @return boolean false
 */
define boolean SoundSummaryHandler (map options ) ``{

    CommandLine::Print (RichText::Rich2Plain(Sound::Summary ()));
    return false; // do not call Write...
}

/**
 * Wrapper function for reading the settings (used by cmd-line)
 * @return boolean success
 */
define boolean SoundRead () ``{

    Sound::use_ui = false;
    block<boolean> abort_block = ``{return false;};
    boolean ret = Sound::Read (false) && Joystick::Read(abort_block);
    return ret;
}

/**
 * Wrapper function for writing the settings (used by cmd-line)
 * @return boolean success
 */
define boolean SoundWrite () ``{

    return Sound::Write ();
}

/**
 * Handler for adding new card
 * @param options parameters on command line
 * @return boolean success
 */
define boolean AddCardHandler (map options) ``{

    integer card_no	= tointeger (options["card"]:"-1");
    boolean all		= haskey (options, "all");
    string modname	= options["module"]:"";
    boolean ret		= false;

    if (all ||
	(Sound::unconfigured_cards != []) && (card_no == -1) && (modname == ""))
    {
	card_no = 0;
    }
    Sound::card_id = card_no; // now Sound::card_id is index to Sound::unconfigured_cards

    // 1. choose the card to add
    map save_entry = $[];
    if (Sound::card_id >= 0)  // -1 is for manual...
    {
	save_entry = Sound::unconfigured_cards[Sound::card_id]:$[];
	if (save_entry == $[])
	{
	    // error message
	    Report::Error ("There is no such detected card.");
	    return false;
	}
    }
    if (save_entry == $[])// manual adding
    {
	if (modname == "")
	{
	    // error message (inssuficient parameters)
	    Report::Error ("You must specify the kernel module name if you want to add a card which was not detected.");
	    return false;
	}
	save_entry = update_manual_card ($[ "module": modname ]);
    }

    integer volume_b	= Sound::default_volume;
    if (haskey (options, "volume"))
	Sound::default_volume = tointeger (options["volume"]:"75");

    // 2. configure selected card(s) ------------
    do
    {
	list save_info	= Sound::modules_conf;
	Sound::card_id	= size (Sound::modules_conf); // id of new card

	save_entry	= add_common_options (save_entry, Sound::card_id);
	save_entry	= add_alias (save_entry, Sound::card_id);

	// now set the value of given kernel parameters...
	modname		= save_entry["module"]:"";
	map params      = get_module_params (modname);
	params		= restore_mod_params (params,save_entry["options"]:$[]);
	foreach (string optname, map o, (map<string,map>) params, {
	    if (haskey (options, optname) && o["value"]:""!=options[optname]:"")
	    {
		list<string> possible_values = string2vallist (o["allows"]:"");
		string err = check_value (
		    options[optname]:"", "string", possible_values);
		if (err != "")
		{
		    CommandLine::Print (err);
		    return;
		}
		save_entry ["options", optname] = options[optname]:"";
	    }
	});

	map res = sound_volume (save_entry, Sound::card_id, true, true, save_info);
	ret = (res["ui"]:`back == `next);

	if (ret)
	{
	    Sound::modules_conf = add (Sound::modules_conf, save_entry);
	    if (card_no >= 0) // was autodetected
	    {
		Sound::unconfigured_cards = remove (Sound::unconfigured_cards,
		    card_no);
	    }
	    // result message, %1 is card name
	    CommandLine::Print (sformat (_("Successfully added card '%1'."),
		save_entry["model"]:""));
	    if (haskey (options, "play"))
		PlayTest (Sound::card_id);
	}
	save_entry	= Sound::unconfigured_cards [0]:$[];

    } while (all && ret && (save_entry != $[]));

    Sound::default_volume = volume_b;
    return ret;
}

/**
 * Handler for removing the sound card
 * @param options parameters on command line
 * @return boolean success
 */
define boolean RemoveCardHandler (map options) ``{

    integer card_no	= tointeger (options["card"]:"-1");
    boolean all		= haskey (options, "all");
    boolean ret		= false;

    if ((card_no == -1 && size (Sound::modules_conf) == 1) || all)
	card_no = 0;// choose first card only if it is the only one
    if (card_no == -1)
    {
	//error message
	Report::Error( _("You must specify the card number."));
	return false;
    }
    if (Sound::modules_conf[card_no]:nil == nil)
    {
	//error message
	Report::Error( _("There is no such sound card."));
	return false;
    }

    Sound::card_id = card_no;
    do
    {
	ret = (_snd_delete() == `next);
    }
    while (all && ret && Sound::modules_conf[Sound::card_id]:nil != nil);

    return ret;
}

/**
 * Handler for playing the test sound
 * @param options parameters on command line
 * @return boolean false (no write)
 */
define boolean TestCardHandler (map options) ``{

    integer card_no = tointeger (options["card"]:"-1");
    if (card_no == -1 && size (Sound::modules_conf) > 0)
	card_no = 0;// choose first card if number is not given
    if (Sound::modules_conf[card_no]:nil == nil)
    {
	//error message
	Report::Error( _("There is no such sound card."));
	return false;
    }
    string ret = PlayTest (card_no);
    if (ret != "")
    {
	Report::Error (ret);
	return false;
    }
    return false; // write not necessary
}

/**
 * Handler for showing sound card information
 * @param options parameters on command line
 * @return boolean false (no write)
 */
define boolean ShowCardHandler (map options) ``{

    integer card_no = tointeger (options["card"]:"-1");
    if (card_no == -1 && size (Sound::modules_conf) > 0)
	card_no = 0;// choose first card if number is not given
    map save_entry = Sound::modules_conf[card_no]:nil;
    if (save_entry == nil)
    {
	//error message
	Report::Error( _("There is no such sound card."));
	return false;
    }
    string modname	= save_entry["module"]:"";
    map params          = get_module_params (modname);
    params		= restore_mod_params (params,save_entry["options"]:$[]);

    // label: list of card parameters will follow; %1 is card name, %2 driver
    string out = sformat (_("Parameters of card '%1' (using module %2):\n"),
	save_entry["model"]:"", modname);

    foreach (string optname, map option, (map<string,map>) params, ``{
	out = out + sformat ("\n%1", optname) + "\n\t"
	    + getDescr (option["descr"]:nil);
	if (option["default"]:"" != "")
	    // label (default value of sound module parameter)
	    out = out +sformat(_("\n\tDefault Value: %1"),option["default"]:"");
	if (option["value"]:"" != "")
	    // label (current value of sound module parameter)
	    out = out + sformat(_("\n\tCurrent Value: %1"), option["value"]:"");
    });
    CommandLine::Print (out);

    return false; // write not necessary
}

/**
 * Handler for setting the paramerer values of sound card
 * @param options parameters on command line
 * @return boolean success
 */
define boolean SetParametersHandler (map options) ``{

    integer card_no = tointeger (options["card"]:"-1");
    if (card_no == -1 && size (Sound::modules_conf) == 1)
	card_no = 0;// choose first card only if it is the only one
    if (card_no == -1)
    {
	//error message
	Report::Error( _("You must specify the card number."));
	return false;
    }
    map save_entry = Sound::modules_conf[card_no]:nil;
    if (save_entry == nil)
    {
	//error message
	Report::Error( _("There is no such sound card."));
	return false;
    }

    string modname	= save_entry["module"]:"";
    map params          = get_module_params (modname);
    params		= restore_mod_params (params,save_entry["options"]:$[]);
    options		= remove (options, "card");

    boolean modified	= false;

    if (haskey (options, "volume"))
    {
	integer volume	= tointeger (options["volume"]:"75");
	string master	= Sound::db_modules[modname,"main_volume"]:"Master";
	setVolume (master, card_no, volume);
        setVolume ("Headphone", card_no, volume);
	map devs	= Sound::db_modules[modname,"mixer"]:$[];
        if (haskey (devs, "PCM"))
	    setVolume ("PCM", card_no, volume);

	storeVolume (card_no);
    }

    foreach (string optname, map o, (map<string,map>) params, {
	if (haskey (options, optname) && o["value"]:"" != options[optname]:"")
	{
	    list<string> possible_values = string2vallist (o["allows"]:"");
	    string err = check_value (
		options[optname]:"", "string", possible_values);
	    if (err != "")
	    {
		CommandLine::Print (err);
		return false;
	    }
	    save_entry ["options", optname] = options[optname]:"";
	    modified	= true;
	}
    });
    if (modified)
    {
	// save save_entry
	integer pos = 0;
	Sound::modules_conf = maplist (map card, Sound::modules_conf, ``{
	    if (pos != card_no)
	    {
		pos = pos + 1;
		return card;
	    }
	    else
	    {
		pos = pos + 1;
		return save_entry;
	    }
	});
    }
    return modified;
}

/**
 * Handler for setting the volume of sound card
 * @param options parameters on command line
 * @return boolean success
 */
define boolean SetVolumeHandler (map options) {

    integer card_no = tointeger (options["card"]:"-1");
    if (card_no == -1 && size (Sound::modules_conf) == 1)
	card_no = 0;// choose first card only if it is the only one
    if (card_no == -1)
    {
	//error message
	Report::Error( _("You must specify the card number."));
	return false;
    }
    map save_entry = Sound::modules_conf[card_no]:nil;
    if (save_entry == nil)
    {
	//error message
	Report::Error( _("There is no such sound card."));
	return false;
    }

    string modname	= save_entry["module"]:"";
    options		= remove (options, "card");
    path pth    = topath(sformat(".audio.alsa.cards.%1.channels", card_no));
    list channels = Sound::db_modules[modname, "mixer_elements"]:SCR::Dir(pth);
    boolean modified	= false;

    foreach (string channel, string val, (map<string,string>) options, {
	if (contains (channels, channel))
	{
	    integer volume	= tointeger (val);
	    setVolume (channel, card_no, volume);
	    modified		= true;
	}
    });
    if (modified)
	storeVolume (card_no);
    if (haskey (options, "play"))
	PlayTest (card_no);
    return false;
}

/**
 * Handler for listing available channels
 */
define boolean ListChannelsHandler (map options) ``{

    integer card_no = tointeger (options["card"]:"-1");
    if (card_no == -1 && size (Sound::modules_conf) == 1)
	card_no = 0;// choose first card only if it is the only one
    if (card_no == -1)
    {
	//error message
	Report::Error( _("You must specify the card number."));
	return false;
    }
    map save_entry = Sound::modules_conf[card_no]:nil;
    if (save_entry == nil)
    {
	//error message
	Report::Error( _("There is no such sound card."));
	return false;
    }

    string modname	= save_entry["module"]:"";
    path pth    = topath(sformat(".audio.alsa.cards.%1.channels", card_no));
    list channels = Sound::db_modules[modname, "mixer_elements"]:SCR::Dir(pth);

    foreach (string ch, (list<string>) channels, {
	integer value = (integer) SCR::Read (topath (
	    sformat(".audio.alsa.cards.%1.channels.%2.volume", card_no, ch)));
	CommandLine::Print (sformat ("%1\t%2", ch, value));
    });

    return false;
}
/**
 * Handler for listing available kernel modules for sound
 */
define boolean ListModulesHandler (map options) ``{

    /*
    // kernel module name
    CommandLine::Print (_("Kernel module") + "\t"
	// kernel module description
	+ _("Description"));
    */
    foreach (term it, (list<term>) get_module_names(), ``{
	string id	= (string) it[0, 0]:"all";
	string name	= it[1]:id;
	if (id == "all")
	    return;
	string space = "\t";
	/*
	if (size (id) < 16)
	    space = space + "\t";
	if (size (id) < 8)
	    space = space + "\t";*/
	CommandLine::Print (id + space + name);
//	CommandLine::Print (sformat ("%1 (%2)", name, id));
    });

    return false;
}


/* the command line description map */
map cmdline = $[
    "id"		: "sound",
    // translators: command line help text for Sound module
    "help"		: _("Sound card configuration module."),
    "guihandler"	: SoundSequence,
    "initialize"	: SoundRead,
    "finish"		: SoundWrite,
    "actions"		: $[
	"summary" :$[
	    "handler"	: SoundSummaryHandler,
	    // translators: command line help text for summary action
	    "help"	: _("Configuration summary of sound cards")
	],
	"add" :$[
	    "handler"	: AddCardHandler,
	    // translators: command line help text for add action
	    "help"	: _("Add sound card. Without parameters, add first one detected."),
	    "options"	: [ "non_strict" ],
	    // help text for unknownd parameters
	    "non_strict_help" : _("Value of the specific module parameter."),
	],
	"remove" :$[
	    "handler"	: RemoveCardHandler,
	    // translators: command line help text for remove action
	    "help"	: _("Remove sound cards")
	],
	"playtest" :$[
	    "handler"	: TestCardHandler,
	    // translators: command line help text for test action
	    "help"	: _("Play test sound on given sound card")
	],
	"show": $[
	    "handler"	: ShowCardHandler,
	    // translators: command line help text for test action
	    "help"	: _("Show the information of given sound card")
	],
	"set": $[
	    "handler"	: SetParametersHandler,
	    // translators: command line help text for set action
	    "help"	: _("Set the new values for given card parameters."),
	    "options"	: [ "non_strict" ],// - for unknown parameter names
	    // help text for unknownd parameters; do not translate 'show'
	    "non_strict_help" : _("Value of the specific module parameter. Use the 'show' command to see a list of allowed parameters."),
	],
	"volume": $[
	    "handler"	: SetVolumeHandler,
	    // translators: command line help text for volume action
	    "help"	: _("Set the volume of specific channels of the given card."),
	    "options"	: [ "non_strict" ],// - for unknown parameter names
	    // help text;  do not translate 'channels' as command name
	    "non_strict_help" : _("Value of the specific channel (0-100). Use the 'channels' command to see a list of available channels."),
	],
	"modules": $[
	    "handler"	: ListModulesHandler,
	    // translators: command line help text for modules action
	    "help"	: _("List all available sound kernel modules.")
	],
	"channels": $[
	    "handler"	: ListChannelsHandler,
	    // translators: command line help text for channels action
	    "help"	: _("List available volume channels of given card.")
	],
    ],
    "options"		: $[
	"card"	:$[
	    // translators: command line help text for the 'card' option
	    "help"	: _("Number of sound card"),
	    "type"	: "string"
	],
	"all"	:$[
	    // translators: command line help text for the 'all' option
	    "help"	: _("All available sound cards"),
	],
	"module"	:$[
	    // translators: command line help text for the 'module' option
	    "help"	: _("Kernel module (driver) for the sound card"),
	    "type"	: "string"
	],
	"play"	:$[
	    // translators: command line help text for the 'play' option
	    "help"	: _("Play the test sound when the card is configured"),
	],
	"volume"	:$[
	    // translators: command line help text for the 'volume' option
	    "help"	: _("Volume value for the sound card (0-100)"),
	    "type"	: "string"
	],
    ],
    "mappings"		: $[
	"summary"	: [],
	"add"		: [ "card", "all", "module", "play", "volume"],
	"remove"	: [ "card", "all" ],//delete alias
	"playtest"	: [ "card" ],
	"show"		: [ "card" ],
	"set"		: [ "card", "volume" ],//edit alias
	"channels"	: [ "card" ],
	"volume"	: [ "card", "play" ],
	"modules"	: [],
    ]
];

// --------------------------------- cmd-line handlers
// --------------------------------------------------------------------------


any ret = nil;

if (Sound::use_alsa)
    ret = CommandLine::Run ( cmdline );
else
    ret = SoundSequence ();

y2debug("ret == %1", ret);

y2milestone("Sound module finished");
y2milestone("----------------------------------------");

return ret;
}//EOF
