text: <?php
  
  namespace Minds\Core\Comments;
  
  use Minds\Core\Guid;
  use Minds\Core\Luid;
  use Minds\Core\Security\ACL;
  use Minds\Entities\RepositoryEntity;
  use Minds\Entities\User;
  use Minds\Helpers\Flags;
  use Minds\Helpers\Unknown;
  use Minds\Helpers\Export;
  use Minds\Core\Di\Di;
  
  /**
   * Comment Entity
   * @package Minds\Core\Comments
   * @method Comment setEntityGuid(int $value)
   * @method Comment setParentGuidL1(int $value)
   * @method int getParentGuidL1()
   * @method Comment setParentGuidL2(int $value)
   * @method int getParentGuidL2()
   * @method Comment setGuid(int $value)
   * @method Comment setRepliesCount(int $value)
   * @method int getRepliesCount())
   * @method Comment setOwnerGuid(int $value)
   * @method int getOwnerGuid()
   * @method Comment setTimeCreated(int $value)
   * @method int getTimeCreated()
   * @method Comment setTimeUpdated(int $value)
   * @method int getTimeUpdated()
   * @method Comment setBody(string $value)
   * @method Comment setAttachments(array $value)
   * @method array getAttachments()
   * @method Comment setMature(bool $value)
   * @method bool isMature()
   * @method Comment setEdited(bool $value)
   * @method bool isEdited()
   * @method Comment setSpam(bool $value)
   * @method bool isSpam()
   * @method Comment setDeleted(bool $value)
   * @method bool isDeleted()
   * @method Comment setVotesUp(array $value)
   * @method array getVotesUp()
   * @method Comment setVotesDown(array $value)
   * @method array getVotesDown()
   * @method Comment setEphemeral(bool $value)
   * @method bool isEphemeral()
   */
  class Comment extends RepositoryEntity
  {
      /** @var string */
      protected $type = 'comment';
  
      /** @var int */
      protected $entityGuid;
  
      /** @var int */
      protected $parentGuidL1;
  
      /** @var int */
      protected $parentGuidL2;
  
      /** @var int */
      protected $parentGuidL3 = 0; // Not supported yet
  
      /** @var int */
      protected $guid;
  
      /** @var int */
      protected $repliesCount = 0;
  
      /** @var int */
      protected $ownerGuid;
  
      /** @var int */
      protected $timeCreated;
  
      /** @var int */
      protected $timeUpdated;
  
      /** @var string */
      protected $body;
  
      /** @var array */
      protected $attachments = [];
  
      /** @var bool */
      protected $mature = false;
  
      /** @var bool */
      protected $edited = false;
  
      /** @var bool */
      protected $spam = false;
  
      /** @var bool */
      protected $deleted = false;
  
      /** @var array */
      protected $ownerObj;
  
      /** @var array */
      protected $votesUp;
  
      /** @var array */
      protected $votesDown;
  
      /** @var bool */
      protected $groupConversation = false;
  
      /** @var bool */
      protected $ephemeral = true;
  
      /**
       * Gets the entity guid for the comment.
       * !!!NOTE!!! Needed for 'create' event hook
       * @return int
       */
      public function getEntityGuid()
      {
          return $this->entityGuid;
      }
  
      /**
       * @return Luid
       * @throws \Minds\Exceptions\InvalidLuidException
       */
      public function getLuid()
      {
          $luid = new Luid();
  
          $luid
              ->setType('comment')
              ->setEntityGuid((string) $this->getEntityGuid())
              ->setPartitionPath($this->getPartitionPath())
              ->setParentPath($this->getParentPath())
              ->setChildPath($this->getChildPath())
              ->setGuid((string) $this->getGuid());
  
          return $luid;
      }
  
      /**
       * @return int
       */
      public function getGuid()
      {
          if (!$this->guid) {
              $this->setGuid(Guid::build());
          }
  
          return $this->guid;
      }
  
      /**
       * @param array|string $value
       * @return $this
       */
      public function setOwnerObj($value)
      {
          if (is_string($value) && $value) {
              $value = json_decode($value, true);
          } elseif ($value instanceof User) {
              $value = $value->export();
          }
  
          $this->ownerObj = $value;
          $this->markAsDirty('ownerObj');
  
          if ($value && !$this->ownerGuid) {
              $this->ownerGuid = $value['guid'];
              $this->markAsDirty('ownerGuid');
          }
  
          return $this;
      }
  
      /**
       * Gets (hydrates if necessary) the owner object
       * @return array
       * @throws \Exception
       */
      public function getOwnerObj()
      {
          if (!$this->ownerObj && $this->ownerGuid) {
              $user = new User($this->ownerGuid);
              $user->fullExport = false;
              $this->setOwnerObj($user->export());
          }
  
          return $this->ownerObj;
      }
  
      /**
       * @return string
       */
      public function getBody()
      {
          if (strlen($this->body) > 1500) {
              return substr($this->body, 0, 1500) . '...';
          }
          return $this->body;
      }
  
      /**
       * Sets an individual attachment
       * @param $attachment
       * @param mixed $value
       * @return Comment
       */
      public function setAttachment($attachment, $value)
      {
          if (is_array($value) || is_object($value)) {
              $value = json_encode($value);
          }
  
          $this->attachments[$attachment] = (string) $value;
          $this->markAsDirty('attachments');
  
          return $this;
      }
  
      /**
       * Gets an individual attachment's value
       * @param $attachment
       * @return bool
       */
      public function getAttachment($attachment)
      {
          if (!isset($this->attachments[$attachment])) {
              return false;
          }
  
          if (in_array(substr($this->attachments[$attachment], 0, 1), ['[', '{'], true)) {
              return json_decode($this->attachments[$attachment], true);
          }
  
          return $this->attachments[$attachment];
      }
  
      /**
       * Returns if the entity can be edited
       * @param User|null $user
       * @return bool
       */
      public function canEdit(User $user = null)
      {
          return ACL::_()->write($this, $user);
      }
  
      /**
       * Get exact path, includes all the partition
       * @return string
       */
      public function getPartitionPath()
      {
          return "{$this->getParentGuidL1()}:{$this->getParentGuidL2()}:{$this->getParentGuidL3()}";
      }
  
      /**
       * Return the partition path of the parent
       * that can be used to grab the parent thread
       * @return string
       */
      public function getParentPath()
      {
          if ($this->getParentGuidL2() == 0) {
              return "0:0:0";
          }
          return "{$this->getParentGuidL1()}:0:0";
      }
  
      /**
       * Return the partition path to be used to
       * fetch child replies
       */
      public function getChildPath()
      {
          if ($this->getParentGuidL1() == 0) { //No parent so we are at the top level
              return "{$this->getGuid()}:0:0";
          }
          if ($this->getParentGuidL2() == 0) { //No level2 so we are at the l1 level
              return "{$this->getParentGuidL1()}:{$this->getGuid()}:0";
          }
          return "{$this->getParentGuidL1()}:{$this->getParentGuidL2()}:{$this->getGuid()}";
      }
  
      /**
       * Return an array of thumbnails
       * @return array
       */
      public function getThumbnails(): array
      {
          $thumbnails = [];
          $mediaManager = Di::_()->get('Media\Image\Manager');
          $sizes = [ 'xlarge', 'large' ];
          foreach ($sizes as $size) {
              $thumbnails[$size] = $mediaManager->getPublicAssetUri($this, $size);
          }
          return $thumbnails;
      }
  
      /**
       * Return the urn for the comment
       * @return string
       */
      public function getUrn()
      {
          return implode(':', [
              'urn',
              'comment',
              $this->getEntityGuid(),
              $this->getPartitionPath(),
              $this->getGuid(),
          ]);
      }
  
      /**
       * Return the entity guid
       * @return string
       */
      public function getAccessId(): string
      {
          return $this->getEntityGuid();
      }
  
      /**
       * Comments don't have containers
       * @return null
       */
      public function getContainerEntity()
      {
          return null;
      }
  
      /**
       * Defines the exportable members
       * @return array
       */
      public function getExportable()
      {
          return [
              'type',
              'entityGuid',
              'parentGuidL1',
              'parentGuidL2',
              'guid',
              'repliesCount',
              'ownerGuid',
              'timeCreated',
              'timeUpdated',
              'body',
              'attachments',
              'mature',
              'edited',
              'spam',
              'deleted',
              function ($export) {
                  return $this->_extendExport($export);
              }
          ];
      }
  
      /**
       * @param array $export
       * @return array
       * @throws \Minds\Exceptions\InvalidLuidException
       */
      protected function _extendExport(array $export)
      {
          $output = [];
  
          $output['_guid'] = (string) $export['guid'];
          $output['guid'] = $output['luid'] = (string) $this->getLuid();
  
          $output['entity_guid'] = (string) $this->getEntityGuid();
  
          $output['parent_guid_l1'] = (string) $this->getParentGuidL1();
          $output['parent_guid_l2'] = (string) $this->getParentGuidL2();
  
          $output['partition_path'] = $this->getPartitionPath();
          $output['parent_path'] = $this->getParentPath();
          $output['child_path'] = $this->getChildPath();
  
          // Legacy
          $output['ownerObj'] = $this->getOwnerObj();
          $output['description'] = $this->getBody();
  
          if (!$output['ownerObj'] && !$this->getOwnerGuid()) {
              $unknown = Unknown::user();
  
              $output['ownerObj'] = $unknown->export();
              $output['owner_guid'] = $unknown->guid;
          }
  
          if ($export['attachments']) {
              foreach ($export['attachments'] as $key => $value) {
                  $output['attachments'][$key] = $this->getAttachment($key);
                  $output[$key] = $output['attachments'][$key];
              }
          }
  
          if (isset($output['custom_type']) && $output['custom_type'] === 'image') {
              $output['custom_type'] = 'batch';
              $output['custom_data'] = [ $output['custom_data'] ];
          }
  
          if (!Flags::shouldDiscloseStatus($this)) {
              unset($output['spam']);
              unset($output['deleted']);
          }
  
          if (!$this->isEphemeral()) {
              $output['thumbs:up:user_guids'] = $this->getVotesUp();
              $output['thumbs:up:count'] = count($this->getVotesUp());
  
              $output['thumbs:down:user_guids'] = $this->getVotesDown();
              $output['thumbs:down:count'] = count($this->getVotesDown());
          }
  
          $output['thumbnails'] = $this->getThumbnails();
  
          $output['can_reply'] = (bool) !$this->getParentGuidL2();
  
          //$output['parent_guid'] = (string) $this->entityGuid;
  
          $output = Export::sanitize($output);
  
          return $output;
      }
  }
  