/*****
* runsystem.in
*
* Runtime functions for system operations.
*
*****/

callable* => voidFunction()
callableBp* => breakpointFunction()
runnable* => primCode()

#include "asyprocess.h"
#include "stack.h"
#include "locate.h"

using namespace camp;
using namespace settings;
using vm::bpinfo;
using vm::bplist;
using vm::getPos;
using vm::Default;
using vm::nullfunc;
using vm::item;
using absyntax::runnable;

typedef callable callableBp;

namespace run {
extern string emptystring;
}

function *voidFunction()
{
 return new function(primVoid());
}

function *breakpointFunction()
{
 return new function(primString(),primString(),primInt(),primInt(),
                     primCode());
}

void clear(string file, Int line, bool warn=false)
{
 bpinfo bp(file,line);
 for(mem::list<bpinfo>::iterator p=bplist.begin(); p != bplist.end(); ++p) {
   if(*p == bp) {
     cout << "cleared breakpoint at " << file << ": " << line << endl;
     bplist.remove(bp);
     return;
   }
 }
 if(warn)
   cout << "No such breakpoint at "  << file << ": " << line << endl;
}

namespace run {
void breakpoint(stack *Stack, runnable *r)
{
 callable *atBreakpointFunction=processData().atBreakpointFunction;
 if(atBreakpointFunction &&
    !nullfunc::instance()->compare(atBreakpointFunction)) {
   position curPos=getPos();
   Stack->push<string>(curPos.filename());
   Stack->push<Int>((Int) curPos.Line());
   Stack->push<Int>((Int) curPos.Column());
   Stack->push(r ? r : vm::Default);
   atBreakpointFunction->call(Stack); // returns a string
 } else Stack->push<string>("");
}
}

string convertname(string name, const string& format)
{
 if(name.empty())
   return buildname(outname(),format,"");
 name=outpath(name);
 return format.empty() ? name : format+":"+name;
}

namespace run {
void purge(Int divisor=0)
{
#ifdef USEGC
 if(divisor > 0) GC_set_free_space_divisor((GC_word) divisor);
 GC_gcollect();
#endif
}

void updateFunction(stack *Stack)
{
 callable *atUpdateFunction=processData().atUpdateFunction;
 if(atUpdateFunction && !nullfunc::instance()->compare(atUpdateFunction))
   atUpdateFunction->call(Stack);
}

void exitFunction(stack *Stack)
{
 callable *atExitFunction=processData().atExitFunction;
 if(atExitFunction && !nullfunc::instance()->compare(atExitFunction))
   atExitFunction->call(Stack);
}
}

// Autogenerated routines:

string outname()
{
 return outname();
}

void atupdate(callable *f)
{
 processData().atUpdateFunction=f;
}

callable *atupdate()
{
 return processData().atUpdateFunction;
}

void atexit(callable *f)
{
 processData().atExitFunction=f;
}

callable *atexit()
{
 return processData().atExitFunction;
}

void atbreakpoint(callableBp *f)
{
 processData().atBreakpointFunction=f;
}

void breakpoint(runnable *s=NULL)
{
 breakpoint(Stack,s);
}

string locatefile(string file, bool full=true)
{
 return locateFile(file,full);
}

void stop(string file, Int line, runnable *s=NULL)
{
 file=locateFile(file);
 clear(file,line);
 cout << "setting breakpoint at " << file << ": " << line << endl;
 bplist.push_back(bpinfo(file,line,s));
}

void breakpoints()
{
 for(mem::list<bpinfo>::iterator p=bplist.begin(); p != bplist.end(); ++p)
   cout << p->f.name() << ": " << p->f.line() << endl;
}

void clear(string file, Int line)
{
 file=locateFile(file);
 clear(file,line,true);
}

void clear()
{
 bplist.clear();
}

void warn(string s)
{
 Warn(s);
}

void nowarn(string s)
{
 noWarn(s);
}

void warning(string s, string t, bool position=false)
{
 if(settings::warn(s)) {
   em.warning(position ? getPos() : nullPos,s);
   em << t;
   em.sync(true);
 }
}

// Strip directory from string
string stripdirectory(string *s)
{
 return stripDir(*s);
}

// Strip directory from string
string stripfile(string *s)
{
 return stripFile(*s);
}

// Strip file extension from string
string stripextension(string *s)
{
 return stripExt(*s);
}

// Call ImageMagick convert.
Int convert(string args=emptystring, string file=emptystring,
           string format=emptystring)
{
 string name=convertname(file,format);
 mem::vector<string> cmd;
 string s=getSetting<string>("convert");
 cmd.push_back(s);
 push_split(cmd,args);
 cmd.push_back(name);
 bool quiet=verbose <= 1;

 char *oldPath=NULL;
 string dir=stripFile(outname());
 if(!dir.empty()) {
   oldPath=getPath();
   setPath(dir.c_str());
 }
 Int ret=System(cmd,quiet ? 1 : 0,true,"convert",
                "your ImageMagick convert utility");
 if(oldPath != NULL)
   setPath(oldPath);

 if(ret == 0 && verbose > 0)
   cout << "Wrote " << (file.empty() ? name : file) << endl;

 return ret;
}

// Call ImageMagick animate.
Int animate(string args=emptystring, string file=emptystring,
           string format=emptystring)
{
 string name=convertname(file,format);
 if(view()) {
   mem::vector<string> cmd;
   string s=getSetting<string>("animate");
   cmd.push_back(s);
   if(s == "magick")
     cmd.push_back("animate");
   push_split(cmd,args);
   cmd.push_back(name);
   return System(cmd,0,false,"animate","your animated GIF viewer");
 }
 return 0;
}

void purge(Int divisor=0)
{
 purge(divisor);
}