Index: /trunk/FACT++/src/smartfact.cc
===================================================================
--- /trunk/FACT++/src/smartfact.cc	(revision 13794)
+++ /trunk/FACT++/src/smartfact.cc	(revision 13795)
@@ -33,8 +33,17 @@
 // ------------------------------------------------------------------------
 
+const static string kHtmlWhite  = "#ffffff";
+const static string kHtmlYellow = "#fffff0";
+const static string kHtmlRed    = "#fff8f0";
+const static string kHtmlGreen  = "#f0fff0";
+const static string kHtmlBlue   = "#f0f0ff";
+
 #ifdef HAVE_LIBNOVA
 
 class Astro
 {
+public:
+    Time time;
+
     Time fSunRiseDayTime;
     Time fSunRiseCivil;
@@ -47,22 +56,16 @@
     Time fSunSetDarkTime;
 
-    ln_rst_time moon;
-
-    ln_equ_posn moon_position;
-    double      moon_disk;
-
+    int state;
     string description;
-
-    //observer.lng = -(17.+53./60+26.525/3600);
-    //observer.lat =   28.+45./60+42.462/3600;
+    string color;
+
+    bool isday;
+
 public:
-    Astro(double lon, double lat, /*const*/ Time/* &*/time=Time())
-    {
-        // observers location (Edinburgh), used to calc rst
-        struct ln_lnlat_posn observer;
-        observer.lng = -(17.+53./60+26.525/3600);
-        observer.lat =   28.+45./60+42.462/3600;
-
-        time = Time(2012, 5, 18, 23, 30);
+    Astro(double lon, double lat, const Time &t=Time()) :  time(t)
+    {
+        ln_lnlat_posn observer;
+        observer.lng = lon;
+        observer.lat = lat;
 
         // get Julian day from local time
@@ -75,5 +78,5 @@
 
         // Warning: return code of 1 means circumpolar and is not checked!
-        ln_get_lunar_rst        (JD-0.5, &observer,      &moon);
+        //ln_get_lunar_rst        (JD-0.5, &observer,      &moon);
         ln_get_solar_rst        (JD-0.5, &observer,      &sun_day);
         ln_get_solar_rst_horizon(JD-0.5, &observer, - 6, &sun_civil);
@@ -94,5 +97,5 @@
         const bool is_night = JD>sun_dark.set;
 
-        ln_get_lunar_rst        (JD+0.5, &observer,      &moon);
+        //ln_get_lunar_rst        (JD+0.5, &observer,      &moon);
         ln_get_solar_rst        (JD+0.5, &observer,      &sun_day);
         ln_get_solar_rst_horizon(JD+0.5, &observer, - 6, &sun_civil);
@@ -119,5 +122,5 @@
         // case 1: sun-rise to sun-set  |  is_day && !is_night | set /rise
         // case 2: sun-set  to midnight |  is_day &&  is_night | rise/set
-
+        /*
         if (is_day^is_night)
         {
@@ -129,9 +132,9 @@
             cout << "SunRise: " << fSunRiseDayTime << endl;
             cout << "SunSet:  " << fSunSetDayTime  << endl;
-        }
-
-        //const double mjd = Time(JD-2400000.5).Mjd();
-
-        int state = is_day^is_night ? 4 : 0;
+        }*/
+
+        isday = is_day^is_night;
+
+        state = isday ? 4 : 0;
         if (time>fSunSetDayTime)       state++;
         if (time>fSunSetCivil)         state++;
@@ -147,5 +150,5 @@
         {
             "dark time",
-            "astronomical twilight",
+            "astron. twilight",
             "civil twilight",
             "sunrise",
@@ -153,5 +156,5 @@
             "sunset",
             "civil twilight",
-            "astronomical twilight",
+            "astron. twilight",
             "dark time"
         };
@@ -159,69 +162,141 @@
         description = state[name];
 
-
-        cout << "NOW: " << name[state] << " [" << state << "]" << endl << endl;
-
-/*
-        // RA, DEC
-        ln_get_lunar_equ_coords(JD, &moon_position);
-        //cout << "MoonRa:  " << equ.ra  << "\n";
-        //cout << "MoonDec: " << equ.dec << "\n";
-
-        // lunar disk, phase and bright limb
-        moon_disk = ln_get_lunar_disk(JD);
-
-        if (JD>sun_dark.set || JD<sun_normal.rise)
-        {
-            cout << "Sunrise will be at:" << endl;
-            cout << "Astronom. TwL: " << Time(sun_dark.rise        -2400000.5).GetAsStr() << endl;
-            cout << "Civil     TwL: " << Time(sun_astronomical.rise-2400000.5).GetAsStr() << endl;
-            cout << "Sunrise:       " << Time(sun_civil.rise       -2400000.5).GetAsStr() << endl;
-            cout << "Day time:      " << Time(sun_normal.rise      -2400000.5).GetAsStr() << endl;
+        string arr;
+        ostringstream out;
+        if (isday)
+        {
+            out << fSunSetDarkTime-time;
+            arr = "&darr;";
         }
         else
         {
-            cout << "Sunset will be at:" << endl;
-            cout << "Sunset:        " << Time(sun_normal.set      -2400000.5).GetAsStr() << endl;
-            cout << "Civil     TwL: " << Time(sun_civil.set       -2400000.5).GetAsStr() << endl;
-            cout << "Astronom. TwL: " << Time(sun_astronomical.set-2400000.5).GetAsStr() << endl;
-            cout << "Dark time:     " << Time(sun_dark.set        -2400000.5).GetAsStr() << endl;
-        }
-
-        if (JD>moon.rise && JD<moon.set)
-            cout << "Moon: VISIBLE (" << setprecision(2) <<  moon_disk*100 << "%)" << endl;
-
-        if (JD<moon.rise)
-            cout << "MoonRise: " << Time(moon.rise   -2400000.5) << endl;
-        if (JD<moon.transit)
-            cout << "MoonCulm: " << Time(moon.transit-2400000.5) << endl;
-        if (JD<moon.set)
-            cout << "MoonSet:  " << Time(moon.set    -2400000.5) << endl;
-            */
-        }
-
-    /*
-
-    Always show the next event:
-
-    What do we have now?
-    time between sunset and civil:        sunset
-    time between civial and astronominal: civil
-    time between astronominal and dark:   astronomical
-    time above dark:                      dark
-
-
-    */
-
+            out << fSunRiseDayTime-time;
+            arr = "&uarr;";
+        }
+
+        description += " ["+out.str().substr(0, 5)+arr+"]";
+
+        switch (state)
+        {
+        case 0: case 1:  color = kHtmlGreen;   break;
+        case 2: case 3:  color = kHtmlYellow;  break;
+        case 4:          color = kHtmlRed;     break;
+        case 5: case 6:  color = kHtmlYellow;  break;
+        case 7: case 8:  color = kHtmlGreen;   break;
+        }
+    }
 };
 
+class Moon
+{
+public:
+    double ra;
+    double dec;
+
+    double disk;
+
+    bool visible;
+
+    Time fMoonRise;
+    Time fMoonTransit;
+    Time fMoonSet;
+
+    string description;
+    string color;
+
+    Time time;
+
+    Moon(double lon, double lat, const Time &t=Time()) : time(t)
+    {
+        const double JD = time.JD();
+
+        ln_lnlat_posn observer;
+        observer.lng = lon;
+        observer.lat = lat;
+
+        ln_rst_time moon;
+        ln_get_lunar_rst(JD-0.5, &observer, &moon);
+
+        fMoonRise    = Time(moon.rise);
+        fMoonTransit = Time(moon.transit);
+        fMoonSet     = Time(moon.set);
+
+        visible =
+            (JD>moon.rise && JD<moon.set  && moon.rise<moon.set) ||
+            ((JD<moon.set  || JD>moon.rise) && moon.rise>moon.set);
+
+        const bool is_up      = JD>moon.rise;
+        const bool is_sinking = JD>moon.transit;
+        const bool is_dn      = JD>moon.set;
+
+        ln_get_lunar_rst(JD+0.5, &observer, &moon);
+        if (is_up)
+            fMoonRise = Time(moon.rise);
+        if (is_sinking)
+            fMoonTransit = Time(moon.transit);
+        if (is_dn)
+            fMoonSet = Time(moon.set);
+
+        ln_equ_posn pos;
+        ln_get_lunar_equ_coords(JD, &pos);
+
+        ra  = pos.ra/15;
+        dec = pos.dec;
+
+        disk = ln_get_lunar_disk(JD)*100;
+
+        if (!visible || disk<25)
+            color = kHtmlGreen;
+        else
+            color = disk>75 ? kHtmlRed : kHtmlYellow;
+
+        string arr;
+        ostringstream dt;
+        if (fMoonSet<fMoonRise)
+        {
+            dt << fMoonSet-time;
+            arr = "&darr;";
+        }
+        else
+        {
+            dt << fMoonRise-time;
+            arr = "&uarr;";
+        }
+
+        ostringstream out;
+        out << setprecision(2);
+        out << (visible?"visible ":"") << disk << "% [" << dt.str().substr(0,5) << arr << "]";
+
+        description = out.str();
+    }
+
+    double Angle(double r, double d)
+    {
+        const double theta0 = M_PI/2-d*M_PI/180;
+        const double phi0   = r*M_PI/12;
+
+        const double theta1 = M_PI/2-dec*M_PI/180;
+        const double phi1   = ra*M_PI/12;
+
+        const double x0 = sin(theta0) * cos(phi0);
+        const double y0 = sin(theta0) * sin(phi0);
+        const double z0 = cos(theta0);
+
+        const double x1 = sin(theta1) * cos(phi1);
+        const double y1 = sin(theta1) * sin(phi1);
+        const double z1 = cos(theta1);
+
+        double arg = x0*x1 + y0*y1 + z0*z1;
+        if(arg >  1.0) arg =  1.0;
+        if(arg < -1.0) arg = -1.0;
+
+        return acos(arg) * 180/M_PI;
+    }
+};
+
 #endif
 
 // ------------------------------------------------------------------------
 
-const static string kHtmlWhite  = "#ffffff";
-const static string kHtmlYellow = "#fffff0";
-const static string kHtmlRed    = "#fff8f0";
-const static string kHtmlGreen  = "#f0fff0";
-const static string kHtmlBlue   = "#f0f0ff";
 
 class StateMachineSmartFACT : public StateMachineDim, public DimInfoHandler
@@ -594,13 +669,36 @@
         const uint16_t idx = uint16_t(floor(fmod(fMagicWeatherHist[kDir].back()+360+11.25, 360)/22.5));
 
+        Astro astro(-(17.+53./60+26.525/3600), 28.+45./60+42.462/3600);
+        Moon  moon(-(17.+53./60+26.525/3600), 28.+45./60+42.462/3600);
+
         ostringstream out;
         out << d.time.JavaDate() << '\n';
+        out << astro.color << '\t' << astro.description << '\n';
+        out << setprecision(2);
+        out << (astro.isday?kHtmlWhite:moon.color) << '\t' << moon.description << '\n';
+        out << setprecision(3);
         for (int i=0; i<6; i++)
             out << "#ffffff\t" << fMagicWeatherHist[i].back() << '\n';
         out << "#ffffff\t" << dir[idx] << '\n';
 
-        //Astro a(-(17.+53./60+26.525/3600), 28.+45./60+42.462/3600);
-
         ofstream(fPath+"/magicweather.txt") << out.str();
+
+        out.str("");
+        out << astro.time.JavaDate() << '\n';
+        out << kHtmlWhite << '\t' << astro.fSunRiseDarkTime.GetAsStr("%H:%M") << '\n';
+        out << kHtmlWhite << '\t' << astro.fSunRiseAstronomical.GetAsStr("%H:%M") << '\n';
+        out << kHtmlWhite << '\t' << astro.fSunRiseCivil.GetAsStr("%H:%M") << '\n';
+        out << kHtmlWhite << '\t' << astro.fSunRiseDayTime.GetAsStr("%H:%M") << '\n';
+
+        out << kHtmlWhite << '\t' << astro.fSunSetDayTime.GetAsStr("%H:%M") << '\n';
+        out << kHtmlWhite << '\t' << astro.fSunSetCivil.GetAsStr("%H:%M") << '\n';
+        out << kHtmlWhite << '\t' << astro.fSunSetAstronomical.GetAsStr("%H:%M") << '\n';
+        out << kHtmlWhite << '\t' << astro.fSunSetDarkTime.GetAsStr("%H:%M") << '\n';
+
+        out << kHtmlWhite << '\t' << moon.fMoonRise.GetAsStr("%H:%M") << '\n';
+        out << kHtmlWhite << '\t' << moon.fMoonTransit.GetAsStr("%H:%M") << '\n';
+        out << kHtmlWhite << '\t' << moon.fMoonSet.GetAsStr("%H:%M") << '\n';
+
+        ofstream(fPath+"/astro.txt") << out.str();
 
         WriteWeather(d, "temp",  kTemp,   -5,   35);
@@ -672,12 +770,27 @@
         out << d.time.JavaDate() << '\n';
 
-        out << "#ffffff\t" << fDriveControlSourceName << '\n';
+        out << kHtmlWhite << '\t' << fDriveControlSourceName << '\n';
         out << setprecision(5);
-        out << "#ffffff\t" << Ra  << '\n';
-        out << "#ffffff\t" << Dec << '\n';
+        out << kHtmlWhite << '\t' << Ra  << '\n';
+        out << kHtmlWhite << '\t' << Dec << '\n';
         out << setprecision(3);
-        out << "#ffffff\t" << Zd  << '\n';
-        out << "#ffffff\t" << Az  << '\n';
-        out << "#ffffff\t" << dev << '\n';
+        out << kHtmlWhite << '\t' << Zd  << '\n';
+        out << kHtmlWhite << '\t' << Az  << '\n';
+        out << kHtmlWhite << '\t' << dev << '\n';
+
+        Moon moon(-(17.+53./60+26.525/3600), 28.+45./60+42.462/3600);
+        if (moon.visible)
+        {
+            const double angle = moon.Angle(Ra, Dec);
+
+            string col = kHtmlGreen;
+            if (angle<35 || angle>145)
+                col = kHtmlYellow;
+            if (angle<25 || angle>155)
+                col = kHtmlRed;
+            out << col << '\t' << setprecision(3) << angle << '\n';
+        }
+        else
+            out << kHtmlWhite << "\t&mdash; \n";
 
         ofstream(fPath+"/tracking.txt") << out.str();
@@ -1336,7 +1449,11 @@
         {
             string col = kHtmlBlue;
+            /*
             if (fMcpConfigurationState!= 5 &&  // Idle
                 fMcpConfigurationState!=11 &&  // Trigger On
-                fMcpConfigurationState!=12)    // Taking Data
+                fMcpConfigurationState!=12)    // Taking Data*/
+            if (fDimMcp.state()!= 5 &&  // Idle
+                fDimMcp.state()!=11 &&  // Trigger On
+                fDimMcp.state()!=12)    // Taking Data
                 col = kHtmlYellow;
             else
@@ -1345,18 +1462,21 @@
 
             out << col << '\t';
-            /*
-             out << fDimRateControl.state() << "/";
-             out << fDimRateScan.state() << "/";
-             out << fMcpConfigurationState << "/";
-             */
-
-            if (fDimRateControl.state()!=5 &&
-                fDimRateScan.state()!=5)
+
+            if (fDimRateControl.state()!=5 && fDimRateScan.state()!=5)
             {
-                if (fMcpConfigurationState!=5 &&
-                    fMcpConfigurationState!=11 &&
-                    fMcpConfigurationState!=12)
-                    out << "Configuring ";
-                out << fMcpConfigurationName;
+                switch (fDimMcp.state()/*fMcpConfigurationState*/)
+                {
+                // kStateIdle
+                case  5: out << "Idle [" << fMcpConfigurationName << "]"; break;
+                // Configuring1 - Configuring3
+                case  7:
+                case  8:
+                case  9: out << "Configuring [" << fMcpConfigurationName << "]"; break;
+                // Configured
+                case 10: out << "Configured [" << fMcpConfigurationName << "]"; break;
+                // TriggerOn / Taking Data
+                case 11: 
+                case 12: out << fMcpConfigurationName; break;
+                }
             }
             else
@@ -1368,5 +1488,5 @@
                         out << "Rate scan in progress";
 
-            if (fDimMcp.state()>5 && fDimRateControl.state()!=5)
+            if (fDimMcp.state()>10 && fDimRateControl.state()!=5)
             {
                 if (fMcpConfigurationMaxEvents>0 || fMcpConfigurationMaxTime>0 || fMcpConfigurationState==12)
