/**
  * Return true or false as to whether a given user can access an object
  * 
  * @param DataObject $node
  *			The object to check perms on
  * @param string $perm
  *			The permission to check against
  * @param Member $member 
  *			The member to check - if not set, the current user is used
  * 
  * @return type 
  */
 public function checkPerm(DataObject $node, $perm, $member = null)
 {
     // if the node doesn't use the extension, fall back to SS logic
     if (!$node->hasExtension('Restrictable')) {
         switch ($perm) {
             case 'View':
                 return $node->canView($member);
             case 'Write':
                 return $node->canEdit($member);
             default:
                 return $node->can($perm, $member);
         }
     }
     if (!$node) {
         return false;
     }
     if (!$member) {
         $member = singleton('SecurityContext')->getMember();
     }
     if (is_int($member)) {
         $member = DataObject::get_by_id('Member', $member);
     }
     if (Permission::check('ADMIN', 'any', $member)) {
         return true;
     }
     $permCache = $this->getCache();
     /* @var $permCache Zend_Cache_Core */
     $key = $this->permCacheKey($node, $perm);
     $userGrants = null;
     if ($key) {
         $userGrants = $permCache->load($key);
         if (count($userGrants)) {
             $userGrants = $this->sanitiseCacheData($userGrants);
         }
     }
     if ($member && $userGrants && isset($userGrants[$perm][$member->ID])) {
         return $userGrants[$perm][$member->ID];
     }
     // okay, we need to build up all the info we have about the node for permissions
     $s = $this->realiseAllSources($node);
     if (!$userGrants) {
         $userGrants = array();
     }
     if (!isset($userGrants[$perm])) {
         $userGrants[$perm] = array();
     }
     $result = null;
     // if no member, just check public view
     $public = $this->checkPublicPerms($node, $perm);
     if ($public) {
         $result = true;
     }
     // can return immediately
     if (!$member) {
         return $result;
     }
     if (is_null($result)) {
         // see whether we're the owner, and if the perm we're checking is in that list
         if ($this->checkOwnerPerms($node, $perm, $member)) {
             $result = true;
         }
     }
     $accessAuthority = '';
     $directGrant = null;
     $can = false;
     if (is_null($result)) {
         $filter = array('ItemID' => $node->ID, 'ItemType' => $node->class);
         $existing = DataList::create('AccessAuthority')->filter($filter);
         // get all access authorities for this object
         $gids = isset($this->groups[$member->ID]) ? $this->groups[$member->ID] : null;
         if (!$gids) {
             $groups = $member ? $member->Groups() : array();
             $gids = array();
             if ($groups && $groups->Count()) {
                 $gids = $groups->map('ID', 'ID')->toArray();
             }
             $this->groups[$member->ID] = $gids;
         }
         $can = false;
         $directGrant = 'NONE';
         if ($existing && $existing->count()) {
             foreach ($existing as $access) {
                 // check if this mentions the perm in question
                 $perms = $access->Perms->getValues();
                 if ($perms) {
                     if (!in_array($perm, $perms)) {
                         continue;
                     }
                 }
                 $grant = null;
                 $authority = $access->getAuthority();
                 if ($authority instanceof Group) {
                     if (isset($gids[$access->AuthorityID])) {
                         $grant = $access->Grant;
                     }
                 } elseif ($authority instanceof Member) {
                     if ($member->ID == $access->AuthorityID) {
                         $grant = $access->Grant;
                     }
                 } else {
                     // another mechanism that will require a lookup of members in a list
                     // TODO cache this
                     if ($authority instanceof ListOfMembers) {
                         $listMembers = $authority->getAllMembers()->map('ID', 'Title');
                         if (isset($listMembers[$member->ID])) {
                             $grant = $access->Grant;
                         }
                     }
                 }
                 if ($grant) {
                     // if it's deny, we can just break away immediately, otherwise we need to evaluate all the
                     // others in case there's another DENY in there somewhere
                     if ($grant === 'DENY') {
                         $directGrant = 'DENY';
                         // immediately break
                         break;
                     } else {
                         // mark that it's been granted for now
                         $directGrant = 'GRANT';
                     }
                 }
             }
         }
     }
     // return immediately if we have something
     if ($directGrant === 'GRANT') {
         $result = true;
     }
     if ($directGrant === 'DENY') {
         $result = false;
     }
     // otherwise query our parents
     if (is_null($result) && $node->InheritPerms) {
         $permParents = $this->getEffectiveParents($node);
         if (count($permParents) || $permParents instanceof IteratorAggregate) {
             foreach ($permParents as $permParent) {
                 if ($permParent && $this->checkPerm($permParent, $perm, $member)) {
                     $result = true;
                 }
             }
         }
     }
     if (is_null($result)) {
         $result = false;
     }
     $userGrants[$perm][$member->ID] = $result;
     if ($key) {
         $permCache->save($userGrants, $key);
     }
     return $result;
 }