<?php

namespace Drupal\lingotek\Exception;

use Drupal\Core\Entity\ContentEntityInterface;

/**
 * An exception for issues when storing content entity translations.
 *
 * @package Drupal\lingotek\Exception
 */
class LingotekContentEntityStorageException extends LingotekException {

  /**
   * The entity that could not be saved.
   *
   * @var \Drupal\Core\Entity\ContentEntityInterface
   */
  protected $entity;

  /**
   * @var string
   */
  protected $table;

  public function __construct(ContentEntityInterface $entity, \Exception $previous = NULL, $message = NULL, $code = 0) {
    $message = $message !== NULL ? $message : '';
    parent::__construct($message, $code, $previous);
    $this->entity = $entity;
    $this->table = $this->extractTableFromPreviousExceptionMessage($previous);
    $this->code = $previous !== NULL ? $previous->getCode() : $code;
  }

  /**
   * Gets the table name that failed to update.
   */
  public function getTable() {
    return $this->table;
  }

  /**
   * Returns TRUE when this exception wraps a lock wait timeout (SQLSTATE 1205).
   */
  public function isLockTimeout() {
    $previous = $this->getPrevious();
    if (!$previous instanceof \Exception) {
      return FALSE;
    }
    $message = $previous->getMessage();
    return strpos($message, 'Lock wait timeout exceeded') !== FALSE || strpos($message, 'SQLSTATE[HY000]: General error: 1205') !== FALSE;
  }

  /**
   * Returns TRUE when this exception indicates "data too long" semantics.
   */
  public function isFieldTooLongError() {
    if ($this instanceof LingotekContentEntityFieldTooLongStorageException) {
      return TRUE;
    }
    $previous = $this->getPrevious();
    if (!$previous instanceof \Exception) {
      return FALSE;
    }
    return strpos($previous->getMessage(), 'Data too long for column') !== FALSE;
  }

  /**
   * Extract the problematic table from the previous exception message.
   *
   * @param \Exception $previous
   *
   * @returns
   *  A string with the problematic table name.
   */
  protected function extractTableFromPreviousExceptionMessage(\Exception $previous = NULL) {
    $table = '';
    if ($previous !== NULL) {
      // Previous message would be like:
      //    "Data too long for column 'name' at row 2"
      $previous_message = $previous->getMessage();
      $strings = explode("'", $previous_message);
      $table = count($strings) > 1 ? $strings[1] : '';
    }
    return $table;
  }

}
