Index: trunk/FACT++/src/InterpreterV8.cc
===================================================================
--- trunk/FACT++/src/InterpreterV8.cc	(revision 14688)
+++ trunk/FACT++/src/InterpreterV8.cc	(revision 14689)
@@ -10,4 +10,5 @@
 
 #ifdef HAVE_NOVA
+#include <libnova/solar.h>
 #include <libnova/lunar.h>
 #include <libnova/transform.h>
@@ -1517,4 +1518,109 @@
     return handle_scope.Close(self);
 }
+
+Handle<Object> InterpreterV8::ConstructRiseSet(const Handle<Value> time, const ln_rst_time &rst)
+{
+    Handle<Object> obj = Object::New();
+    obj->Set(String::New("time"), time, ReadOnly);
+    if (rst.transit<0)
+        return obj;
+
+    Handle<Value> rise  = Date::New(Time(rst.rise).JavaDate());
+    Handle<Value> set   = Date::New(Time(rst.set).JavaDate());
+    Handle<Value> trans = Date::New(Time(rst.transit).JavaDate());
+    if (rise.IsEmpty() || set.IsEmpty() || trans.IsEmpty())
+        return Handle<Object>();
+
+    obj->Set(String::New("rise"), rise, ReadOnly);
+    obj->Set(String::New("set"),  set, ReadOnly);
+    obj->Set(String::New("transit"), trans, ReadOnly);
+    return obj;
+}
+
+Handle<Value> InterpreterV8::SunHorizon(const Arguments &args)
+{
+    if (args.Length()>2)
+        return ThrowException(String::New("Sun.horizon must not be called with one or two arguments."));
+
+    HandleScope handle_scope;
+
+    double hrz = NAN;
+    if (args.Length()<2)
+        hrz = LN_SOLAR_STANDART_HORIZON;
+    if (args.Length()==2 && args[1]->IsNumber())
+        hrz = args[1]->NumberValue();
+    if (args.Length()==2 && args[1]->IsString())
+    {
+        char *arg = *String::AsciiValue(args[1]);
+        transform(arg, arg+strlen(arg), arg, ::tolower);
+
+        const string str = Tools::Trim(arg);
+        if (str==string("civil").substr(0, str.length()))
+            hrz = LN_SOLAR_CIVIL_HORIZON;
+        if (str==string("nautic").substr(0, str.length()))
+            hrz = LN_SOLAR_NAUTIC_HORIZON;
+        if (str==string("astronomical").substr(0, str.length()))
+            hrz = LN_SOLAR_ASTRONOMICAL_HORIZON;
+    }
+
+    if (!finite(hrz))
+        return ThrowException(String::New("Second argument did not yield a valid number."));
+
+    const Local<Value> date =
+        args.Length()==0 ? Date::New(Time().JavaDate()) : args[0];
+    if (date.IsEmpty())
+        return Undefined();
+
+    const uint64_t v = uint64_t(date->NumberValue());
+    const Time utc(v/1000, v%1000);
+
+    ln_lnlat_posn obs;
+    obs.lng = -(17.+53./60+26.525/3600);
+    obs.lat =   28.+45./60+42.462/3600;
+
+    // get Julian day from local time
+    const double JD = utc.JD();
+
+    ln_rst_time sun;
+    const bool rc = ln_get_solar_rst_horizon(JD-0.5, &obs, hrz, &sun);
+    if (rc)
+        sun.transit = -1;
+
+    Handle<Object> rst = ConstructRiseSet(date, sun);
+    rst->Set(String::New("horizon"), Number::New(hrz));
+    return handle_scope.Close(rst);
+};
+
+Handle<Value> InterpreterV8::MoonHorizon(const Arguments &args)
+{
+    if (args.Length()>1)
+        return ThrowException(String::New("Moon.horizon must not be called with one argument."));
+
+    HandleScope handle_scope;
+
+    const Local<Value> date =
+        args.Length()==0 ? Date::New(Time().JavaDate()) : args[0];
+    if (date.IsEmpty())
+        return Undefined();
+
+    const uint64_t v = uint64_t(date->NumberValue());
+    const Time utc(v/1000, v%1000);
+
+    ln_lnlat_posn obs;
+    obs.lng = -(17.+53./60+26.525/3600);
+    obs.lat =   28.+45./60+42.462/3600;
+
+    // get Julian day from local time
+    const double JD = utc.JD();
+
+    ln_rst_time moon;
+    const bool rc = ln_get_lunar_rst(JD-0.5, &obs, &moon);
+
+    if (rc)
+        moon.transit = -1;
+
+    Handle<Object> rst = ConstructRiseSet(date, moon);
+    return handle_scope.Close(rst);
+};
 #endif
 
@@ -1792,7 +1898,7 @@
 
     Handle<ObjectTemplate> dimctrl = ObjectTemplate::New();
-    dimctrl->Set(String::New("newState"),  FunctionTemplate::New(WrapNewState),  ReadOnly);
-    dimctrl->Set(String::New("setState"),  FunctionTemplate::New(WrapSetState),  ReadOnly);
-    dimctrl->Set(String::New("getState"),  FunctionTemplate::New(WrapGetState),  ReadOnly);
+    dimctrl->Set(String::New("defineState"), FunctionTemplate::New(WrapNewState),  ReadOnly);
+    dimctrl->Set(String::New("setState"),    FunctionTemplate::New(WrapSetState),  ReadOnly);
+    dimctrl->Set(String::New("getState"),    FunctionTemplate::New(WrapGetState),  ReadOnly);
 
     Handle<ObjectTemplate> v8 = ObjectTemplate::New();
@@ -1852,5 +1958,11 @@
     moon->SetClassName(String::New("Moon"));
     moon->Set(String::New("disk"), FunctionTemplate::New(MoonDisk), ReadOnly);
+    moon->Set(String::New("horizon"), FunctionTemplate::New(MoonHorizon), ReadOnly);
     global->Set(String::New("Moon"), moon, ReadOnly);
+
+    Handle<FunctionTemplate> sun = FunctionTemplate::New();
+    sun->SetClassName(String::New("Sun"));
+    sun->Set(String::New("horizon"), FunctionTemplate::New(SunHorizon), ReadOnly);
+    global->Set(String::New("Sun"), sun, ReadOnly);
 
     fTemplateLocal = loc;
Index: trunk/FACT++/src/InterpreterV8.h
===================================================================
--- trunk/FACT++/src/InterpreterV8.h	(revision 14688)
+++ trunk/FACT++/src/InterpreterV8.h	(revision 14689)
@@ -17,4 +17,8 @@
 
 class Database;
+
+#ifdef HAVE_NOVA
+struct ln_rst_time;
+#endif
 
 class InterpreterV8
@@ -83,6 +87,8 @@
     v8::Handle<v8::Value> OnChangeSet(v8::Local<v8::String>, v8::Local<v8::Value>, const v8::AccessorInfo &);
 
+    static v8::Handle<v8::Value> Constructor(const v8::Arguments &args);
+
+#ifdef HAVE_NOVA
     static double GetDataMember(const v8::Arguments &args, const char *name);
-    static v8::Handle<v8::Value> Constructor(const v8::Arguments &args);
 
     static v8::Handle<v8::Value> LocalToString(const v8::Arguments &args);
@@ -97,4 +103,8 @@
     static v8::Handle<v8::Value> ConstructorSky(const v8::Arguments &args);
     static v8::Handle<v8::Value> ConstructorLocal(const v8::Arguments &args);
+    static v8::Handle<v8::Value> MoonHorizon(const v8::Arguments &args);
+    static v8::Handle<v8::Value> SunHorizon(const v8::Arguments &args);
+    static v8::Handle<v8::Object> ConstructRiseSet(const v8::Handle<v8::Value>, const ln_rst_time &);
+#endif
 
     static v8::Handle<v8::Value> WrapInclude(const v8::Arguments &args)  { if (This) return This->FuncInclude(args);  else return v8::Undefined(); }
