/**
 * File:
 *   mixer.ycp
 *
 * Module:
 *   Sound
 *
 * Summary:
 *   advanced dialog for mixer setting
 *
 * Authors:
 * Dan Meszaros <dmeszar@suse.cz>
 *
 * String corrections by Christian Steinruecken <cstein@suse.de>, 2001/08/01
 *
 * $Id: mixer.ycp 19990 2004-10-27 10:25:26Z lslezak $
 *
 */

{
    textdomain "sound";
    import "Wizard";
    import "Sound";
    import "Label";

    include "sound/ui.ycp"; // only ReallyAbort?
    include "sound/volume_routines.ycp"; // setVolume, PlayTest

    // translation map of channel names
    map channel_trans = $[
	// channel name - label for IntField widget in mixer dialog
	"Master"	: _("Master"),
	// channel name - label for IntField widget in mixer dialog
	"PCM"		: _("PCM"),
	// channel name - label for IntField widget in mixer dialog
	"Master Mono"	: _("Master Mono"),
	// channel name - label for IntField widget in mixer dialog
	"Headphone"	: _("Headphone"),
	// channel name - label for IntField widget in mixer dialog
	"Line"		: _("Line"),
	// channel name - label for IntField widget in mixer dialog
	"CD"		: _("CD"),
	// channel name - label for IntField widget in mixer dialog
	"Mic"		: _("Mic"),
	// channel name - label for IntField widget in mixer dialog
	"Video"		: _("Video"),
	// channel name - label for IntField widget in mixer dialog
	"Phone"		: _("Phone"),
	// channel name - label for IntField widget in mixer dialog
	"Aux"		: _("Aux"),
	// channel name - label for IntField widget in mixer dialog
	"PC Speaker"	: _("PC Speaker"),
	// channel name - label for IntField widget in mixer dialog
	"Bass"		: _("Bass"),
	// channel name - label for IntField widget in mixer dialog
	"Treble"	: _("Treble"),
	// channel name - label for IntField widget in mixer dialog
	"Surround"	: _("Surround"),
	// channel name - label for IntField widget in mixer dialog
	"LFE"		: _("LFE"),
	// channel name - label for IntField widget in mixer dialog
	"Center"	: _("Center"),
	// channel name - label for IntField widget in mixer dialog
	"Wave"		: _("Wave"),
	// channel name - label for IntField widget in mixer dialog
	"Wave Center"	: _("Wave Center"),
	// channel name - label for IntField widget in mixer dialog
	"Wave Surround"	: _("Wave Surround"),
	// channel name - label for IntField widget in mixer dialog
	"AC97"		: _("AC97"),
	// channel name - label for IntField widget in mixer dialog
	"Music"		: _("Music")
    ];

    /**
     * Translate channel name
     * @param name untranslated channel name
     * @return string translated name
     */
    define string translateChannelName(string name) {
	if (name == nil || name == "")
	{
	    return "";
	}

	string ret = channel_trans[name]:name;
	y2debug("translated channel name: %1", ret);

	return ret;
    }

    /**
     * returns intfield (if we are running in ncurses) or
     * slider (for qt)
     * @param label label for slider
     * @param value initial value
     * @param spec true-slider false-intfield
     * @return term widget
     */
    define term volElement(string label, integer value, boolean spec) ``{
	if (spec)
	{
	    return `Slider(`id(label), `opt(`notify), translateChannelName(label), 0, 100, value);
	}
	else
	{
	    return `IntField(`id(label), `opt(`notify), translateChannelName(label), 0, 100, value);
	}
    }

    /**
     * creates a mixer widget with channels obtained from 1st param
     * @param channels channels to be shown
     * @return term widget
     */
    define term mixerWidget(list channels) ``{

        term widget	= `VBox();
        boolean spec	= UI::HasSpecialWidget(`Slider);
	integer nchan	= size(channels)-2; // don't count in 'Master' and 'PCM'
	integer ncols	= 4;

	// how many channels per column
	integer chansPerCol = tointeger(tofloat(nchan) / tofloat(ncols) +0.999);

	// 1. group first two elements to one Frame
	term ttmp = nil;
	if (spec)
	{
	    ttmp = `VBox();
	}
	else
	{
	    ttmp = `HBox();
	}
	integer pos = 0;
	while (pos < 2 && pos < size(channels))
	{
	    string lab	= channels [pos, 0]:"";
	    integer vol	= channels [pos, 1]:0;
	    ttmp	= add (ttmp, volElement (lab, vol, spec));
	    pos		= pos + 1;
	}

	ttmp = add(ttmp, `VSpacing(1));

	// frame label
	term mainGroup = `Frame(_("&Master volume"), `HBox(
	    `HSpacing(3),
	    ttmp,
	    `HSpacing(3),
	    `VBox (
		// push button label
		`PushButton(`id(`test), `opt(`key_F6), _("&Test"))
	    )
	));

	// 2. now group elements to columns

        integer counter	= 0;
        term col	= `HBox(`HSpacing(2));

	while (pos < size(channels))
	{
	    if (ncols == counter)
	    {
		widget = add(widget, `Top(col));
		if (!spec)
                {
                    widget = add(widget, `HStretch());
                }
                col = `HBox(`HSpacing(2));
                counter = 0;
	    }

	    string lab	= channels [pos, 0]:"";
	    integer vol	= channels [pos, 1]:0;

	    col		= add (col, `HWeight(1, volElement (lab, vol, false)));
	    col		= add (col, `HSpacing(2));
	    pos		= pos + 1;
	    counter	= counter + 1;
	}

	while (counter < ncols)
	{
	    col		= add (col, `HWeight(1, `Label(" ")));
	    col		= add (col, `HSpacing(2));
	    counter	= counter + 1;
	}
        widget = add (widget, `Top(col));

	// frame label
        return `VBox(mainGroup, `Frame(_("&Other channels"), widget));
    }

/**
 * shows mixer dialog for respective card
 * @param card_id card id
 * @return map result
 */
define map mixerDialog (integer card_id) ``{

    Sound::LoadDatabase (true);

    path pth	= topath(sformat(".audio.alsa.cards.%1.channels", card_id));
    list channels	= [];
    string modname	= "";

    if (Sound::use_alsa)
    {
	modname	= Sound::modules_conf[card_id, "module"]:"snd-dummy";
	channels = Sound::db_modules[modname, "mixer_elements"]:SCR::Dir(pth);
    }
    else
    {
	channels = ["Master"];
    }

    list muted		= [];

    pth = topath(sformat(".audio.alsa.cards.%1.name", card_id));
    string card_name = Sound::use_alsa ?
	(string) SCR::Read(pth) : sformat("%1",card_id);

    // get list of muted channels
    if (Sound::use_alsa)
    {
	foreach(string channel, (list<string>) channels, ``{
	    path pth2 = topath(sformat(".audio.alsa.cards.%1.channels.%2.mute",
		card_id, channel));
	    if ((boolean) SCR::Read(pth2))
	    {
		muted = add (muted, channel);
	    }
	});

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

	// put 'Master', 'PCM' to list head
	if (contains(channels, "PCM"))
	{
	    channels = filter (string ch, (list<string>) channels, ``(ch !="PCM"));
	    channels = prepend (channels, "PCM");
	}

	string master_channel =
	    Sound::db_modules [modname, "main_volume"]:"Master";

	if (modname != "" && contains(channels, master_channel))
	{
	    channels = filter (string ch, (list<string>) channels, ``(ch !=master_channel));
	    channels = prepend (channels, master_channel);
	}
	channels = (list<list>)
	maplist(string ch, (list<string>) channels, ``{
	    if (contains(muted, ch))
	    {
		return [ch, 0];
	    }
	    else
	    {
		return [ch, SCR::Read(topath(
		    sformat(".audio.alsa.cards.%1.channels.%2.volume",
		    card_id, ch)))
		];
	    }
	});
    }
    else
    {
	integer vol = (integer)SCR::Read(
	    topath(sformat(".audio.oss.cards.%1.channels.Master", card_id)));
	channels = [["Master", vol]];
    }

    // help text - mixer setting
    string help = _("<P>With this dialog you can set volume for each channel of the selected sound card. 
Press <B>Next</B> to save your volume settings, press <B>Back</B> to restore the original settings.</P>");

    term con = mixerWidget (channels);

    // dialog header
    Wizard::SetContents (sformat(_("Volume settings for card '%1'"), card_id),
	con, help, true, true);
    Wizard::RestoreNextButton();

    any	ui = nil; // value can be `next `abort... or string (channel name)
    integer value = 0;

    UI::ChangeWidget (`id(`test), `Enabled, !Mode::config());

    repeat
    {
	ui = UI::UserInput();

	if (is(ui, string))
	{
	    // unmute if neccessary
	    if (contains(muted, ui))
	    {
		SCR::Write (
		    topath(sformat(
			".audio.alsa.cards.%1.channels.%2.mute", card_id,ui)),
		    false);
	    }
	    // set volume
	    if (Sound::use_alsa)
	    {
		setVolume ((string)ui, card_id, value);
		value = (integer)UI::QueryWidget(`id(ui), `Value);
	    }
	    else
	    {
		setVolume("Master", card_id,
		    (integer)UI::QueryWidget(`id(ui), `Value));
	    }
	}
	else if (ui == `test)
	{
	    PlayTest(card_id);
	}
	else if (ui == `abort && ReallyAbort())
	{
	    return $["ui": `abort];
	}

    } until (ui == `back || ui == `next);

    if (ui == `next)
    {
	// store volume settings
	path pth = topath(sformat(".audio.alsa.cards.%1.store", card_id));
	SCR::Execute(pth, 0, 0);
    }
    else
    {
	// restore volume settings
        path pth = topath(sformat(".audio.alsa.cards.%1.restore", card_id));
        SCR::Execute(pth, 0, 0);
    }

    return $["ui": ui];

}

}//EOF
