<?php

/**
 * Class ControllerExtensionModuleCart2cartBridgeInstall
 */
class ControllerExtensionModuleCart2cartBridgeInstall extends Controller {

  /**
   *
   */
  const M1_BRIDGE_VERSION = '21';

  /**
   *
   */
  const MODULE_DEFAULT = 5060;
  /**
   *
   */
  const MODULE_BRIDGE_ALREADY_INSTALLED = 5061;
  /**
   *
   */
  const MODULE_BRIDGE_SUCCESSFULLY_INSTALLED = 5062;
  /**
   *
   */
  const MODULE_BRIDGE_SUCCESSFULLY_UNINSTALLED = 5063;

  /**
   *
   */
  const MODULE_ERROR_DEFAULT = 'defaultError';
  /**
   *
   */
  const MODULE_ERROR_TOKEN = 5068;
  /**
   *
   */
  const MODULE_ERROR_ROOT_DIR_PERMISSION = 5069;
  /**
   *
   */
  const MODULE_ERROR_EXTRACTING_ARCHIVE = 5070;
  /**
   *
   */
  const MODULE_ERROR_INSTALLED_PERMISSION = 5071;
  /**
   *
   */
  const MODULE_ERROR_PERMISSION = 5072;

  /**
   *
   */
  const MODULE_ERROR_BRIDGE_WAS_BROKEN = 5085;
  /**
   *
   */
  const MODULE_ERROR_BRIDGE_WAS_NOT_UPDATED = 5086;

  /**
   *
   */
  const API_PATH_FOR_BRIDGE = 'https://app.shopping-cart-migration.com/api.bridge.download/';

  /**
   * @var string
   */
  protected $_cart_name ='OpenCart';
  /**
   * @var string
   */
  protected $_root_path ='';
  /**
   * @var string
   */
  protected $_c2c_bridge_path ='';

  /**
   * @var
   */
  public $file;

  /**
   *
   */
  public function index()
  {
    if (version_compare(phpversion(), '7.0.0', '>=')) {
      try {
        $response = new stdClass();
        $this->doActions($response);
      } catch (Throwable $e) {
        $response->is_error = true;

        if (strpos($e->getMessage(), 'ZipArchive') !== false) {
          $response->code = self::MODULE_ERROR_INSTALLED_PERMISSION;
          $response->message = 'Permission denied on ZipArchive save.';
        } elseif (strpos($e->getMessage(), 'Permission') !== false) {
          $response->code = self::MODULE_ERROR_PERMISSION;
          $response->message = 'Permission problem.';
        } else {
          $response->message = $e->getMessage();
        }
      }
    } else {
      try {
        $response = new stdClass();
        $this->doActions($response);
      } catch (Exception $e) {
        $response->is_error = true;

        if (strpos($e->getMessage(), 'ZipArchive') !== false) {
          $response->code = self::MODULE_ERROR_INSTALLED_PERMISSION;
          $response->message = 'Permission denied on ZipArchive save.';
        } elseif (strpos($e->getMessage(), 'Permission') !== false) {
          $response->code = self::MODULE_ERROR_PERMISSION;
          $response->message = 'Permission problem.';
        } else {
          $response->message = $e->getMessage();
        }
      }
    }

    header('Access-Control-Allow-Origin: *');
    $this->response->setOutput(json_encode($response));
  }

  /**
   * @param stdClass $response
   */
  public function doActions(stdClass $response)
  {
    $this->_root_path = realpath(dirname(dirname(dirname(dirname(__DIR__)))));
    $this->_c2c_bridge_path = $this->_root_path . '/bridge2cart';

    $token = (string)(isset($this->request->post['token']) ? $this->request->post['token'] : false);
    $mode = (string)(isset($this->request->post['mode']) ? $this->request->post['mode'] : false);

    if ($token && $mode) {

      switch ($mode) {
        case 'install':
          $this->installBridge($response, $token);
        break;
        case 'unistall':
          $this->unInstallBridge($response, $token);
        break;
      }

    } elseif (!$token && $mode) {
      $response->is_error = true;
      $response->code = self::MODULE_ERROR_TOKEN;
      $response->message = '';
    }

    if (isset($response->is_error)) {
      if (!isset($response->code)) {
        $response->code = $response->is_error ? self::MODULE_ERROR_DEFAULT : self::MODULE_DEFAULT;
      }

      if (!isset($response->message)) {
        $response->message = '';
      }
    } else {
      $this->response->redirect('index.php');
    }
  }

  /**
   * @param stdClass $response
   * @param bool     $token
   */
  public function installBridge(stdClass $response, $token = false)
  {
    if (!$this->_checkRootDirPermission()) {
      if ($this->isBridgeInstalled()) {
        $response->is_error = false;
        $response->code = self::MODULE_BRIDGE_ALREADY_INSTALLED;
        $response->message = 'Bridge already installed.';
      } else {
        $response->is_error = true;
        $response->code = self::MODULE_ERROR_ROOT_DIR_PERMISSION;
        $response->message = 'Bad permission for ' . $this->_cart_name . ' root folder.';
      }
    } else {
      $is_installed = false;
      if ($this->isBridgeInstalled()) {
        $is_installed = $this->_updateBridge($response, $token);
      }

      if (!$is_installed) {
        $this->copyBridge($response, $token);
      }
    }
  }

  /**
   * @param stdClass $response
   * @param bool     $token
   */
  public function copyBridge(stdClass $response, $token = false)
  {
    $root_path = $this->_root_path;

    $arr_context_options = array(
      "ssl" => array(
        "verify_peer" => false,
        "verify_peer_name" => false,
      ),
    );
    $zipped_bridge = file_get_contents(
      self::API_PATH_FOR_BRIDGE . 'token/' . $token, false, stream_context_create($arr_context_options)
    );

    if (function_exists('file_put_contents')) {
      file_put_contents($root_path . DIRECTORY_SEPARATOR . 'bridge.zip', $zipped_bridge);
    }

    $zip = new ZipArchive();
    if ($zip->open($root_path . DIRECTORY_SEPARATOR . 'bridge.zip')) {

      $this->deleteDir($this->_c2c_bridge_path);

      $zip->extractTo($root_path . DIRECTORY_SEPARATOR);
      $zip->close();

      $file_name = 'bridge.zip';
      if (is_readable($root_path . DIRECTORY_SEPARATOR . $file_name)) {
        unlink($root_path . DIRECTORY_SEPARATOR . $file_name);
      }

      $response->is_error = false;
      $response->code = self::MODULE_BRIDGE_SUCCESSFULLY_INSTALLED;

      $this->_checkBridgeDirPermission();
      $this->_checkBridgeFilesPermission();

      $this->_checkBridge($response, $token);
    } else {
      $response->is_error = true;
      $response->code = self::MODULE_ERROR_EXTRACTING_ARCHIVE;
      $response->message = 'Error extracting archive.';
    }
  }

  /**
   * @param stdClass $response
   * @param bool     $token
   *
   * @return bool
   */
  protected function _checkBridge(stdClass $response, $token = false)
  {
    $result = false;

    $check_bridge = $this->_bridgeAction($token);

    switch ($check_bridge) {
      case 'BRIDGE_OK':
        $response->is_error = false;
        $response->code = self::MODULE_BRIDGE_SUCCESSFULLY_INSTALLED;
        $result = true;
      break;
      default:
        $this->deleteDir($this->_c2c_bridge_path);
        $response->is_error = true;
        $response->code = self::MODULE_ERROR_BRIDGE_WAS_BROKEN;
      break;
    }

    return $result;
  }

  /**
   * @param stdClass $response
   * @param bool     $token
   *
   * @return bool
   */
  protected function _updateBridge(stdClass $response, $token = false)
  {
    $result = false;

    if ($check_bridge = $this->_bridgeAction($token, 'update')) {
      if (strpos($check_bridge, 'Bridge successfully updated') !== false) {
        $check_bridge = 'BRIDGE_OK';
      } elseif (strpos($check_bridge, 'Bridge is custom') !== false) {
        $check_bridge = 'BRIDGE_IS_CUSTOM';
      }
    }

    switch ($check_bridge) {
      case 'BRIDGE_OK':
        $response->is_error = false;
        $response->code = self::MODULE_BRIDGE_SUCCESSFULLY_INSTALLED;
        $result = true;
      break;
      case 'BRIDGE_IS_CUSTOM':
        $response->is_error = false;
        $response->code = self::MODULE_ERROR_BRIDGE_WAS_NOT_UPDATED;
        $result = true;
      break;
      default:
        $this->deleteDir($this->_c2c_bridge_path);
        sleep(3);
        $response->is_error = true;
        $response->code = self::MODULE_ERROR_BRIDGE_WAS_BROKEN;
      break;
    }

    return $result;
  }

  /**
   * @param string $token
   * @param string $action
   *
   * @return bool|string
   */
  protected function _bridgeAction($token, $action = 'checkbridge')
  {
    return @file_get_contents(
      $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['SERVER_NAME']
      . str_replace('/index.php', '', $_SERVER['SCRIPT_NAME'])
      . '/bridge2cart/bridge.php?action=' . $action . '&ver=' . self::M1_BRIDGE_VERSION . '&token=' . $token
    );
  }

  /**
   * @param stdClass $response
   * @param bool     $token
   */
  public function unInstallBridge(stdClass $response, $token = false)
  {
    if ($this->isBridgeInstalled() && $this->deleteDir($this->_c2c_bridge_path)) {
      $response->is_error = false;
      $response->code = self::MODULE_BRIDGE_SUCCESSFULLY_UNINSTALLED;
      return;
    }

    $response->is_error = true;
    $response->code = self::MODULE_ERROR_INSTALLED_PERMISSION;
  }

  /**
   * @param $dir_path
   *
   * @return bool
   */
  public function deleteDir($dir_path)
  {
    if (is_dir($dir_path)) {
      $objects = scandir($dir_path);
      foreach ($objects as $object) {
        if ($object != "." && $object !="..") {
          if (filetype($dir_path . DIRECTORY_SEPARATOR . $object) == "dir") {
            $this->deleteDir($dir_path . DIRECTORY_SEPARATOR . $object);
          } else {
            if(!unlink($dir_path . DIRECTORY_SEPARATOR . $object)){
              return false;
            }
          }
        }
      }
      reset($objects);
      if (!rmdir($dir_path)) {
        return false;
      }
    } else {
      return false;
    }
    return true;
  }

  /**
   * @return bool
   */
  protected function isBridgeInstalled()
  {
    $this->_checkBridgeDirPermission();
    $this->_checkBridgeFilePermission();
    return (file_exists($this->_root_path . DIRECTORY_SEPARATOR .  'bridge2cart' . DIRECTORY_SEPARATOR . 'bridge.php'));
  }

  /**
   * @return bool
   */
  protected function _checkBridgeDirPermission()
  {
    return $this->_checkDirPermission($this->_root_path . DIRECTORY_SEPARATOR .  'bridge2cart' . DIRECTORY_SEPARATOR);
  }

  /**
   * @return bool
   */
  protected function _checkBridgeFilesPermission()
  {
    $check = true;

    $files = array(
      $this->_root_path . DIRECTORY_SEPARATOR .  'bridge2cart' . DIRECTORY_SEPARATOR . 'bridge.php',
      $this->_root_path . DIRECTORY_SEPARATOR .  'bridge2cart' . DIRECTORY_SEPARATOR . 'config.php',
      $this->_root_path . DIRECTORY_SEPARATOR .  'bridge2cart' . DIRECTORY_SEPARATOR . 'index.php',
    );

    foreach ($files as $file) {
      $check and $check = $this->_checkBridgeFilePermission($file);
    }

    return $check;
  }

  /**
   * @param null|string $path_to_file
   *
   * @return bool
   */
  protected function _checkBridgeFilePermission($path_to_file = null)
  {
    if ($path_to_file === null) {
      $path_to_file = $this->_root_path . DIRECTORY_SEPARATOR .  'bridge2cart' . DIRECTORY_SEPARATOR . 'bridge.php';
    }

    if (!is_writable($path_to_file)) {
      @chmod($path_to_file, 0666);
    }

    return is_writable($path_to_file);
  }

  /**
   * @return bool
   */
  protected function _checkRootDirPermission()
  {
    return $this->_checkDirPermission($this->_root_path);
  }

  /**
   * @return bool
   */
  protected function _checkDirPermission($path)
  {
    if (!is_writable($path)) {
      @chmod($path, 0777);
    }

    return is_writable($path);
  }
}