// Vipa ver. 1.0b by dpanic@gmail.com
// http://dpanic.googlepages.com

module Vipa;
var
  RADI := true,
  stats:={};

proc Log(v) =
  begin
    printf("[ %s ] %s\n", now(), text v);
  end Log;

proc w(d, f, v) =
  var
    rd, wr, entries, e, ima:=false;
  begin
    try
      entries:=FS.ReadDir(".");
      for e in entries do
        if e.type = "dir" and e.name = d then
          ima:=true;
        end;
      end;
      if ima = false then
        try
          FS.MkDir(d);
        handle FS.Error =>
        end;
      end;        
      wr:=File.OpenWr(d & "/" & f);

      if typename(v) = "list" then
        for e in v do 
          Wr.PutText(wr, text e & "\n");
        end;
      else      
        Wr.PutText(wr, text v & "\n");
      end;
      Wr.Flush(wr);
      Wr.Close(wr);
    handle File.Error =>
      Log("[Log.w]: File.Error greska:" & d & "/" & f);
    handle FS.Error =>
      Log("FS.Error greska");
    handle Wr.Error =>
      Log("Wr.Error greska");
    end;
  end w;




proc Say(rd, wr, cmd) =
  var
    line, i, x;
  begin
    Log(sprintf("===> OUT: '%s'", cmd));
    Wr.PutText(wr, cmd & "\r\n");
    Wr.Flush(wr);

    Rd.GetLine(rd); // Skip local echo

    i := 0;
    while i < 10 do
      while Rd.CharsReady(rd) > 0 do            
        line:=Rd.GetLine(rd);
        if line # '' then

//          x:=split(line, ",");
          //if size(x) > 3 then
//            w(".", "phonebook", sprintf("\n-%s %s-\n\n", x[2], x[4]));
//          end;
          Log(sprintf("<=== IN: '%s'", line));
        end;
      end;
      delay(0.1); 
      i := i + 1;
    end;
  end Say;

proc AddStats(key) =
  begin
    if not key in stats then
      stats:=stats + { key:={"poziva":=0, "zauzet":=0, "nedostupan":=0, "nejavlja":=0, "nemozedaodgovori":=0, "divert":=0 } };
    end;
  end AddStats;

proc GetTarget(i, nr) =
  begin
    if i < size(nr) then
      return nr[i+1];
    else
      return nr[1];
    end;  
  end GetTarget;

proc whereis(target, nr) =
  var
    i;
  begin
    for i:=1 to size(nr) do
      if nr[i] = target then
        return i;
      end;
    end;
    return 1;
  end whereis;


proc Call(rd, wr, nr, id) = 
  var
    i, line:="", target, e, z, brojpoziva:=0,
    vreme_s, vreme_z, vreme_f;
  begin
    target:=nr[1];

    while RADI = true do
      delay(3);
   
      brojpoziva:=brojpoziva + 1;
      if brojpoziva >= 5 then
        Say(rd, wr, "ATZ");
        brojpoziva:=0;
      end;
   
      AddStats(target);
      Log(sprintf("===> Dialing %s...", target));

      Log(sprintf("=== STATS ==="));
      for e,z in stats do
	Log(sprintf(" = Broj: %s =", e));
	Log(sprintf("   Poziva: [%d]", z.poziva));
	Log(sprintf("   Zauzet: [%d]", z.zauzet));
	Log(sprintf("   Divert: [%d]", z.divert));
	Log(sprintf("   Nedostupan: [%d]", z.nedostupan));
	Log(sprintf("   Ne javlja se: [%d]", z.nejavlja));
	Log(sprintf("   Ne moze da odgovori: [%d]", z.nemozedaodgovori));
	Log(sprintf(" ======================================================================="));
        save(stats, "./stats-" & id &".dat");
      end;

      Say(rd, wr, "ATDT " & target);
      stats[target].poziva:=stats[target].poziva + 1;          
 
      vreme_s:=number sprintf("%:0s", clock()); // vreme starta
      loop
        while 1 do           
          line:=Rd.GetLine(rd);
          if line # '' then
            Log(sprintf("<=== '%s'", line));
          end;
          if line = "BUSY" or line = "NO CARRIER" or line = "NO ANSWER" then
            vreme_z:=number sprintf("%:0s", clock());
            exit;
          end;
        end;
      end;


      vreme_f:=vreme_z - vreme_s;
      match(line) of
        | "NO ANSWER": 
            Log(sprintf("===> Pretplatnik %s se ne javlja!", target));
            stats[target].nejavlja:=stats[target].nejavlja + 1;
        | "BUSY": 
          // meta ostaje ista
          stats[target].zauzet:=stats[target].zauzet + 1;
        | "NO CARRIER": 
          if vreme_f > 40 then             // pretplatnik se ne javlja
            Log(sprintf("===> Pretplatnik %s se ne javlja!", target));
            stats[target].nejavlja:=stats[target].nejavlja + 1;
//            target:=nr[1]; 
          else                             // pretplatnik je nedostupan      
            if vreme_f >= 6 and vreme_f <= 10 then
              Log(sprintf("===> Pretplatnik %s ne podrzava data call pozive! %d", target, vreme_f));
              stats[target].nemozedaodgovori:=stats[target].nemozedaodgovori + 1;
              target:=GetTarget(whereis(target, nr), nr); // nedostupan
	    elsif vreme_f < 6 then
              Log(sprintf("===> Pretplatnik %s je uradio preusmeravanje! %d", target, vreme_f));
              stats[target].divert:=stats[target].divert + 1;
              target:=GetTarget(whereis(target, nr), nr); // nedostupan
            else
              Log(sprintf("===> Pretplatnik %s nedostupan [%ds], radim traceroute()!", target, vreme_f));
              stats[target].nedostupan:=stats[target].nedostupan + 1;
              target:=GetTarget(whereis(target, nr), nr); // nedostupan
            end;
          end;
      end;

    end;

  end Call;



proc Main(nr) =
  var
    device := "/dev/ttyACM0", id, i,
    ser, rd, wr, cfg, numbers;
  begin
    try
      id:=sprintf("%:0s", clock());
      printf("\n*** Vipa by dpanic@gmail.com ***\n");
      printf("********************************\n\n");

      printf("Otvaram uredjaj '%s'...\n", device);
      ser, rd, wr:=Serial.Open(device);
      printf("Uzimam konfiguraciju...\n");
      cfg:=Serial.GetConfig(ser);

      cfg.baud_rate:="BR38400";
      Serial.SetConfig(ser, cfg);
      cfg:=Serial.GetConfig(ser);
      printf("Baud rate: %s\n\n", cfg.baud_rate);
      
      Say(rd, wr, "AT S7=45 S0=0 L1 V1 X4 &c1 E1 Q0  ");
      Say(rd, wr, "ATI0");
      Say(rd, wr, "ATI1");
      Say(rd, wr, "ATI2");

      if nr = "phonebook" then

        Say(rd, wr, "at+mode=2");
        Say(rd, wr, "at+cpbs=\"AD\"");
        Say(rd, wr, "at+mpbr=?");
        for i:=1 to 500 do
          Say(rd, wr, "at+mpbr=" & i);
        end;
        delay(10000);
      end;

      numbers:=split(nr, ",");
      :$numbers$
      Call(rd, wr, numbers, id); 

      Serial.Close(ser);
      printf("Done.\n");
    handle Serial.Error => printf("Unable to open '%s'\n", device);
    handle Rd.Error => printf("Rd.Error\n");
    handle Rd.EndOfFile => printf("Rd.EndOfFile\n");
    handle Wr.Error => printf("Wr.Error\n");
    end;
  end Main;

begin
end Vipa.
