﻿/*
 Automatic Profile Changer for m-shell
 Copyleft Ales Janda, KYBLSoft 2008
 More on www.kyblsoft.cz/mobil
 It's GNU GPL software - enjoy it ;-)
*/


use app,files,math,phone,sms,time,ui;

 // setting of times when should be set silent profile. Set it as you need, below is example
.timesoff=[
  ['from': 22, 'to': 7],              // every day from 22 h to 7 h
  ['from': 7, 'to': 10.30, 'days': [2,5,6,7,10], 'towakeup': true],  // in Tuesday, Friday, weekend and special day with id 10 - silent from 7 h at morning to human wake up, or to 10:30
  ['from': 9.15, 'to': 10.50, 'days': [1,3,4]],  // in Monday, Wednesday and Thursday silent from 9:15 to 10:50
  ['from': 11, 'to': 12.35, 'days': [3,4]],   //etc...
  ['from': 12.45, 'to': 15.05, 'days': [1]],
  ['from': 12.45, 'to': 14.20, 'days': [2,4]],
  ['from': 14.30, 'to': 16.05, 'days': [3]],
  ['from': 16.15, 'to': 17.50, 'days': [3]],
  ['from': 18.00, 'to': 19.25, 'days': [2,3,4]],
  ['from': 18.08, 'to': 19.45, 'days': [1]]
];

// setting of special days, i.e. set behavior not according to day in week but day in year.
// Normally, these special days should have other numbers than 1 - 7. Or you can define some special day with id from range 1 - 7 for cases as "this Thursday I have program the same as I usually have in Wednesday"
.specialdays=['10': ['1405',    // define National Days in format DDMM (see .dateformat below)
'0101','0105','0805','2810','1711','2312','2412','2512','2612','2712','2812','2912','3012','3112']];

.idletime=15;
.dateformat='DDMM';


function ConvertNumberToTime(hour)
//9.5 -> 9:30
  
  hr=math.floor(hour);
  mnt=hour-hr;
  mnt=str(math.floor(mnt*60));
  if len(mnt) = 1 then
    mnt='0'+mnt;
  end;
  return hr+':'+mnt;
end;

function ConvertTimeToNumber(hour)
//9:30 (9.30) => 9.5
  
  hr=math.floor(hour);
  mnt=hour-hr;
  return hr+mnt/60*100;
end;

function ConvertTimesToNumbers(timesoff)
//9:30 (9.30) => 9.5

  for i=0 to len(timesoff)-1 do
    timesoff[i]['from']=ConvertTimeToNumber(timesoff[i]['from']);
    timesoff[i]['to']=ConvertTimeToNumber(timesoff[i]['to']);
  end;
end;

function ConvertSpecialsDays(specialdays)
  ret=[];
  daysnumbers=keys(specialdays);

  for i=0 to len(specialdays)-1 do
    daynumber=daysnumbers[i];
    for day in specialdays[daynumber] do
      ret[day]=daynumber;
    end;
  end;

  return ret;
end;

function IsSoundOff()
  return files.exists('C:\\Shared\\silentmode.txt');
end;

function IsUserWakedUp()
//user waked up when no new message is received
//(there must some message be received in night, otherwise it won't work

  while true do
    try
      messages=sms.inbox();
      new=sms.get(messages[len(messages)-1])['unread'];
      return not new;
    catch e by
      sleep(500);
    end;
  end;
end;

function TurnSoundOnOrOff()
  app.show(270555829);  //GDesk
  sleep(1000);
  app.key([25,-25]);   //"wake up" phone
  sleep(2000);
  app.key([167,-167]); //close info about new messages, calls etc.
  sleep(2000);
  app.key([69,-69]);   //e
  sleep(2000);
  app.key(15);    //#
  sleep(1000);
  app.key(-15);   //hold off #
  sleep(3000);
  app.show(3890268855);  //m-shell
end;

function TurnStateAndReturnTurningLength(sound)
  starttime=time.get();

  attempts=0;
  while sound = IsSoundOff() and attempts < 10 do
    attempts++;

    if sound then
      print time.str(time.get(),'hh:mm:ss')+' Turning on...';
    else
      print time.str(time.get(),'hh:mm:ss')+' Turning on...';
    end;

    phone.state(phone.idle);

    while ui.idletime() < .idletime*1000 do
      sleep(.idletime*1000-ui.idletime());
      phone.state(phone.idle);
    end;

    TurnSoundOnOrOff();

  end;

  return (time.get()-starttime)/60/60;
end;

function GetTimeTo(hournow,tohour)
  if hournow <= tohour then
    return tohour-hournow;
  else
    return 24-hournow+tohour;
  end;
end;

function TestCas(timeoff,day,hour)

  //check of day
  if timeoff['days'] # null then
    ok=false;
    for d in timeoff['days'] do
      if d = day then
        ok=true;
        break;
      end;
    end;
    if not ok then
      return ['state': true, 'validto': GetTimeTo(hour,24), 'towakeup': false];
    end;
  end;

  //check of hour
  if timeoff['from'] < timeoff['to'] then
    if hour >= timeoff['from'] and hour < timeoff['to'] then
      return ['state': false, 'validto': GetTimeTo(hour,timeoff['to']), 'towakeup': timeoff['towakeup']];
    else
      return ['state': true, 'validto': GetTimeTo(hour,timeoff['from']), 'towakeup': timeoff['towakeup']];
    end;
  else
    if hour >= timeoff['from'] or hour < timeoff['to'] then
      return ['state': false, 'validto': GetTimeTo(hour,timeoff['to']), 'towakeup': timeoff['towakeup']];
    else
      return ['state': true, 'validto': GetTimeTo(hour,timeoff['from']), 'towakeup': timeoff['towakeup']];
    end;
  end;
end;

function GetNextAction(timesoff,day,hour)
  wait=24*60*60;
  sound=true;
  towakeup=false;

  for timeoff in timesoff do
    state=TestCas(timeoff,day,hour);
    if state['validto'] < wait then
      wait=state['validto'];
    end;
    if not state['state'] then
      if state['towakeup'] = true then
        if not IsUserWakedUp() then
                //so condition is valid
          sound=false;
          towakeup=true;
        end;
      else
        sound=false;
      end;
    end;
  end;

  return ['state': sound,'wait': wait,'towakeup': towakeup];
end;

function WaitForTime(hours)
  while hours > 0 do
    wait=hours;

    if wait > 0.4 then
      wait=0.4;
    end;

    sleep(wait*60*60*1000);
    hours-=wait;
  end;
  sleep(100);  //because rounding error
end;

function WaitForTimeToWakeUp(hours)
  while hours > 0 do
    if IsUserWakedUp() then
      break;
    end;

    wait=hours;

    if wait > 0.03 then //1,5 minuts
      wait=0.03;
    end;

    sleep(wait*60*60*1000);
    hours-=wait;
  end;
  sleep(100);  //because rounding error
end;

function GetDayNumber(timenum,specialdays)
 //returns num of special day or day in week

  day=time.str(timenum,.dateformat);
  if specialdays[day] # null then
    return num(specialdays[day]);
  else
    return time.dayofweek(timenum)+1;
  end;
end;

ConvertTimesToNumbers(.timesoff);
specialdays=ConvertSpecialsDays(.specialdays);

while true do
  timenum=time.get();
  day=GetDayNumber(timenum,specialdays);
  hour=num(time.str(timenum,'hh'));
  hour+=num(time.str(timenum,'mm'))/60;
  hour+=num(time.str(timenum,'ss'))/3600;

  action=GetNextAction(timesoff,day,hour);

  action['wait']-=TurnStateAndReturnTurningLength(action['state']);
  if action['wait'] > 0 then
             //muze byt uz lehce pod
    message=time.str(time.get(),'hh:mm:ss')+' Waiting '+ConvertNumberToTime(action['wait'])+' hr';
    if action['towakeup'] then
      print message+' to wake up';
      WaitForTimeToWakeUp(action['wait']);
    else
      print message;
      WaitForTime(action['wait']);
    end;
  end;
end;