+class NasalFPDelegate : public FlightPlan::Delegate
+{
+public:
+ NasalFPDelegate(FlightPlan* fp, FGNasalSys* sys, naRef ins) :
+ _nasal(sys),
+ _plan(fp),
+ _instance(ins)
+ {
+ SG_LOG(SG_NASAL, SG_INFO, "created Nasal delegate for " << fp);
+ _gcSaveKey = _nasal->gcSave(ins);
+ }
+
+ virtual ~NasalFPDelegate()
+ {
+ SG_LOG(SG_NASAL, SG_INFO, "destroying Nasal delegate for " << _plan);
+ _nasal->gcRelease(_gcSaveKey);
+ }
+
+ virtual void departureChanged()
+ {
+ callDelegateMethod("departureChanged");
+ }
+
+ virtual void arrivalChanged()
+ {
+ callDelegateMethod("arrivalChanged");
+ }
+
+ virtual void waypointsChanged()
+ {
+ callDelegateMethod("waypointsChanged");
+ }
+
+ virtual void currentWaypointChanged()
+ {
+ callDelegateMethod("currentWaypointChanged");
+ }
+
+ virtual void cleared()
+ {
+ callDelegateMethod("cleared");
+ }
+private:
+
+ void callDelegateMethod(const char* method)
+ {
+ naRef f;
+ naMember_cget(_nasal->context(), _instance, method, &f);
+ if (naIsNil(f)) {
+ return; // no method on the delegate
+ }
+
+ naRef arg[1];
+ arg[0] = ghostForFlightPlan(_nasal->context(), _plan);
+ _nasal->callMethod(f, _instance, 1, arg, naNil());
+ }
+
+ FGNasalSys* _nasal;
+ FlightPlan* _plan;
+ naRef _instance;
+ int _gcSaveKey;
+};
+
+class NasalFPDelegateFactory : public FlightPlan::DelegateFactory
+{
+public:
+ NasalFPDelegateFactory(naRef code)
+ {
+ _nasal = (FGNasalSys*) globals->get_subsystem("nasal");
+ _func = code;
+ _gcSaveKey = _nasal->gcSave(_func);
+ }
+
+ ~NasalFPDelegateFactory()
+ {
+ _nasal->gcRelease(_gcSaveKey);
+ }
+
+ virtual FlightPlan::Delegate* createFlightPlanDelegate(FlightPlan* fp)
+ {
+ naRef args[1];
+ args[0] = ghostForFlightPlan(_nasal->context(), fp);
+ naRef instance = _nasal->call(_func, 1, args, naNil());
+ if (naIsNil(instance)) {
+ return NULL;
+ }
+
+ return new NasalFPDelegate(fp, _nasal, instance);
+ }
+private:
+ FGNasalSys* _nasal;
+ naRef _func;
+ int _gcSaveKey;
+};
+
+static naRef f_registerFPDelegate(naContext c, naRef me, int argc, naRef* args)
+{
+ if ((argc < 1) || !naIsFunc(args[0])) {
+ naRuntimeError(c, "non-function argument to registerFlightPlanDelegate");
+ }
+
+ NasalFPDelegateFactory* factory = new NasalFPDelegateFactory(args[0]);
+ FlightPlan::registerDelegateFactory(factory);
+
+ return naNil();
+}
+
+static WayptRef wayptFromArg(naRef arg)
+{
+ WayptRef r = wayptGhost(arg);
+ if (r.valid()) {
+ return r;
+ }
+
+ FGPositioned* pos = positionedGhost(arg);
+ if (!pos) {
+ // let's check if the arg is hash, coudl extra a geod and hence build
+ // a simple waypoint
+
+ return WayptRef();
+ }
+
+// special-case for runways
+ if (pos->type() == FGPositioned::RUNWAY) {
+ return new RunwayWaypt((FGRunway*) pos, NULL);
+ }
+
+ return new NavaidWaypoint(pos, NULL);
+}
+
+static naRef convertWayptVecToNasal(naContext c, const WayptVec& wps)
+{
+ naRef result = naNewVector(c);
+ BOOST_FOREACH(WayptRef wpt, wps) {
+ naVec_append(result, ghostForWaypt(c, wpt.get()));
+ }
+ return result;
+}
+
+static naRef f_airwaySearch(naContext c, naRef me, int argc, naRef* args)
+{
+ if (argc < 2) {
+ naRuntimeError(c, "airwaysSearch needs at least two arguments");
+ }
+
+ WayptRef start = wayptFromArg(args[0]),
+ end = wayptFromArg(args[1]);
+
+ if (!start || !end) {
+ SG_LOG(SG_NASAL, SG_WARN, "airwaysSearch: start or end points are invalid");
+ return naNil();
+ }
+
+ bool highLevel = true;
+ if ((argc > 2) && naIsString(args[2])) {
+ if (!strcmp(naStr_data(args[2]), "lowlevel")) {
+ highLevel = false;
+ }
+ }
+
+ WayptVec route;
+ if (highLevel) {
+ Airway::highLevel()->route(start, end, route);
+ } else {
+ Airway::lowLevel()->route(start, end, route);
+ }
+
+ return convertWayptVecToNasal(c, route);
+}
+
+static naRef f_createWP(naContext c, naRef me, int argc, naRef* args)
+{
+ SGGeod pos;
+ int argOffset = geodFromArgs(args, 0, argc, pos);
+
+ if (((argc - argOffset) < 1) || !naIsString(args[argOffset])) {
+ naRuntimeError(c, "createWP: no identifier supplied");
+ }
+
+ std::string ident = naStr_data(args[argOffset++]);
+ WayptRef wpt = new BasicWaypt(pos, ident, NULL);
+
+// set waypt flags - approach, departure, pseudo, etc
+ if (argc > argOffset) {
+ WayptFlag f = wayptFlagFromString(naStr_data(args[argOffset++]));
+ wpt->setFlag(f);
+ }
+
+ return ghostForWaypt(c, wpt);
+}
+
+static naRef f_createWPFrom(naContext c, naRef me, int argc, naRef* args)
+{
+ if (argc < 1) {
+ naRuntimeError(c, "createWPFrom: need at least one argument");
+ }
+
+ FGPositioned* positioned = positionedGhost(args[0]);
+ if (!positioned) {
+ naRuntimeError(c, "createWPFrom: couldn;t convert arg[0] to FGPositioned");
+ }
+
+ WayptRef wpt;
+ if (positioned->type() == FGPositioned::RUNWAY) {
+ wpt = new RunwayWaypt((FGRunway*) positioned, NULL);
+ } else {
+ wpt = new NavaidWaypoint(positioned, NULL);
+ }
+
+ // set waypt flags - approach, departure, pseudo, etc
+ if (argc > 1) {
+ WayptFlag f = wayptFlagFromString(naStr_data(args[1]));
+ wpt->setFlag(f);
+ }
+
+ return ghostForWaypt(c, wpt);
+}
+