You are here

public function MerciDefaultController_non_inventory::bestFit in MERCI (Manage Equipment Reservations, Checkout and Inventory) 7.3

2 calls to MerciDefaultController_non_inventory::bestFit()
MerciDefaultController_non_inventory::fillBuckets in merci_core/reservation.handler.inc
MerciDefaultController_non_inventory::reservations in merci_core/reservation.handler.inc

File

merci_core/reservation.handler.inc, line 478
Abstraction of the selection logic of an entity reference field.

Class

MerciDefaultController_non_inventory
A null implementation of EntityReference_SelectionHandler.

Code

public function bestFit($dates) {
  $entity = $this->entity;
  $context = $this->context;
  $best_fit = array();
  $parent_conflicts = parent::conflicts($dates);
  $date_value = $dates['value'];
  foreach ($this->items as $delta => $item) {

    // No need to sort into buckets if there is nothing to sort into buckets.
    if (!array_key_exists($delta, $parent_conflicts) or !array_key_exists($date_value, $parent_conflicts[$delta])) {
      continue;
    }

    // Determine if the quantity field exists.  If so use it.
    try {
      $quantity = $item->{$context['quantity_field']}
        ->value();
    } catch (EntityMetadataWrapperException $e) {
      $quantity = 1;
    }

    // Split reservations based on quantity.
    $reservations = array();
    foreach ($parent_conflicts[$delta][$date_value] as $reservation) {
      for ($i = 0; $i < $reservation->quantity; $i++) {
        $reservations[] = $reservation;
      }
    }

    // Determine how many bucket items are needed for this time period.
    // Need to sort like this:
    //            .... time ....
    // item1  x x a a a x x x x x f x e e e x x x x x
    // item2  x x x d d d d d d x x x x c c c x x x x
    // item3  x x b b b b b b b b b b b b b x x x x x
    // etc ......
    //
    //      // Order by lenght of reservation descending.
    //      // Do first-fit algorythm.
    // Sort by length of reservation.
    uasort($reservations, array(
      $this,
      "merci_bucket_cmp_length",
    ));
    $buckets = array();

    // First-fit algorythm.
    foreach ($reservations as $test_reservation) {

      // Go through each bucket item to look for a available slot for this reservation.
      //
      // Find a bucket to use for this reservation.
      for ($i = 0; $i < $quantity; $i++) {
        $fits = TRUE;

        // Bucket already has other reservations we need to check against for a fit.
        if (array_key_exists($i, $buckets)) {
          foreach ($buckets[$i] as $reservation) {
            if ($this
              ->merci_bucket_intersects($reservation, $test_reservation)) {

              //Conflict so skip saving the reservation to this slot and try to use the next bucket item.
              $fits = FALSE;
              break;
            }
          }
        }

        // We've found a slot so test the next reservation.
        if ($fits) {
          if (array_key_exists($i, $buckets)) {
            $buckets[$i] = array();
          }
          $buckets[$i][] = $test_reservation;
          break;
        }
      }
    }
    if (count($buckets)) {
      $best_fit[$delta] = $buckets;
    }
  }
  return $best_fit;
}