OpenVeo Manage AngularJS back end

API Docs for: 1.0.0-alpha.0
Show:

File: app/client/admin/js/ovManage/GroupFactory.js

'use strict';

(function(app) {

  /**
   * Defines a factory to manage groups.
   *
   * @module ov.manage
   * @class GroupFactory
   */
  function GroupFactory($q,
                         $rootScope,
                         $timeout,
                         $filter,
                         DEVICE_STATUS,
                         MANAGEABLE_TYPES,
                         DeviceFactory,
                         ManageFactory,
                         ManageableFactory
                        ) {
    var TOTAL_PRESETS = 5;
    var groups = null;
    var presets = [];

    // Create presets for groups
    // Use preset id as preset name
    for (var i = 1; i < TOTAL_PRESETS + 1; i++)
      presets.push({id: String(i), name: String(i)});

    /**
     * Gets a group by its id.
     *
     * It implies that the list of groups has been retrieved
     * from server using GroupFactory.getGroups().
     *
     * @method getGroup
     * @param {String} id The group id
     * @return {Object|Null} The group or null if not found
     */
    function getGroup(id) {
      for (var i = 0; i < groups.length; i++)
        if (groups[i].id === id) return groups[i];

      return null;
    }

    /**
     * Updates status of a group regarding the status of its devices.
     *
     * @method updateStatus
     * @param {String} groupId The group id
     */
    function updateStatus(groupId) {
      var group = getGroup(groupId);

      if (group) {
        var groupReady = false;

        // If one device in the group is not able to start a session
        // mark the whole group as not able to start a session
        for (var i = 0; i < group.devices.length; i++) {

          // Update device status
          var device = group.devices[i];

          switch (device.status) {
            case DEVICE_STATUS.ERROR:
              group.statusMessage = 'MANAGE.STATUS.ERROR';
              group.status = DEVICE_STATUS.ERROR;
              return;
            case DEVICE_STATUS.STARTED:
            case DEVICE_STATUS.STOPPING:
              group.statusMessage = 'MANAGE.STATUS.RECORDING';
              group.status = DEVICE_STATUS.STARTED;
              return;
            case DEVICE_STATUS.STARTING:
              group.statusMessage = 'MANAGE.STATUS.STARTING';
              group.status = DEVICE_STATUS.STARTING;
              return;
            default:
              if (device.status == DEVICE_STATUS.STOPPED)
                groupReady = true;
          }
        }

        if (groupReady) {

          // All devices in the group are not in error, started or starting state
          // and at least one device is stopped
          group.statusMessage = 'MANAGE.STATUS.READY';
          group.status = DEVICE_STATUS.STOPPED;

        } else {

          // No devices connected
          group.statusMessage = 'MANAGE.STATUS.DISCONNECTED';
          group.status = DEVICE_STATUS.DISCONNECTED;

        }
      }
    }

    /**
     * Adds a group historic.
     *
     * @method addHistoric
     * @param {String} id The group id
     * @param {Object} historic The historic
     */
    function addHistoric(id, historic) {
      var group = getGroup(id);
      ManageableFactory.addHistoric(group, historic);
    }

    /**
     * Adds a group schedule.
     *
     * @method addSchedule
     * @param {String} id The group id
     * @param {Object} schedule The schedule
     */
    function addSchedule(id, schedule) {
      var group = getGroup(id);
      ManageableFactory.addSchedule(group, schedule);
    }

    /**
     * Removes a group historic.
     *
     * @method removeHistoric
     * @param {String} id The group id
     * @param {String} historicId The historic id
     */
    function removeHistoric(id, historicId) {
      var group = getGroup(id);
      ManageableFactory.removeHistoric(group, historicId);
    }

    /**
     * Removes a device's history.
     *
     * @method removeHistory
     * @param {String} id The device id
     */
    function removeHistory(id) {
      var group = getGroup(id);
      ManageableFactory.removeHistory(group);
    }

    /**
     * Removes a group schedule.
     *
     * @method removeSchedule
     * @param {String} groupId The group id
     * @param {String} scheduleId The schedule id
     */
    function removeSchedule(groupId, scheduleId) {
      var group = getGroup(groupId);
      ManageableFactory.removeSchedule(group, scheduleId);
    }

    /**
     * Gets a device from a group.
     *
     * @method getDeviceFromGroup
     * @param {String} deviceId The id of the device
     * @param {String} groupId The id of the group
     * @return {Object|Null} The device or null if not found
     */
    function getDeviceFromGroup(deviceId, groupId) {
      var group = getGroup(groupId);

      if (group) {
        for (var i = 0; i < group.devices.length; i++)
          if (group.devices[i].id === deviceId) return group.devices[i];
      }

      return null;
    }

    /**
     * Adds a device to a group.
     *
     * @method addDeviceToGroup
     * @param {Object} device The device to add to the group
     * @param {String} groupId The id of the group
     */
    function addDeviceToGroup(device, groupId) {
      if (device && groupId) {
        var group = getGroup(groupId);
        var existingDevice = getDeviceFromGroup(device.id, groupId);

        if (!existingDevice) {
          device.group = groupId;

          if (!group.devices)
            group.devices = [];

          group.devices.push(device);
          updateStatus(group.id);
        }

      }
    }

    /**
     * Adds a new group.
     *
     * @method addGroup
     * @param {Object} group The new group description object
     */
    function addGroup(group) {
      if (!getGroup(group.id)) {
        var history = group.history;
        group.type = MANAGEABLE_TYPES.GROUP;
        group.devices = [];
        group.history = [];
        group.inputs = {};
        group.presets = presets;
        groups.push(group);

        history.forEach(function(historic) {
          addHistoric(group.id, historic);
        });

        updateStatus(group.id);
      }
    }

    /**
     * Gets all groups of devices from server.
     *
     * @method getGroups
     * @return {Promise} A promise resolving with the list of groups
     */
    function getGroups() {
      var p = $q.defer();

      if (!groups) {
        ManageFactory.getGroups().then(function(newGroups) {
          groups = [];

          newGroups.forEach(function(group) {
            addGroup(group);
          });

          p.resolve(groups);
        }, function(error) {
          p.reject(error);
        });
      } else
        p.resolve(groups);

      return p.promise;
    }

    /**
     * Adds devices to their respecting group.
     *
     * It uses the group property of each device
     *
     * @method addDevices
     * @param {Array} devices The list of devices
     */
    function addDevices(devices) {
      if (groups && devices) {

        // Iterate through devices
        for (var i in devices) {
          var deviceGroupId = devices[i].group;

          // Iterate through groups
          for (var j in groups) {

            if (groups[j].id === deviceGroupId) {

              // Found device's group
              // Add device to the group
              addDeviceToGroup(devices[i], groups[j].id);
              break;

            }
          }
        }
      }
    }

    /**
     * Sets a property on all groups.
     *
     * @method setGroupsProperty
     * @param {String} property The name of the property to set
     * @param {Mixed} value The value for the property
     */
    function setGroupsProperty(property, value) {
      groups.forEach(function(group) {
        group[property] = value;
      });
    }

    /**
     * Removes a group.
     *
     * @method removeGroup
     * @param {String} id The group id
     */
    function removeGroup(id) {
      var groupIndex = -1;
      var group = null;
      for (var i = 0; i < groups.length; i++) {
        if (groups[i].id === id) {
          groupIndex = i;
          group = groups[i];
          break;
        }
      }

      // Remove devices from group
      if (group) {
        group.devices.forEach(function(device) {
          delete device.group;
        });
      }

      // Remove group
      if (groupIndex !== -1)
        groups.splice(groupIndex, 1);
    }

    /**
     * Updates a group property.
     *
     * @method setProperty
     * @param {String} id The group id
     * @param {String} property The property to modify
     * @param {Mixed} value The property value
     */
    function setProperty(id, property, value) {
      var group = getGroup(id);

      if (group)
        group[property] = value;
    }

    /**
     * Removes a device from a group.
     *
     * @method removeDeviceFromGroup
     * @param {Object} device The device to remove
     * @param {String} groupId The group id
     */
    function removeDeviceFromGroup(device, groupId) {
      var group = getGroup(groupId),
        deviceIndex = -1;

      if (device && group) {
        for (var i = 0; i < group.devices.length; i++) {
          if (group.devices[i].id === device.id) {
            deviceIndex = i;
            break;
          }
        }

        if (deviceIndex !== -1)
          group.devices.splice(deviceIndex, 1);

        delete device.group;
      }
    }

    /**
     * Validates a preset confronting group's devices' available inputs.
     *
     * If one of the devices has invalid inputs regarding the preset, preset
     * is considered invalid.
     *
     * @method validatePreset
     * @param {String} groupId The group id
     * @param {String} presetId The preset id
     */
    function validatePreset(groupId, presetId) {
      var group = getGroup(groupId);

      if (group) {
        var devicesInError = [];

        group.devices.forEach(function(device) {
          DeviceFactory.validatePreset(device.id, presetId);

          if (device.inputs.error)
            devicesInError.push($filter('translate')(device.name));
        });

        if (devicesInError.length) {
          group.inputs.error = $filter('translate')('MANAGE.GROUP.PRESET_INPUTS_ERROR', null, {
            devices: devicesInError.join(', ')
          });
        } else
          group.inputs.error = null;

      }

    }

    /**
     * Checks if a schedule is not in collision with other schedules.
     *
     * Group's schedule should not be in collision with devices' schedule inside the group.
     *
     * @method isValidSchedule
     * @param {String} id The group id
     * @param {Object} schedule The schedule to validate
     * @return {Error|Null} The error if validation failed, null otherwise
     */
    function isValidSchedule(id, schedule) {
      var group = getGroup(id);

      if (group) {
        var validationError = ManageableFactory.isValidSchedule(schedule, group.schedules);
        if (validationError) return validationError;

        var devicesInConflict = [];

        // Validates that the new schedule is not in conflict with one of the
        // schedules in group's devices
        for (var i = 0; i < group.devices.length; i++) {
          var device = group.devices[i];
          var isConflict = false;

          for (var j = 0; j < device.schedules.length; j++) {
            if (ManageableFactory.checkSchedulesConflict(device.schedules[j], schedule)) {
              isConflict = true;
              break;
            }
          }

          if (isConflict)
            devicesInConflict.push($filter('translate')(device.name));

        }

        if (devicesInConflict.length) {
          return new Error($filter('translate')('MANAGE.MANAGEABLE.GROUP_DEVICES_CONFLICT_ERROR', null, {
            devices: devicesInConflict.join(', ')
          }));
        }
      }

      return null;
    }

    return {
      getGroups: getGroups,
      addDevices: addDevices,
      getGroup: getGroup,
      addGroup: addGroup,
      removeGroup: removeGroup,
      setGroupsProperty: setGroupsProperty,
      setProperty: setProperty,
      addDeviceToGroup: addDeviceToGroup,
      removeDeviceFromGroup: removeDeviceFromGroup,
      addHistoric: addHistoric,
      addSchedule: addSchedule,
      removeHistoric: removeHistoric,
      removeHistory: removeHistory,
      removeSchedule: removeSchedule,
      updateStatus: updateStatus,
      validatePreset: validatePreset,
      isValidSchedule: isValidSchedule
    };

  }

  app.factory('ManageGroupFactory', GroupFactory);
  GroupFactory.$inject = [
    '$q',
    '$rootScope',
    '$timeout',
    '$filter',
    'MANAGE_DEVICE_STATUS',
    'MANAGE_MANAGEABLE_TYPES',
    'ManageDeviceFactory',
    'ManageFactory',
    'ManageManageableFactory'
  ];

})(angular.module('ov.manage'));