/**
  * detach a single tag from records
  * 
  * @param array $recordIds
  * @param string $dirtyTagId
  * @param string $appId
  * @param Tinebase_Controller_Record_Abstract $controller
  */
 protected function _detachSingleTag($recordIds, $dirtyTagId, $appId, $controller)
 {
     $tag = $this->getTagsById($dirtyTagId, Tinebase_Model_TagRight::USE_RIGHT)->getFirstRecord();
     if (empty($tag)) {
         Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . ' No use right for tag, detaching not possible.');
         return;
     }
     $tagId = $tag->getId();
     $attachedIds = array();
     $select = $this->_db->select()->from(array('tagging' => SQL_TABLE_PREFIX . 'tagging'), 'record_id')->where($this->_db->quoteIdentifier('application_id') . ' = ?', $appId)->where($this->_db->quoteIdentifier('tag_id') . ' = ? ', $tagId)->where($this->_db->quoteInto($this->_db->quoteIdentifier('record_id') . ' IN (?)', $recordIds));
     Tinebase_Backend_Sql_Abstract::traitGroup($select);
     foreach ($this->_db->fetchAssoc($select) as $tagArray) {
         $attachedIds[] = $tagArray['record_id'];
     }
     if (empty($attachedIds)) {
         Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . ' There are no records we could detach the tag(s) from');
         return;
     }
     Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Detaching 1 Tag from ' . count($attachedIds) . ' records.');
     foreach ($attachedIds as $recordId) {
         $this->_db->delete(SQL_TABLE_PREFIX . 'tagging', array($this->_db->quoteIdentifier('tag_id') . ' = ?' => $tagId, $this->_db->quoteIdentifier('record_id') . ' = ?' => $recordId, $this->_db->quoteIdentifier('application_id') . ' = ?' => $appId));
     }
     $controller->concurrencyManagementAndModlogMultiple($attachedIds, array('tags' => array($tag->toArray())), array('tags' => array()));
     $this->_deleteOccurrence($tagId, count($attachedIds));
 }