1 'use strict';
  2 
  3 //this is just the class implementation of 'Observation'
  4 include('scripts/Observation_class.js');
  5 
  6 var file = $['file'] ? $['file'] : 'scripts/schedule.js';
  7 
  8 console.out('Reading schedule from '+file);
  9 
 10 // this file just contains the definition of
 11 // the variable observations, which builds our nightly schedule, hence the filename
 12 include(file);
 13 
 14 // -------------------------------------------------------------------------------------
 15 
 16 // Get current time
 17 var now = new Date(); //new Date("2013-04-07 19:00:00 UTC");
 18 
 19 // Because Main.js could start a new observations just in the moment between 'now'
 20 // and entering the new data in the database, we have to use the unique id
 21 // in Main.js to check if the current observation should be changed (and sub resetted)
 22 now = new Date(now.getTime());
 23 
 24 //console.out("","NOW: "+now.toUTCString());
 25 
 26 // -------------------------------------------------------------------------------------
 27 
 28 console.out("Processing "+observations.length+" entries.");
 29 
 30 var has_now = false;
 31 
 32 // make Observation objects from user input and check if 'date' is increasing.
 33 for (var i=0; i<observations.length; i++)
 34 {
 35     if (observations[i].date.toUpperCase()=="NOW")
 36     {
 37         if (has_now)
 38             throw new Error("Only one entry 'now' allowed");
 39 
 40         has_now = true;
 41     }
 42 
 43     observations[i] = new Observation(observations[i]);
 44 
 45     // check if the start date given by the user is increasing.
 46     if (i>0 && observations[i].start <= observations[i-1].start)
 47     {
 48         throw new Error("Start time '"+ observations[i].start.toUTCString()+
 49                         "' in row "+i+" exceeds start time in row "+(i-1)+" "+observations[i-1].start.toUTCString() );
 50     }
 51 }
 52 
 53 // Remove all past entries from the schedule
 54 while (observations.length>0 && observations[0].start<now)
 55     observations.shift();
 56 
 57 // Output for debugging
 58 /*
 59 console.out("");
 60 for (var i=0; i<observations.length; i++)
 61 {
 62     for (var j=0; j<observations[i].length; j++)
 63         console.out("%3d.%3d: ".$(i,j)+JSON.stringify(observations[i][j]));
 64     console.out("");
 65 }*/
 66 
 67 // -------------------------------------------------------------------------------------
 68 
 69 // Connect to database
 70 var db = new Database("scheduler:5ch3du13r@www.fact-project.org/factdata");
 71 
 72 // get all sources from database
 73 var sources = db.query("SELECT * from Source");
 74 
 75 // Convert SourceName to SourceKey
 76 function getSourceKey(src)
 77 {
 78     var arr = sources.filter(function(e) { return e['fSourceName']==src; });
 79     if (arr.length==0)
 80         throw new Error("Source '"+src+"' unknown.");
 81     if (arr.length>1)
 82         throw new Error("More than one source '"+src+"' found.");
 83     return arr[0]['fSourceKEY'];
 84 }
 85 
 86 // -------------------------------------------------------------------------------------
 87 
 88 // List of all available measurement types
 89 var measurementType = [ "STARTUP", "IDLE", "DRSCALIB", "SINGLEPE", "DATA", "RATESCAN", "SHUTDOWN", "OVTEST", "RATESCAN2", "SLEEP", "CUSTOM" ];
 90 
 91 // Convert measurement type to index
 92 function getMeasurementTypeKey(task)
 93 {
 94     var idx = measurementType.indexOf(task);
 95     if (idx>=0)
 96         return idx;
 97 
 98     throw new Error("Task "+task+" not supported!");
 99 }
100 
101 // -------------------------------------------------------------------------------------
102 
103 var queries = [ ];
104 
105 var system_on = false;
106 
107 // Now create the schedule which should be entered into the databse
108 for (var i=0; i<observations.length; i++)
109 {
110     var obs = observations[i];
111 
112     for (var j=0; j<obs.length; j++)
113     {
114         console.out(i+" "+j+" "+obs[j].start.toUTCString());
115         var isUp = Sun.horizon(-12, obs[j].start).isUp;
116 
117         if (obs[j].task=="STARTUP" && j>0)
118             throw new Error("STARTUP must be the first measurement in a list of measurements.");
119         if (obs[j].task=="DATA" && j!=obs.length-1)
120             throw new Error("DATA must be the last task in a list of measurements");
121         if (obs[j].task=="SHUTDOWN" && j!=obs.length-1)
122             throw new Error("SHUTDOWN must be the last task in a list of measurements");
123         if (system_on && obs[j].task=="SHUTDOWN" && isUp)
124             throw new Error("SHUTDOWN must not be scheduled after -12deg (~10min before nautical sun-rise)");
125         // FIXME: Check also end-time!
126         if ((obs[j].task=="DATA" || obs[j].task=="RATESCAN" ||  obs[j].task=="RATESCAN2" ) && isUp)
127             throw new Error("Data or Ratescan must not be scheduled when the sun is up (-12deg, earlist/lastest during astronomical twilight)");
128 
129         if (obs[j].task=="STARTUP" || obs[j].task=="DATA")
130             system_on = true;
131 
132         var str = "INSERT INTO Schedule SET";
133         str += " fStart='"+obs[j].start.toISOString()+"'";
134         str += ",fMeasurementID="+obs[j].sub;
135         str += ",fMeasurementTypeKey="+getMeasurementTypeKey(obs[j].task);
136 
137         // Currently only data in the case when a source is given or ra/dec is given can be provided
138         if (obs[j].source)
139             str += ",fSourceKey="+getSourceKey(obs[j].source);
140 
141         //lidclosed only  needs to be inserted to DB if 'false'
142         if (obs[j].lidclosed)
143         {
144             if (obs[j].task=="RATESCAN2" && obs[j].rstype!="default")
145                 str += ",fData='\"lidclosed\":"+obs[j].lidclosed+",\"rstype\":\""+obs[j].rstype+"\",\"zd\":"+obs[j].zd+",\"az\":"+obs[j].az+"'";
146             else
147                 str += ",fData='\"lidclosed\":"+obs[j].lidclosed+",\"zd\":"+obs[j].zd+",\"az\":"+obs[j].az+"'";
148         }
149         else
150             if (obs[j].ra)
151                 str += ",fData='\"ra\":"+obs[j].ra+",\"dec\":"+obs[j].dec+"'";
152 
153         if (obs[j].task=="CUSTOM")
154             str += ",fData='\"biason\":"+obs[j].biason+",\"time\":\""+obs[j].time+"\",\"threshold\":\""+obs[j].threshold+"\",\"zd\":"+obs[j].zd+",\"az\":"+obs[j].az+"'";
155 
156         queries.push(str);
157     }
158 }
159 
160 if (queries.length==0)
161 {
162     console.out("","Nothing to do... no observation past "+now.toUTCString(), "");
163     exit();
164 }
165 
166 // Output and send all queries, update the databse
167 //console.out("");
168 
169 db.query("LOCK TABLES Schedule WRITE");
170 db.query("DELETE FROM Schedule WHERE fStart>='"+now.toISOString()+"'");
171 for (var i=0; i<queries.length; i++)
172     db.query(queries[i]);
173 db.query("UNLOCK TABLES");
174 
175 //console.out("");
176 
177 // ======================================================================================
178 
179 // Because Main.js could start a new observations just in the moment between 'now'
180 // and entering the new data in the database, we have to use the unique id
181 // in Main.js to check if the current observation should be changed (and sub resetted)
182 var start = new Date(now.getTime());//-12*3600000);
183 
184 //console.out("","START: "+now.toUTCString());
185 
186 // Get the current schedule
187 var rows = db.query("SELECT * FROM Schedule WHERE fStart>='"+start.toISOString()+"' ORDER BY fStart, fMeasurementID");
188 
189 var schedule = [];
190 var entry    = -1;
191 var sub      =  0;
192 
193 for (var i=0; i<rows.length; i++)
194 {
195     //console.out(JSON.stringify(rows[i]));
196 
197     var start = new Date(rows[i]['fStart']+" UTC");
198     var id    = rows[i]['fScheduleID'];
199     var src   = rows[i]['fSourceKey'];
200     var task  = rows[i]['fMeasurementTypeKey'];
201     var sub   = rows[i]['fMeasurementID'];
202     var data  = rows[i]['fData'];
203 
204     if (sub==0)
205         entry++;
206 
207     var m = { }
208     m.task = measurementType[task];
209 
210     if (src)
211     {
212         // Convert SourceKey to SourceName
213         var arr = sources.filter(function(e) { return e['fSourceKEY']==src; });
214         if (arr.length==0)
215             throw new Error("SourceKey "+src+" unknown.");
216 
217         m.source = arr[0]['fSourceName'];
218     }
219 
220     if (data)
221     {
222         var obj = JSON.parse(("{"+data+"}").replace(/\ /g, "").replace(/(\w+):/gi, "\"$1\":"));
223         for (var key in obj)
224             m[key] = obj[key];
225     }
226 
227     if (!schedule[entry])
228         schedule[entry] = { };
229 
230     schedule[entry].id   = id;
231     schedule[entry].date = start;
232 
233     if (!schedule[entry].measurements)
234         schedule[entry].measurements = [];
235 
236     schedule[entry].measurements[sub] = m;
237 }
238 
239 // -------------------------------------------------------------------------------------
240 
241 console.out("[");
242 for (var i=0; i<schedule.length; i++)
243 {
244     var obs = schedule[i];
245 
246     console.out(' { date:"'+obs.date.toISOString()+'" measurements:');
247     var obs = obs.measurements;
248 
249     console.out("     [");
250     for (var j=0; j<obs.length; j++)
251     {
252         console.out("      "+JSON.stringify(obs[j])+",");
253     }
254     console.out("     ]");
255     console.out(" },");
256 }
257 console.out("]");
258