/**
 * File:	modules/PowerManagement.ycp
 * Package:	Configuration of power-management
 * Summary:	PowerManagement settings, input and output functions
 * Authors:	Jiri Srain <jsrain@suse.cz>
 *
 * $Id: PowerManagement.ycp 22751 2005-03-23 10:46:09Z jsrain $
 *
 * Representation of the configuration of power-management.
 * Input and output routines.
 */

{

module "PowerManagement";
textdomain "power-management";

import "Mode";
import "PackageSystem";
import "Progress";
import "Report";
import "Service";


/**
 * Mapping of cheme option identifiers in the internal structure and in the
 * created file
 * Key is internal structure, value is scheme file
 */
map<string,string> scheme_options_mapping = $[
    "SCHEME_NAME"		: "POWERSAVE_SCHEME_NAME",
    "SCHEME_DESCRIPTION"	: "POWERSAVE_SCHEME_DESCRIPTION",
    "CPUFREQUENCY"		: "POWERSAVE_CPUFREQUENCY",
    "ALLOW_THROTTLING"		: "POWERSAVE_ALLOW_THROTTLING",
    "MAX_THROTTLING"		: "POWERSAVE_MAX_THROTTLING",
    "ALWAYS_THROTTLE"		: "POWERSAVE_ALWAYS_THROTTLE",
    "DISK_STANDBY_MODE"		: "POWERSAVE_DISK_STANDBY_MODE",
    "DISK_ACOUSTIC"		: "POWERSAVE_DISK_ACOUSTIC",
    "COOLING_POLICY"		: "POWERSAVE_COOLING_POLICY",
//    "DISABLE_SCREEN_SAVER"	: "POWERSAVE_DISABLE_SCREEN_SAVER",
//    "DISABLE_DPMS"		: "POWERSAVE_DISABLE_DPMS",
//    "DPMS_STANDBY"		: "POWERSAVE_DPMS_STANDBY",
//    "DPMS_SUSPEND"		: "POWERSAVE_DPMS_SUSPEND",
//    "DPMS_OFF"			: "POWERSAVE_DPMS_OFF",
//    "" : "",
];

/**
 * Mapping of global option identifiers in the internal structure and in the
 * created file
 * Key is internal structure, value is scheme file (2-member list, first file
 * identifier, second variable name)
 */
map<string,list<string> > global_options_mapping = $[
    "AC_SCHEME"			: ["common",	 "POWERSAVE_AC_SCHEME"],
    "BATTERY_SCHEME"		: ["common",	 "POWERSAVE_BATTERY_SCHEME"],
    "BATTERY_WARNING"		: ["battery",	 "POWERSAVED_BATTERY_WARNING"],
    "BATTERY_LOW"		: ["battery",	 "POWERSAVED_BATTERY_LOW"],
    "BATTERY_CRITICAL"		: ["battery",	 "POWERSAVED_BATTERY_CRITICAL"],
    "EVENT_BATTERY_WARNING"	: ["events",	 "POWERSAVE_EVENT_BATTERY_WARNING"],
    "EVENT_BATTERY_LOW"		: ["events",	 "POWERSAVE_EVENT_BATTERY_LOW"],
    "EVENT_BATTERY_CRITICAL"	: ["events",	 "POWERSAVE_EVENT_BATTERY_CRITICAL"],
    "EVENT_BUTTON_POWER"	: ["events",	 "POWERSAVE_EVENT_BUTTON_POWER"],
    "EVENT_BUTTON_SLEEP"	: ["events",	 "POWERSAVE_EVENT_BUTTON_SLEEP"],
    "EVENT_BUTTON_LID_CLOSED"	: ["events",	 "POWERSAVE_EVENT_BUTTON_LID_CLOSED"],
    "DISABLE_USER_SUSPEND2DISK"	: ["sleep",	 "POWERSAVED_DISABLE_USER_SUSPEND2DISK"],
    "DISABLE_USER_SUSPEND2RAM"	: ["sleep",	 "POWERSAVED_DISABLE_USER_SUSPEND2RAM"],
    "DISABLE_USER_STANDBY"	: ["sleep",	 "POWERSAVED_DISABLE_USER_STANDBY"],
//    ""		: ["",	 ""],
];

/**
 * Was the settings modified?
 * @return boolean true if modified
 */
global boolean Modified();

// persistent variables

global list<map<string,string> > schemes = [];

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

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

string apm_acpi = "";

/* not needed any more, getting from kpowersave package
 global map scheme_names = $[
    // power saving scheme name, combo box and default contents of text entry
    "Performance" : _("Performance"),
    // power saving scheme name, combo box and default contents of text entry
    "Powersave" : _("Powersave"),
    // power saving scheme name, combo box and default contents of text entry
    "Acoustic" : _("Acoustic"),
    // power saving scheme name, combo box and default contents of text entry
    "Presentation" : _("Presentation"),
];

global map scheme_desciptions = $[
    "Scheme optimized to let machine run on maximum performance." :
	// pwer saving scheme description, contents of text entry
	_("Scheme optimized to let machine run on maximum performance."),
    "Scheme optimized to let maximum power savings take place." :
	// pwer saving scheme description, contents of text entry
	_("Scheme optimized to let maximum power savings take place."),
    "Scheme optimized to let machine run as quiet as possible." :
	// pwer saving scheme description, contents of text entry
	_("Scheme optimized to let machine run as quietly as possible."),
];*/

list<string> acpi_modes = nil;


/**
 * Data was modified?
 */
global boolean modified = false;

/**
 */
global boolean proposal_valid = false;

/**
 * Write only, used during autoinstallation.
 * Don't run services and SuSEconfig, it's all done at one place.
 */
global boolean write_only = false;

/**
 * Abort function
 * return boolean return true if abort
 */
global boolean() AbortFunction = nil;

// UI helping variables

global list<map<string,string> > current_schemes = [];
global integer current_scheme_index = -1;
global map<string,string> current_scheme = $[];


/**
 * Abort function
 * @return blah blah lahjk
 */
global define boolean Abort() ``{
    if(AbortFunction != nil)
	return AbortFunction ();
    return false;
}

/**
 * Data was modified?
 * @return true if modified
 */
global boolean Modified() {
    y2debug("modified=%1",modified);
    return modified;
}



/**
 * Read all power-management settings
 * @return true on success
 */
global boolean Read() {
    y2milestone ("Reading power management settings");
    if (Mode::config ())
	AbortFunction = nil;

    /* PowerManagement read dialog caption */
    string caption = _("Initializing Configuration");

    integer steps = 3;

    integer sl = 0;
    sleep(sl);

    boolean success = true;
    boolean stage_success = true;

    // We do not set help text here, because it was set outside
    Progress::New( caption, " ", steps, [
	    /* Progress stage 1/3 */
	    _("Check environment"),
	    /* Progress stage 2/3 */
	    _("Read general settings"),
	    /* Progress stage 3/3 */
	    _("Read power saving schemes"),
	], [
	    /* Progress step 1/3 */
	    _("Checking the environment..."),
	    /* Progress step 2/3 */
	    _("Reading general settings..."),
	    /* Progress step 3/3 */
	    _("Reading power saving schemes..."),
	    /* Progress finished */
	    _("Finished")
	],
	""
    );

    // read database
    if(Abort()) return false;
    Progress::NextStage();

    // check installed packages
    if (! Mode::test ()
	&& ! PackageSystem::CheckAndInstallPackagesInteractive (["powersave"])
    )
    {
	return false;
    }

    // check supported APM or ACPI
    map out = (map)SCR::Execute (.target.bash_output,
	"/usr/bin/powersave --apm-acpi");
    if (issubstring (out["stdout"]:"", "ACPI"))
	apm_acpi = "ACPI";
    else if (issubstring (out["stdout"]:"", "APM"))
	apm_acpi = "APM";
    else if (! Mode::config ())
    {
	// error report
	Report::Error (_("This system does not support ACPI or APM."));
	return false;
    }

    y2milestone ("Dected saving mehanism: %1", apm_acpi);

    if(! stage_success)
    {
	/* Error message */
	Report::Error(_("Cannot read the database1."));
    }
    success = success && stage_success;
    stage_success = true;
    sleep(sl);

    // read general settings
    if(Abort()) return false;
    Progress::NextStage();

    foreach (string key, list<string> conf, global_options_mapping, {
	string v = (string)SCR::Read (
	    .sysconfig.powersave.global.value + conf[0]:"" + conf[1]:"");
	global_settings[key] = v;
    });

    if(! stage_success)
    {
	/* Error message */
	Report::Error(_("Cannot read the general settings."));
    }
    success = success && stage_success;
    stage_success = true;
    sleep(sl);

    // read saving schemes
    if(Abort()) return false;
    Progress::NextStage();

    list<string> r_schemes = (list<string>)
	SCR::Dir (.sysconfig.powersave.schemes.section);
    schemes = maplist (string s, r_schemes, ``{
	map<string,string> scheme = $[
	    "_scheme_id" : s,
	];
	path p = add (.sysconfig.powersave.schemes.value, s);
	foreach (string key, string conf, scheme_options_mapping, {
	    string v = (string)SCR::Read (add (p, conf));
	    scheme[key] = v;
	});
	return scheme;
    });
    new_schemes = $[];

    if(! stage_success)
    {
	/* Error message */
	Report::Warning(_("Cannot read power saving schemes."));
    }
    sleep(sl);

    /* Progress finished */
    Progress::NextStage();
    success = success && stage_success;
    sleep(sl);

    modified = false;

    y2debug ("Global settings: %1", global_settings);
    y2debug ("Power saving schemes: %1", schemes);

    return success;
}

/**
 * Write all power-management settings
 * @return true on success
 */
global boolean Write() {
    y2milestone ("Writing power management settings");
    if (Mode::autoinst ())
	AbortFunction = nil;

    /* PowerManagement read dialog caption */
    string caption = _("Saving Configuration");

    integer steps = 3;

    integer sl = 0;
    sleep(sl);

    boolean success = true;
    boolean stage_success = true;

    // We do not set help text here, because it was set outside
    Progress::New(caption, " ", steps, [
	    /* Progress stage 1/3 */
	    _("Write schemes"),
	    /* Progress stage 2/3 */
	    _("Write general settings"),
	    /* Progress stage 3/3 */
	    _("Restart powersave daemon")
	], [
	    /* Progress step 1/3 */
	    _("Writing schemes..."),
	    /* Progress step 2/3 */
	    _("Writing general settings..."),
	    /* Progress step 3/3 */
	    _("Restarting powersave daemon..."),
	    /* Progress finished */
	    _("Finished")
	],
	""
    );

    // write schemes
    if(Abort()) return false;
    Progress::NextStage();

    y2milestone ("Writing power saving schemes");
    // copy new scheme files
    foreach (string dst, string src, new_schemes, ``{
	if (dst != "")
	{
	    y2milestone ("Creating config file of scheme %1 as copy of %2",
		dst, src);
	    stage_success = (0 == SCR::Execute (.target.bash, sformat (
		"cat /etc/sysconfig/powersave/scheme_%1 | awk '
/^## Path:.*$/ { printf (\"## Path: System/Powermanagement/Scheme/%2\\n\");
next }
// {print $0;}' >  /etc/sysconfig/powersave/scheme_%2",
		src, dst))) && stage_success;
	}
    });

    // remove deleted schemes
    list<string> old = (list<string>)SCR::Dir (.sysconfig.powersave.schemes.section);
    list<string> current = maplist (map<string,string> s, schemes, ``(
	s["_scheme_id"]:""
    ));
    list<string> delete = filter (string s, old, ``(! contains (current, s)));
    foreach (string s, delete, ``{
	SCR::Write (add (.sysconfig.powersave.schemes.section, s), nil);
    });

    // write scheme settings
    foreach (map<string,string> scheme, schemes, ``{
	string id = scheme["_scheme_id"]:"";
	y2milestone ("Writing scheme %1", id);
	path p = add (.sysconfig.powersave.schemes.value, id);
	foreach (string key, string conf, scheme_options_mapping, {
	    if (key != "_scheme_id")
	    {
		string v = scheme[key]:nil;
		SCR::Write (add (p, conf), v);
	    }
	});
    });
    SCR::Write (.sysconfig.powersave.schemes, nil);

    if(! stage_success)
    {
	/* Error message */
	Report::Error(_("Cannot write power saving schemes."));
    }
    success = success && stage_success;
    stage_success = true;
    sleep(sl);

    // write global settings
    if(Abort()) return false;
    Progress::NextStage ();

    y2milestone ("Writing global settings");
    foreach (string key, list<string> conf, global_options_mapping, {
	string v = global_settings[key]:nil;
	SCR::Write (
	    .sysconfig.powersave.global.value + conf[0]:"" + conf[1]:"", v);
    });
    SCR::Write (.sysconfig.powersave.global, nil);

    if(! stage_success)
    {
	/* Error message */
	Report::Error(_("Cannot write general settings."));
    }
    success = success && stage_success;
    stage_success = true;
    sleep(sl);

    // restart daemon
    if(Abort()) return false;
    Progress::NextStage ();

    y2milestone ("Restarting powersave daemon");
    stage_success = Service::Restart ("powersaved");
    stage_success = Service::Enable ("powersaved") && stage_success;

    if(! stage_success)
    {
	/* Error message */
	Report::Error(_("Cannot restart the powersave daemon."));
    }
    success = success && stage_success;
    stage_success = true;
    sleep(sl);

    /* Progress finished */
    Progress::NextStage();
    sleep(sl);
    sleep (500);

    return true;
}

/**
 * Get all power-management settings from the first parameter
 * (For use by autoinstallation.)
 * @param settings The YCP structure to be imported.
 * @return boolean True on success
 */
global boolean Import (map settings) {
    y2milestone ("Importing settings: %1", settings);
    schemes = settings["schemes"]:[];
    global_settings = settings["global_settings"]:$[];
    return true;
}

/**
 * Dump the power-management settings to a single map
 * (For use by autoinstallation.)
 * @return map Dumped settings (later acceptable by Import ())
 */
global map Export () {
    map<string,any> ret = $[
	"schemes" : schemes,
	"global_settings" : global_settings,
    ];
    y2milestone ("Exporting settings: %1", ret);
    return ret;
}

/**
 * Create a textual summary and a list of unconfigured cards
 * @return summary of the current configuration
 */
global list<string> Summary() {
    string ac_scheme = "";
    string bat_scheme = "";

    string scheme = PowerManagement::global_settings["AC_SCHEME"]:"";
    if (scheme == "")
	scheme = "performance";

    foreach (map<string,string> s, schemes, ``{
	if (s["_scheme_id"]:"" == scheme)
	    ac_scheme = s["SCHEME_DESCRIPTION"]:"";
    });
    if (ac_scheme == "")
	ac_scheme = scheme;

    scheme = PowerManagement::global_settings["BATTERY_SCHEME"]:"";
    if (scheme == "")
        scheme = "performance";
    foreach (map<string,string> s, schemes, ``{
	if (s["_scheme_id"]:"" == scheme)
	    bat_scheme = s["SCHEME_DESCRIPTION"]:"";
    });
    if (bat_scheme == "")
	bat_scheme = scheme;

    list<string> ret = [
	// summary text, %1 is scheme name
	sformat (_("AC Scheme: %1"), ac_scheme),
	// summary text, %1 is scheme name
	sformat (_("Battery Scheme: %1"), bat_scheme),
    ];
    y2milestone ("Power management summary: %1", ret);

    return ret;
}

/**
 * Return packages needed to be installed and removed during
 * Autoinstallation to insure module has all needed software
 * installed.
 * @return map with 2 lists.
 */
global map AutoPackages() {
    return $[ "install":["powersave"], "remove":[] ];
}

/**
 * List all supported ACPI modes
 * @return a list containing all supported ACPI modes
 */
global list<string> ACPIModes () {
    if (acpi_modes == nil)
    {
	string modes = (string)SCR::Read (.target.string, "/proc/acpi/sleep");
	list<string> spl = splitstring (modes, " \t");
	spl = filter (string s, spl, {return s != "" && s != "\n";});
	acpi_modes = spl;
    }
    return acpi_modes;
}

/**
 * Check if ACPI is being used
 * @return boolean true if ACPI is being used
 */
global boolean ACPI () {
    return tolower (apm_acpi) == "acpi";
}

/**
 * Check if APM is being used
 * @return boolean true if APM is being used
 */
global boolean APM () {
    return tolower (apm_acpi) == "apm";
}

/**
 * Translate a text using powersave mo-file
 * @param text string to translate
 * @return string translated text
 */
global string TranslatePowersaveText (string text) {
    map out = (map)SCR::Execute (.target.bash_output, sformat (
	"TEXTDOMAINDIR=/usr/share/locale/ gettext power-management \"%1\"",
	text));
    if (out["exit"]:-1 != 0)
    {
	return text;
    }
    string translated = out["stdout"]:"";
    return translated;
}

/**
 * Get localized scheme name
 * @param name string original scheme name
 * @return string localized scheme name
 */
global string TranslateSchemeName (string name) {
    return TranslatePowersaveText (name);
}

/**
 * Get localized scheme description
 * @param descr string original scheme desceriptino
 * @return string localized scheme decription
 */
global string TranslateSchemeDescription (string descr) {
    return TranslatePowersaveText (descr);
}

/**
 * Find index of a scheme
 * @param name string scheme name
 * @return integer scheme index (-1 if not found)
 */
global integer FindScheme (string name) {
    integer ret = -1;
    integer index = -1;
    foreach (map<string,string> s, schemes, {
	index = index + 1;
	if (s["SCHEME_NAME"]:"" == name)
	{
	    ret = index;
	}
    });
    return ret;
}

/**
 * Fetch all schemes
 */
global void FetchSchemes () {
    current_schemes = schemes;
}

/**
 * Store all schemes
 */
global void StoreSchemes () {
    schemes = current_schemes;
    modified = true;
}

/**
 * fetch a scheme
 * @param index integer index of the scheme (-1 is new scheme)
 * @param clone integer index of scheme to clone if not exists
 */
global void FetchScheme (integer index, integer clone) {
    current_scheme_index = index;
    if (index == -1)
    {
	if (clone != nil)
	{
	    current_scheme = current_schemes[clone]:$[];

	}
	else
	{
	    current_scheme = current_schemes[0]:$[];
	}
    }
    else
    {
	current_scheme = current_schemes[index]:$[];
    }
    if (current_scheme == $[])
    {
	current_scheme = current_schemes[0]:$[];
    }
}

/**
 * Store the current scheme
 */
global void StoreScheme () {
    if (current_scheme_index == -1)
    {
	current_schemes = add (current_schemes, current_scheme);
    }
    else
    {
	current_schemes[current_scheme_index] = current_scheme;
    }
}

/* EOF */
}
