/**
  * @throws Exception
  * @throws NotSupportedException
  */
 public function beforeSave()
 {
     if ($this->node !== null && !$this->node->getIsNewRecord()) {
         $this->node->refresh();
     }
     switch ($this->operation) {
         case self::OPERATION_MAKE_ROOT:
             $item = $this->owner->getAttribute($this->itemAttribute);
             if ($item !== null) {
                 $this->owner->setAttribute($this->pathAttribute, $item);
             }
             $this->owner->setAttribute($this->depthAttribute, 0);
             break;
         case self::OPERATION_PREPEND_TO:
             $this->checkNode(false);
             $item = $this->owner->getAttribute($this->itemAttribute);
             if ($item !== null) {
                 $path = $this->node->getAttribute($this->pathAttribute);
                 $this->owner->setAttribute($this->pathAttribute, $path . $this->delimiter . $item);
             }
             $this->owner->setAttribute($this->depthAttribute, $this->node->getAttribute($this->depthAttribute) + 1);
             if ($this->sortAttribute !== null) {
                 $to = $this->node->getChildren()->orderBy(null)->min($this->sortAttribute);
                 $to = $to !== null ? $to - $this->step : 0;
                 $this->owner->setAttribute($this->sortAttribute, $to);
             }
             break;
         case self::OPERATION_APPEND_TO:
             $this->checkNode(false);
             $item = $this->owner->getAttribute($this->itemAttribute);
             if ($item !== null) {
                 $path = $this->node->getAttribute($this->pathAttribute);
                 $this->owner->setAttribute($this->pathAttribute, $path . $this->delimiter . $item);
             }
             $this->owner->setAttribute($this->depthAttribute, $this->node->getAttribute($this->depthAttribute) + 1);
             if ($this->sortAttribute !== null) {
                 $to = $this->node->getChildren()->orderBy(null)->max($this->sortAttribute);
                 $to = $to !== null ? $to + $this->step : 0;
                 $this->owner->setAttribute($this->sortAttribute, $to);
             }
             break;
         case self::OPERATION_INSERT_BEFORE:
             $this->checkNode(true);
             $item = $this->owner->getAttribute($this->itemAttribute);
             if ($item !== null) {
                 $path = $this->getParentPath($this->node->getAttribute($this->pathAttribute));
                 $this->owner->setAttribute($this->pathAttribute, $path . $this->delimiter . $item);
             }
             $this->owner->setAttribute($this->depthAttribute, $this->node->getAttribute($this->depthAttribute));
             if ($this->sortAttribute !== null) {
                 $this->moveTo($this->node->getAttribute($this->sortAttribute) - 1, false);
             }
             break;
         case self::OPERATION_INSERT_AFTER:
             $this->checkNode(true);
             $item = $this->owner->getAttribute($this->itemAttribute);
             if ($item !== null) {
                 $path = $this->getParentPath($this->node->getAttribute($this->pathAttribute));
                 $this->owner->setAttribute($this->pathAttribute, $path . $this->delimiter . $item);
             }
             $this->owner->setAttribute($this->depthAttribute, $this->node->getAttribute($this->depthAttribute));
             if ($this->sortAttribute !== null) {
                 $this->moveTo($this->node->getAttribute($this->sortAttribute) + 1, true);
             }
             break;
         default:
             if ($this->owner->getIsNewRecord()) {
                 throw new NotSupportedException('Method "' . $this->owner->className() . '::insert" is not supported for inserting new nodes.');
             }
             $item = $this->owner->getAttribute($this->itemAttribute);
             $path = $this->getParentPath($this->owner->getAttribute($this->pathAttribute));
             $this->owner->setAttribute($this->pathAttribute, $path . $this->delimiter . $item);
     }
 }