'use strict';

var Func = function() { };
Func.sum = function(a, b) { return a+b; }
Func.sq  = function(a, b) { return Math.sqrt(a*a + b*b); }
Func.min = function(a, b) { return Math.min(a, b); }
Func.max = function(a, b) { return Math.max(a, b); }
Func.avg = function(arr)  { return arr.reduce(Func.Sum, 0)/arr.length; }
Func.stat = function(arr, func)
{
    if (arr.length==0)
        return undefined;

    var sum = 0;
    var sq  = 0;
    var cnt = 0;
    var min = arr[0];
    var max = arr[0];
    arr.forEach(function(val) { sum+=val; sq+=val*val; if (val>max) max=val; if (val<min) min=val; if (func && func(val)) cnt++ });
    sum /= arr.length;
    sq  /= arr.length;

    return { avg:sum, rms:Math.sqrt(sq-sum*sum), min:min, max:max, count:cnt };
}

// ===================================================================

console.out(("\n%78s".$("")).replace(/ /g, "="));

include('scripts/CheckStates.js');

var table =
[
 [ "MCP",             [ "Idle"      ] ],
 [ "AGILENT_CONTROL", [ "VoltageOn" ] ],
 [ "FTM_CONTROL",     [ "Idle"      ] ],
 [ "FAD_CONTROL",     [ "Connected",    "WritingData"     ] ],
 [ "BIAS_CONTROL",    [ "Disconnected", "VoltageOff"      ] ],
 [ "DATA_LOGGER",     [ "WaitForRun",   "NightlyFileOpen", "Logging" ] ],
];

console.out("Checking states.");
if (!checkStates(table))
{
    throw new Error("Something unexpected has happened. One of the servers",
            "is in a state in which it should not be. Please,",
            "try to find out what happened...");
}

// ===================================================================

include('scripts/Hist1D.js');
include('scripts/Hist2D.js');

console.out("Checking power on time");

var service_drs = new Subscription("FAD_CONTROL/DRS_RUNS");

var runs = service_drs.get(5000, false);
if (!runs)
    throw new Error("Could not connect to FAD_CONTROL/DRS_RUNS");
/*
runs = {
    "name"    : "FAD_CONTROL/DRS_RUNS",
    "format"  : "I:1;I:3",
    "qos"     : 0,
    "size"    : 16,
    "counter" : 0,
    "time"    : new Date("2012-11-20T05:23:52.804Z"),
    "data"    : [300,[148,149,154]]
  };
*/

// Wait for agilent to be online with state information
// FIXME: timeout
while (!dim.state("AGILENT_CONTROL"))
    v8.sleep();

var power = dim.state("AGILENT_CONTROL").time;
var now   = new Date();

var diff = (now-runs.time)/3600000;

console.out(" * Now:                "+now);
console.out(" * Last power cycle:   "+power);
console.out(" * Last DRS calib set: "+(runs.data?runs.time:"none"));
//console.out(JSON.stringify(dim.state("AGILENT_CONTROL")));


if (1)//diff>8 && now.getHours()>16 || runs.time<power)
{
    //console.out("Most probablay the camera has not been checked for underflows yet.");

    // Wait for dim.send to be ready
    // FIXME: timeout
    while (!dim.send("FAD_CONTROL"))
        v8.sleep();

    // FAD_CONTROL/RAW_DATA:
    //  roi,roi_tm,num_fad,num_ftm,type,num_boards,error,
    //  dummy,time,time_board,start_pix,start_tm,adc

    // FAD_CONTROL/EVENT_DATA
    // avg,rms,max,pos

    var service_event = new Subscription("FAD_CONTROL/EVENT_DATA");
    var event = service_event.get(5000, false);
    //if (!event)
    //    throw new Error("Could not connect to FAD_CONTROL/EVENT_DATA");

    var event_counter = event.counter;

    dim.send("FAD_CONTROL/START_DRS_CALIBRATION");
    dim.send("FAD_CONTROL/SET_FILE_FORMAT", 0);

    console.out("Starting drs-gain");
    dim.send("MCP/START", -1, 3, "drs-gain");

    // FIXME: add a timeout here (10s)
    console.out("Waiting for new event");
    var d = new Date();
    while (event_counter == service_event.get(0, false).counter)
        v8.sleep();

    console.out("Event received: "+(new Date()-d)+"ms");

    console.out("Stop run");
    dim.send("MCP/STOP");
    while (!dim.send("RATE_CONTROL"))
    {
        v8.sleep(800);
        console.out("waiting for RATE_CONTROL to send the necessary format information");
    }
    dim.send("RATE_CONTROL/STOP"); // GlobalThresholdSet -> Connected
    dim.wait("MCP", "Idle", 3000);

    var nn = runs.data && runs.data[0]>0 ? runs.data[1].reduce(Func.max) : -1;
    if (nn>0)
    {
        console.out("Trying to restore last DRS calibration #"+nn+"  ["+runs.time+"]");

        var night = new Date(runs.time-1000*60*60*12);
        var yy = night.getUTCFullYear();
        var mm = night.getUTCMonth()+1;
        var dd = night.getUTCDate();

        var filefmt = "/loc_data/raw/%d/%02d/%02d/%4d%02d%02d_%03d.drs.fits";

        // FIXME: Timeout
        var drs_counter = service_drs.get(0, false);
        dim.send("FAD_CONTROL/LOAD_DRS_CALIBRATION", filefmt.$(yy, mm, dd, yy, mm, dd, nn));
        while (drs_counter == service_drs.get(0, false).counter)
            v8.sleep();
    }

    //console.out(JSON.stringify(service_drs.get(0, false)));

    event = service_event.get(0, false);

    service_event.close();

    var hist = Hist2D(16, -2048.5, 2048.5, 11, -10, 100);

    for (var i=0; i<1440; i++)
        hist.fill(event.data[0][i], isNaN(event.data[1][i])?-1:event.data[1][i]);

    //console.out(("%78s".$("")).replace(/ /g, "-"));
    hist.print();
    //console.out(("%78s".$("")).replace(/ /g, "-"));

    // Could also be <512
    var stat0 = Func.stat(event.data[0], function(val) { if (val<0) console.out(" VAL="+val); return val<0; });
    var stat1 = Func.stat(event.data[1]);

    console.out("Avg[min]=%.1f".$(stat0.min));
    console.out("Avg[avg]=%.1f +- %.1f".$(stat0.avg, stat0.rms));
    console.out("Avg[max]=%.1f".$(+stat0.max));
    console.out("Avg[cnt]="+stat0.count);
    console.out("");
    console.out("Rms[min]=%.1f".$(stat1.min));
    console.out("Rms[avg]=%.1f +- %.1f".$(stat1.avg, stat1.rms));
    console.out("Rms[max]=%.1f".$(stat1.max));
    console.out(("%78s\n".$("")).replace(/ /g, "="));
}

service_drs.close();
