/**
  * Process bulk add/remove/etc operations
  *
  * @param Bin    $rec
  * @param string $bulk_op
  * @param array  $data
  * @param string $notes
  */
 protected function run_bulk($rec, $bulk_op, $data, $notes = null)
 {
     // check for write-authz on bin (for everything EXCEPT random)
     if ($bulk_op != 'bulk_random' && !$rec->user_may_write($this->user)) {
         $msg = "Insufficient authz for {$bulk_op}";
         throw new Rframe_Exception(Rframe::BAD_AUTHZ, $msg);
     }
     $this->bulk_op = $bulk_op;
     // rethrow any exceptions as 'data' exceptions
     try {
         if ($bulk_op == 'bulk_add') {
             $this->bulk_rs = AIR2Bin::add_sources($rec, $data, $notes);
         }
         if ($bulk_op == 'bulk_addsub') {
             $this->bulk_rs = AIR2Bin::add_submissions($rec, $data, $notes);
         }
         if ($bulk_op == 'bulk_addsearch') {
             $this->bulk_rs = AIR2Bin::add_search($this->user, $rec, $data, $notes);
         }
         if ($bulk_op == 'bulk_addtank') {
             $tanks = array();
             $data = is_array($data) ? array_unique($data) : array($data);
             foreach ($data as $uuid) {
                 $t = AIR2_Record::find('Tank', $uuid);
                 if (!$t) {
                     throw new Exception("Invalid tank_uuid({$uuid})");
                 }
                 $tanks[] = $t;
             }
             foreach ($tanks as $t) {
                 $counts = AIR2Bin::add_tank($rec, $t, $notes);
                 foreach ($counts as $key => $val) {
                     if (!isset($this->bulk_rs[$key])) {
                         $this->bulk_rs[$key] = 0;
                     }
                     $this->bulk_rs[$key] += $counts[$key];
                 }
             }
         }
         if ($bulk_op == 'bulk_addbin') {
             $bins = array();
             $data = is_array($data) ? array_unique($data) : array($data);
             foreach ($data as $uuid) {
                 $b = AIR2_Record::find('Bin', $uuid);
                 if (!$b) {
                     throw new Exception("Invalid bin_uuid({$uuid})");
                 }
                 if (!$b->user_may_read($this->user)) {
                     throw new Exception("Invalid bin_uuid({$uuid})");
                 }
                 $bins[] = $b;
             }
             foreach ($bins as $b) {
                 $counts = AIR2Bin::add_bin($rec, $b, $notes);
                 foreach ($counts as $key => $val) {
                     if (!isset($this->bulk_rs[$key])) {
                         $this->bulk_rs[$key] = 0;
                     }
                     $this->bulk_rs[$key] += $counts[$key];
                 }
             }
         }
         if ($bulk_op == 'bulk_remove') {
             $this->bulk_rs = AIR2Bin::remove_sources($rec, $data);
         }
         if ($bulk_op == 'bulk_removeall') {
             $this->bulk_rs = AIR2Bin::remove_all_sources($rec, $data);
         }
         if ($bulk_op == 'bulk_random') {
             $this->bulk_rs = AIR2Bin::randomize($this->user, $rec, $data);
         }
         if ($bulk_op == 'bulk_tag') {
             $this->bulk_rs = AIR2Bin::tag_sources($this->user, $rec, $data);
         }
         if ($bulk_op == 'bulk_annot') {
             $this->bulk_rs = AIR2Bin::annotate_sources($this->user, $rec, $data);
         }
     } catch (Rframe_Exception $e) {
         throw $e;
         //re-throw as-is
     } catch (Exception $e) {
         throw new Rframe_Exception(Rframe::BAD_DATA, $e->getMessage());
     }
 }