#! /usr/bin/octave -fq

if (false)
  ## Read CSV data from file
  filename = "fornetto";
  filename = "2014-03-30";
  filename = "2014-03-29";
  filename = "2014-02-03";
  filename = "test";
  infile = ["dumps/" filename ".csv"];
  outfile = ["tags/" filename ".json"];
  fid = fopen(outfile, 'w');
else
  ## Read CSV data from standard input
  infile = stdin();
  fid = stdout;
endif
data = dlmread(infile, ',');

## Global variables
global m = struct()
global json

## Initialise the global state
m.curtime = 0;
m.oldtime = 0;
m.curact = 0;
m.oldact = 0;
m.currea = 0;
m.oldrea = 0;
m.basetime = 0;
m.baseact = 0;
m.baserea = 0;
m.starttime = 0;
m.ontime = 0;
m.state = "idle";
m.reachange = false;
m.active = false;
m.const.period = 20000;

## Utility functions including fuzzy comparisons
function val = approxeq(a, b, tol=150)
  val = (a > b-tol && a < b+tol);
endfunction

function val = approxle(a, b, tol=150)
  val = a < b+tol;
endfunction

function val = approxge(a, b, tol=150)
  val = a > b-tol;
endfunction

#
## States of the state machine
function idle
  global m
  if (m.curact-m.oldact > 100 && approxle(m.curact-m.oldact, 1500))
    m.reachange = false;
    m.baseact = m.oldact;
    m.baserea = m.oldrea;
    m.starttime = m.curtime;
    m.state = @starting;
  endif
endfunction

function starting
  global m
  if (m.curact > 1500 && approxeq(m.curact-m.baseact, 1500))
    m.ontime = m.curtime;
    m.baseact = m.curact-1500;
    m.state = @on;
  else
    m.state = @idle;
    feval(m.state);
  endif
endfunction

function goingup
  global m
  if (m.curact > 1500 && approxeq(m.curact-m.baseact, 1500))
    m.ontime = m.curtime;
    m.baseact = m.curact-1500;
    m.state = @on;
  else
    m.state = @off;
    feval(m.state);
  endif
endfunction

function on
  global m
  if (m.curact-m.oldact < -100 && approxge(m.curact-m.oldact,-1500))
    m.state = @goingdown;
##   elseif (approxeq(m.curact-m.baseact,1500)
## 	  #&& m.curtime-m.ontime > m.const.period+1000
## 	  && approxeq(m.currea-m.baserea, 160, 100))
##     m.ontime += m.const.period;
##     #puts(["-<new ontime:" strtrim(ctime(m.ontime/1000)) ">-"]);
  else
    m.baseact = m.curact-1500;
  endif
  if (m.baseact < 0)
    if (m.active)
      secs = (m.ontime+m.const.period-m.starttime)/1000;
      fprintf(stderr, " --> false alarm (duration %d'%d\")\n", floor(secs/60), rem(secs, 60));
    endif
    m.state = @idle;
    m.active = false;
  elseif (!m.active && m.curtime-m.starttime > m.const.period/2 && m.reachange)
    m.active = true;
    fputs(stderr, ["micro on at " strtrim(ctime(m.starttime/1000))]);
  endif
endfunction

function goingdown
  global m
  if (approxeq(m.curact, m.baseact))
    m.baseact = m.curact;
    m.state = @off;
  else
    m.state = @on;
    feval(m.state);
  endif
endfunction

function off
  global m json
  if (m.curact-m.oldact > 100 && approxle(m.curact-m.oldact, 1500))
    m.state = @goingup;
  else
    m.baseact = m.curact;
  endif
  if (!m.active && m.curtime-m.starttime > m.const.period/2 && m.reachange)
    m.active = true;
    fputs(stderr, ["micro on at " strtrim(ctime(m.starttime/1000))]);
  endif
  if (m.curtime-m.ontime > m.const.period+1000)
    m.state = @idle;
    if (m.active)
      m.active = false;
      secs = (m.ontime+m.const.period-m.starttime)/1000;
      fprintf(stderr, ", duration %d'%d\"\n", floor(secs/60), rem(secs, 60));
      comma = ",\n";
      str = '"shortText":"M", "cssClass":"annotation';
      if (length(json) > 1)
	json(end+1) = { comma };
      endif
      json(end+1) = { sprintf('{ "x":%ld, %sBeg", "text":"" }%s{ "x":%ld, %sEnd", "text":"" }',
			      m.starttime, str, comma, m.curtime, str) };
    endif
  endif
endfunction


#
## Open the JSON output
json = { "{ \"tags\" : [\n" };

## Run the state machine on every data row
for i = 1:rows(data)

  ## Data gap
  if (isnan(time = data(i,1)))
    if (m.active)
       fputs(stderr, ", data gap, duration unknown\n");
    endif
    m.state = @idle;
    m.active = false;
  endif

  ## Reactive power reading
  if ((rea = data(i,3)) > 0)
    m.oldrea = m.currea;
    m.currea = rea;
  endif

  ## Active power reading
  if ((act = data(i,2)) > 0)
    m.oldtime = m.curtime;
    m.curtime = time;
    m.oldact = m.curact;
    m.curact = act;

    m.reachange |= approxeq(m.currea-m.baserea, 160, 100);
    feval(m.state);
    data(i,4) = m.active;
    if (false)					# set to true for debugging
      format long
      #disp({m.curtime, strtrim(ctime(m.curtime/1000)), m.oldact, m.curact, m.state, m.baseact, m.reachange, m.active});
      disp(m);
    endif
  endif

endfor

## Close the JSON output
json(end+1) = {"\n] }\n"};
fputs(fid, cell2mat(json));
