
(function() {
  var updateIntervalId = null;

  function simpleObject(obj, props) {
    var result = {};
    for(var i = 0; i < props.length; i++) {
      if(obj[props[i]]) result[props[i]] = obj[props[i]];
    }
    return result;
  }

  function onceThenRepeat(fn, delay, interval) {
    setTimeout(fn, delay);
    return setInterval(fn, interval);
  }

  // Provides device information (e.g. battery, screen)
  var DeviceInfo = (function() {
    var info = {};

    function getBattery(cb) {
      if(navigator.getBattery) {
        var promise = navigator.getBattery();
        if(promise && promise.then) {
          return promise.then(cb);
        }
      }

      cb(navigator.battery || navigator.webkitBattery || navigator.mozBattery || navigator.msBattery);
    }

    function updateInfo() {
      if(window.screen) {
        info.screen = simpleObject(window.screen, [ 'width', 'height' ]);
      }

      getBattery(function(battery) {
        if(battery) {
          info.battery = simpleObject(battery, [ 'level', 'charging' ]);
        }
      });
    }

    return {
      update: updateInfo,
      current: info
    };
  })();

  // Manages simulation
  var Simulation = (function() {
    var simId, tasks, taskIndex, cleanup, simStart;

    // Starts a new simulation
    function startSimulation(id, newTasks) {
      simId = id;
      tasks = newTasks;

      simStart = new Date();

      taskIndex = -1;
      nextTask();
    }

    // Starts the next task
    function nextTask() {
      if(++taskIndex >= tasks.length) {
        taskIndex = 0;
      }

      if(typeof cleanup == 'function') {
        cleanup();
      }

      var task = tasks[taskIndex];

      console.log(task);

      switch(task.type) {
        case 'website':
          $('<iframe>', {
            src: task.url,
            id: 'website-sim-frame',
            frameborder: 0,
            width: '100%',
            height: $(window).height() + 'px'
          }).appendTo('body');

          cleanup = function() {
            $('#website-sim-frame').remove();
          };

          setTimeout(nextTask, parseInt(task.duration) * 1000);
          break;
        case 'page':
          var url = '/assets/page/' + (task.page || 'average') + '/';
          $('<iframe>', {
            src: url,
            id: 'website-sim-frame',
            frameborder: 0,
            width: '100%',
            height: $(window).height() + 'px'
          }).appendTo('body');

          cleanup = function() {
            $('#website-sim-frame').remove();
          }

          setTimeout(nextTask, parseInt(task.duration) * 1000);
          break;
        default:
          // TODO: Implement
          reportProblem('Simulation failed due to unknown task type: ' + task.type);
      }
    }

    // Returns the simulation status
    function getStatus() {
      if(simId != null) {
        return {
          running: true,
          id: simId,
          currentTask: taskIndex,
          time: new Date() - simStart
        };
      } else {
        return { running: false };
      }
    }

    return {
      start: startSimulation,
      status: getStatus
    };
  })();

  // Handles server communication
  function requestUpdate() {
    var data = {
      info: DeviceInfo.current,
      simulation: Simulation.status()
    };

    $.ajax({
      type: 'POST',
      url: '/request-update',
      data: JSON.stringify(data),
      contentType: 'application/json; charset=utf-8',
      dataType: 'json',
      success: function(data, textStatus, jqXHR) {
        // Change update interval if necessary
        if(data.updateInterval && data.updateInterval != updateInterval) {
          clearInterval(updateIntervalId);
          updateInterval = data.updateInterval;
          updateIntervalId = setInterval(requestUpdate, updateInterval);
        }

        // Start simulation
        if(data.startSimulation && data.startSimulation.id && data.startSimulation.tasks) {
          Simulation.start(data.startSimulation.id, data.startSimulation.tasks);
        }
      }
    });
  }

  // Periodically update device information
  onceThenRepeat(DeviceInfo.update, 1000, 20000);

  // Start requesting updates from the server
  updateIntervalId = setInterval(requestUpdate, updateInterval);
})();
