/**
 * File:	modules/AutoinstScripts.ycp
 * Module:	Auto-Installation
 * Summary:	Custom scripts
 * Authors:	Anas Nashif <nashif@suse.de>
 *
 * $Id: AutoinstScripts.ycp 21739 2005-02-20 21:43:45Z nashif $
 */

{
    module "AutoinstScripts";
    textdomain "autoinst";

    import "Mode";
    import "AutoinstConfig";
    import "Summary";
    import "URL";
    import "Service";

    include "autoinstall/io.ycp";

    /* Pre scripts */
    global list<map> pre = [];

    /* Post scripts */
    global list<map> post = [];

    /* Chroot scripts */
    global list<map> chroot = [];

    /* Init scripts */
    global list<map> init = [];

    /* Merged scripts */
    global list<map> merged = [];

    /* default value of settings modified */
    global boolean modified = false;

    /**
     * Function sets internal variable, which indicates, that any
     * settings were modified, to "true"
     */
    global define void SetModified ()
    {
        modified = true;
    }

    /**
     * Functions which returns if the settings were modified
     * @return boolean  settings were modified
     */
    global define boolean GetModified ()
    {
        return modified;
    }


    /**
     * merge all types of scripts into one single list
     * @param -
     * @return merged list
     */
    list<map> mergeScripts ()
    {

	list<map> result = maplist (map p, pre,
				 ``{
				     p = add(p,"type","pre-scripts");
				     return p;
				 });
	result = (list<map>)union(result,	maplist (map p, post,
					 ``{
					     p = add(p,"type","post-scripts");
					     return p;
					 })
		       );
	result = (list<map>)union(result,	maplist (map p, chroot,
					 ``{
					     p = add(p,"type","chroot-scripts");
					     return p;
					 })
		       );
	result = (list<map>)union(result,	maplist (map p, init,
					 ``{
					     p = add(p,"type","init-scripts");
					     return p;
					 })
		       );
	return result;
    }


    /**
     * Constructor
     */
    define void AutoinstScripts()
    {
	if ( !Mode::autoinst () )
	{
	    merged = mergeScripts();
	}
    }


    /**
     * Dump the settings to a map, for autoinstallation use.
     * @return map
     */
    global define map<string, list> Export()
    {
	pre = [];
	post = [];
	chroot = [];
	init = [];
	y2milestone("Merged %1", merged);

	// split
	foreach(map s, merged, ``{
	    if (s["type"]:"" == "pre-scripts")
		pre = add(pre,s);
	    else if (s["type"]:"" == "post-scripts")
		post = add(post,s);
	    else if (s["type"]:"" == "init-scripts")
		init = add(init,s);
	    else if (s["type"]:"" == "chroot-scripts")
		chroot = add(chroot,s);
	});


	// clean
	list<map> expre =  maplist (map p, pre,  ``{
	    return ($["filename":p["filename"]:"",
		      "interpreter": p["interpreter"]:"",
		      "source":p["source"]:"",
                      "location":p["location"]:""
		    ]);
	});
	list<map> expost =  maplist (map p, post, ``{
	    return ($["filename":p["filename"]:"",
		      "interpreter": p["interpreter"]:"",
		      "source":p["source"]:"",
                      "location":p["location"]:""
                      ]
		    );
	});
	list<map> exchroot =  maplist (map p, chroot, ``{
	    return ($["filename":p["filename"]:"",
		      "interpreter": p["interpreter"]:"",
		      "source":p["source"]:"",
		      "chrooted":p["chrooted"]:false,
                      "location":p["location"]:""
		    ]);
	});
	list<map> exinit =  maplist (map p, init, ``{
	    return ($["filename":p["filename"]:"",
		      "source":p["source"]:"",
                      "location":p["location"]:""
		    ]);
	});
	map<string, list> result = $[];
	if (size(expre) > 0 )
	    result["pre-scripts"] = expre;
	if (size(expost) > 0 )
	    result["post-scripts"] = expost;
	if (size(exchroot) > 0 )
	    result["chroot-scripts"] = exchroot;
	if (size(exinit) > 0 )
	    result["init-scripts"] = exinit;

	return result;

    }


    /**
     * Get all the configuration from a map.
     * When called by autoinst_<module name> (preparing autoinstallation data)
     * the map may be empty.
     * @param settings	$[...]
     * @return	success
     */
    global define boolean Import(map s)
    {
        y2debug("Calling AutoinstScripts::Import()");
	pre = s["pre-scripts"]:[];
	init = s["init-scripts"]:[];
	post = s["post-scripts"]:[];
	chroot = s["chroot-scripts"]:[];
	merged = mergeScripts();
        y2debug("merged: %1", merged);
	return true;
    }

    /**
     * Return Summary
     * @return string summary
     */
    global define string Summary()
    {
	string summary = "";
	summary = Summary::AddHeader(summary, _("Preinstallation Scripts"));
	if (size( pre) > 0 )
	{
	    summary = Summary::OpenList(summary);
	    foreach(map script, pre, ``{
		summary = Summary::AddListItem(summary, script["filename"]:"" );
	    });
	    summary = Summary::CloseList(summary);
	}
	else
	{
	    summary = Summary::AddLine(summary, Summary::NotConfigured());
	}
	summary = Summary::AddHeader(summary, _("Postinstallation Scripts"));
	if (size( post) > 0)
	{
	    summary = Summary::OpenList(summary);
	    foreach(map script, post, ``{
		summary = Summary::AddListItem(summary, script["filename"]:"" );
	    });
	    summary = Summary::CloseList(summary);
	}
	else
	{
	    summary = Summary::AddLine(summary, Summary::NotConfigured());
	}
	summary = Summary::AddHeader(summary, _("Chroot Scripts"));
	if (size( chroot) > 0 )
	{
	    summary = Summary::OpenList(summary);
	    foreach(map script, chroot, ``{
		summary = Summary::AddListItem(summary, script["filename"]:"" );
	    });
	    summary = Summary::CloseList(summary);
	}
	else
	{
	    summary = Summary::AddLine(summary, Summary::NotConfigured());
	}
	summary = Summary::AddHeader(summary, _("Init Scripts"));
	if (size( init) > 0 )
	{
	    summary = Summary::OpenList(summary);
	    foreach(map script, init, ``{
		summary = Summary::AddListItem(summary, script["filename"]:"" );
	    });
	    summary = Summary::CloseList(summary);
	}
	else
	{
	    summary = Summary::AddLine(summary, Summary::NotConfigured());
	}
	return summary;
    }

    /**
     * delete a script from a list
     * @param script name
     * @return void
     */
    global define void  deleteScript(string scriptName)
    {
	list<map> clean = filter(map s, merged, ``(s["filename"]:"" != scriptName));
	merged = clean;
	return;
    }

    /**
     * Add or edit a script
     * @param scriptName script name
     * @param source source of script
     * @param interpreter interpreter to be used with script
     * @param type type of script
     * @return void
     */
    global define void AddEditScript(string scriptName,
            string source,
            string interpreter,
            string type)
    {
	boolean mod = false;
	merged = maplist (map script , merged, ``{
	    // Edit
	    if (script["filename"]:"" == scriptName)
	    {
		map oldScript = $[];
		oldScript=add(oldScript,"filename", scriptName);
		oldScript=add(oldScript,"source", source);
		oldScript=add(oldScript,"interpreter", interpreter);
		oldScript=add(oldScript,"type", type);
		mod = true;
		return oldScript;
	    }
	    else {
		return script;
	    }
	});

	if (!mod)
	{
	    map script = $[];
	    script=add(script,"filename", scriptName);
	    script=add(script,"source", source);
	    script=add(script,"interpreter", interpreter);
	    script=add(script,"type", type);

	    merged=add(merged,script);
	}
        y2debug("Merged scripts: %1", merged);
	return;
    }


    /**
     * return type of script as formatted string
     * @param script type
     * @return string type as translated string
     */
    global define string typeString(string type)
    {
	if (type == "pre-scripts")
	{
	    return _("Pre");
	}
	else if (type == "post-scripts")
	{
	    return _("Post");
	}
	else if (type == "init-scripts")
	{
	    return _("Init");
	}
	else if (type == "chroot-scripts")
	{
	    return _("Chroot");
	}
	return _("Unknown");
    }



    /**
     * Execute pre scripts
     * @param string type of script
     * @param boolean if script should be executed in chroot env.
     * @return boolean true on success
     */
    global define boolean Write( string type , boolean special)
    {
        if (!Mode::autoinst ())
            return true;

	list<map> scripts = [];
	if (type == "pre-scripts")
	{
	    scripts = pre;
	}
        else if (type == "init-scripts")
	{
	    scripts = init;
	}
	else if ( type == "chroot-scripts" && !special)
	{
	    scripts = filter(map s, chroot, ``(!s["chrooted"]:false));
	}
	else if ( type == "chroot-scripts" && special)
	{
	    scripts = filter(map s, chroot, ``(s["chrooted"]:false));
	}
	else if (type == "post-scripts" && !special)
	{
	    scripts = filter(map s, post, ``(!s["network_needed"]:false));
	}
	else if (type == "post-scripts" && special)
	{
	    scripts = filter(map s, post, ``(s["network_needed"]:false));
	}
	else
	{
	    y2error("Unsupported script type");
	    return false;
	}


	string tmpdirString = "";
	string current_logdir = "";

	if (type == "pre-scripts")
	{
	    tmpdirString = sformat("%1/%2", AutoinstConfig::tmpDir, type);
	    SCR::Execute (.target.mkdir, tmpdirString);

	    current_logdir = sformat("%1/logs", tmpdirString);
	    SCR::Execute (.target.mkdir,  current_logdir);
	}
	else if (type == "chroot-scripts")
	{
	    tmpdirString = sformat("%1%2", (special) ? "" : AutoinstConfig::destdir,  AutoinstConfig::scripts_dir);
	    SCR::Execute (.target.mkdir, (special) ? AutoinstConfig::scripts_dir : tmpdirString);

	    current_logdir = sformat("%1%2", (special) ? "" : AutoinstConfig::destdir, AutoinstConfig::logs_dir);
	    SCR::Execute (.target.mkdir,  (special) ? AutoinstConfig::logs_dir : current_logdir);
	}
	else
	{
	    current_logdir = AutoinstConfig::logs_dir;
	}


	foreach( map s, scripts,
		 ``{
	    string scriptInterpreter	= s["interpreter"]:"shell";
	    string scriptName = s["filename"]:type;
            if (scriptName=="")
            {
                map t = URL::Parse(s["location"]:"");
                scriptName=basename(t["path"]:"");
            }
	    string scriptPath = "";

	    if (type == "pre-scripts")
	    {
		scriptPath = sformat("%1/%2/%3", AutoinstConfig::tmpDir, type, scriptName);
		y2milestone("Writing pre script into %1", scriptPath);
                if (s["location"]:"" != "")
                {
                    y2debug("getting script: %1", s["location"]:"" );
                    if (!GetURL(s["location"]:"", scriptPath ) )
                    {
                       y2error("script %1 could not be retrieved", s["location"]:"");
                    }
                } else {
	            SCR::Write(.target.string,  scriptPath, s["source"]:"echo Empty script!");
                }
	    }
            else if (type == "init-scripts")
	    {
		scriptPath = sformat("%1/%2",  AutoinstConfig::initscripts_dir,  scriptName);
		y2milestone("Writing init script into %1", scriptPath);
                if (s["location"]:""!="")
                {
                    y2debug("getting script: %1", s["location"]:"" );
                    if (!GetURL(s["location"]:"", scriptPath ) )
                    {
                       y2error("script %1 could not be retrieved", s["location"]:"");
                    }
                } else {
	            SCR::Write(.target.string,  scriptPath, s["source"]:"echo Empty script!");
                }
                Service::Enable("autoyast");
	    }
	    else if (type == "chroot-scripts")
	    {
		scriptPath = sformat("%1%2/%3", (special) ? "" : AutoinstConfig::destdir,  AutoinstConfig::scripts_dir,  scriptName);
		y2milestone("Writing chroot script into %1", scriptPath);
                if (s["location"]:""!="")
                {
                    if (!GetURL(s["location"]:"", scriptPath ) )
                    {
                       y2error("script %1 could not be retrieved", s["location"]:"");
                    }
                } else {
	            SCR::Write(.target.string,  scriptPath, s["source"]:"echo Empty script!");
                }
	    }
	    else
	    {
		// disable all sources and finish target
		Pkg::SourceFinishAll();
		Pkg::TargetFinish();

		scriptPath = sformat("%1/%2", AutoinstConfig::scripts_dir, scriptName);
		y2milestone("Writing  script into %1", scriptPath);
                if (s["location"]:""!="")
                {
                    if (!GetURL(s["location"]:"", scriptPath ) )
                    {
                       y2error("script %1 could not be retrieved", s["location"]:"");
                    }
                } else {
	            SCR::Write(.target.string,  scriptPath, s["source"]:"echo Empty script!");
                }
	    }

            if (type != "init-scripts")
            {
                // string message =  sformat(_("Executing user supplied script: %1"), scriptName);
                string executionString = "";
                if (scriptInterpreter == "shell")
                {
                    executionString = sformat("/bin/sh -x %1  2&> %2/%3.log", scriptPath, current_logdir, scriptName);
                    SCR::Execute (.target.bash, executionString);
                }
                else if (scriptInterpreter == "perl")
                {
                    executionString = sformat("/usr/bin/perl %1  2&> %2/%3.log", scriptPath, current_logdir, scriptName);
                    SCR::Execute (.target.bash,executionString);
                }
                else if (scriptInterpreter == "python")
                {
                    executionString = sformat("/usr/bin/python %1  2&> %2/%3.log", scriptPath, current_logdir, scriptName);
                    SCR::Execute (.target.bash,executionString);
                }
                else
                {
                    y2error("Unknown interpreter: %1", scriptInterpreter);
                }
                y2milestone("Script Execution command: %1", executionString );
            }
	});

	return true;
    }


// EOF
}
