<?php
 namespace TCMS\Gen;
 require_once "env-function.php";
 class TCMSGenExtension {
 public function createExtension($options) {
 if(isset($options['help'])) {
 $this->showHelpCreateExtension();
 return true;
 }
 $extensionName = $this->formatExtensionName($options);
 if(!$extensionName) {
 showLogError("Vui lòng nhập tên extension.");
 showLogInfo("Nhập --help để xem hướng dẫn tạo extension.");
 return false;
 }
 if(!isset($options['area'])) {
 showLogError("Vui lòng nhập area cho extension.");
 showLogInfo("Nhập --help để xem hướng dẫn tạo extension.");
 return false;
 }
 $_appId = readAppId();
 $appConfig = require(ROOT_PATH . 'apps' . DIRECTORY_SEPARATOR . $_appId . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'app.php');
 if(empty($appConfig['areas'][$options['area']])) {
 showLogError("area ". $options['area'] ." không tồn tại");
 return;
 }
 $type = $this->getExtensionType($options);
 if(!$type) {
 showLogError("Vui lòng nhập loại extension --type.");
 showLogInfo("Nhập --help để xem hướng dẫn tạo extension.");
 return false;
 }
 $className = $this->getExtClassName($options, $extensionName);
 if(!$className) {
 showLogError("Không tìm thấy class của extension");
 return false;
 }
 $isPrivate = false;
 if(isset($options['private'])) {
 $appId = $_appId;
 $extPath = ROOT_PATH . 'apps' . DIRECTORY_SEPARATOR . $appId . DIRECTORY_SEPARATOR . 'extensions';
 if(!file_exists($extPath)) {
 mkdir($extPath);
 }
 $extPath .= DIRECTORY_SEPARATOR . $extensionName;
 $isPrivate = true;
 }
 else {
 $appId = false;
 $extPath = ROOT_PATH . 'extensions';
 if(!file_exists($extPath)) {
 mkdir($extPath);
 }
 $extPath = $extPath . DIRECTORY_SEPARATOR . $extensionName;
 }
 if(file_exists($extPath)) {
 showLogError("Extension $extensionName đã tồn tại");
 return false;
 }
 $this->createExtensionFile($extPath, $extensionName, $className, $type, $isPrivate, $appId, $options['area']);
 }
 private function createExtensionFile($extPath, $extensionName, $className, $type, $isPrivate, $appId, $areaNN) {
 mkdir($extPath);
 if($isPrivate && !$appId) {
 $appId = readAppId();
 }
 $namespaceName = $isPrivate ? ($this->formatAppNamespace($appId) . "\\Extension") : "Extension";
 switch($type) {
 case 'control': $this->createControlExtension($extPath, $extensionName, $className, $namespaceName);
 showLogSuccess("Tạo thành công control extension $extPath");
 break;
 case 'form': $this->createFormControlExtension($extPath, $extensionName, $className, $namespaceName);
 showLogSuccess("Tạo thành công form control extension $extPath");
 break;
 case 'model': $this->createModelExtension($extPath, $extensionName, $className, $namespaceName);
 showLogSuccess("Tạo thành công model extension $extPath");
 break;
 case 'auth': $this->createAuthExtension($extPath, $extensionName, $className, $namespaceName);
 showLogSuccess("Tạo thành công auth extension $extPath");
 break;
 case 'hook': $this->createHookExtension($extPath, $extensionName, $className, $namespaceName);
 showLogSuccess("Tạo thành công hook extension $extPath");
 break;
 }
 if(empty($appId)) $appId = readAppId();
 $this->addToConfig($appId, $areaNN, $namespaceName . '\\' . $className, $extensionName, $isPrivate);
 }
 private function addToConfig($appId, $areaName, $namespaceName, $name, $isPrivate) {
 $path = ROOT_PATH . 'apps' . DIRECTORY_SEPARATOR . $appId . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . $areaName . '.extension.php';
 if(!file_exists($path)) {
 $fp2 = fopen($path, 'w');
 fwrite($fp2, "<?php\nreturn [\n\n];");
 fclose($fp2);
 }
 $modelContent = readConfigFile($path);
 $lineIndex = -1;
 $lineIndex2 = -1;
 $len = count($modelContent);
 for ($i = $len - 1;
 $i >= 0;
 $i--) {
 if($lineIndex == -1) {
 if(strripos($modelContent[$i], "]") !== false) {
 $lineIndex = $i;
 }
 }
 else {
 if(strripos($modelContent[$i], "]") !== false) {
 $lineIndex2 = $i;
 break;
 }
 }
 }
 $contentFile = false;
 if ($lineIndex2 === -1) {
 $models = require_once($path);
 if (count($models) === 0) {
 $contentFile = "<?php\nreturn [\n";
 $contentFile .= "\t'$name' => ";
 $contentFile .= "[\n";
 if(!$isPrivate) {
 $contentFile .= "\t\t'$name' => $namespaceName::class,\n";
 }
 else {
 $contentFile .= "\t\t'$name' => [\n\t\t\t'namespace' => $namespaceName::class,\n";
 $contentFile .= "\t\t\t'private' => true\n\t\t],\n";
 }
 $contentFile .= "\t]\n";
 $contentFile .= "];";
 }
 }
 else {
 for ($i = 0;
 $i < $lineIndex2;
 $i++) {
 $contentFile .= $modelContent[$i];
 }
 $line = $modelContent[$lineIndex2];
 $startIndex = strripos($line, "]");
 $contentFile .= substr($line, 0, $startIndex) . "],\n";
 $contentFile .= "\t'$name' => ";
 $contentFile .= "[\n";
 if(!$isPrivate) {
 $contentFile .= "\t\t'$name' => $namespaceName::class,\n";
 }
 else {
 $contentFile .= "\t\t'$name' => [\n\t\t\t'namespace' => $namespaceName::class,\n";
 $contentFile .= "\t\t\t'private' => true\n\t\t],\n";
 }
 $contentFile .= "\t]";
 $contentFile .= "\n];";
 }
 if ($contentFile) {
 $fp2 = fopen($path, 'w');
 fwrite($fp2, $contentFile);
 fclose($fp2);
 }
 else {
 showLogError("Nội dung config extension.php trong app " . $appId . " không hợp lệ");
 }
 }
 private function createControlExtension($extPath, $extensionName, $className, $namespaceName) {
 mkdir($extPath . DIRECTORY_SEPARATOR . 'views');
 $controllerContent = "<?php\n\n";
 $controllerContent .= "namespace $namespaceName;\n";
 $controllerContent .= "use TCMS\ControlExtension;\n\n";
 $controllerContent .= "class $className extends ControlExtension {\n";
 $controllerContent .= "\tprivate \$option = [];\n\n";
 $controllerContent .= "\tpublic function render(\$value, \$option = null) {\n";
 $controllerContent .= "\t\tcopy_option(\$this->option, \$option);\n";
 $controllerContent .= "\t}\n\n";
 $controllerContent .= "}";
 $fp2 = fopen($extPath . DIRECTORY_SEPARATOR . $extensionName . '.php', 'w');
 fwrite($fp2, $controllerContent);
 fclose($fp2);
 }
 private function createFormControlExtension($extPath, $extensionName, $className, $namespaceName) {
 mkdir($extPath . DIRECTORY_SEPARATOR . 'views');
 $controllerContent = "<?php\n\n";
 $controllerContent .= "namespace $namespaceName;\n";
 $controllerContent .= "use TCMS\FormControlExtension;\n\n";
 $controllerContent .= "class $className extends FormControlExtension {\n";
 $controllerContent .= "\tprivate \$option = [];\n\n";
 $controllerContent .= "\tpublic function render(\$value, \$option = null) {\n";
 $controllerContent .= "\t\tcopy_option(\$this->option, \$option);\n";
 $controllerContent .= "\t}\n\n";
 $controllerContent .= "\tpublic function onSubmit(\$model) {\n\n";
 $controllerContent .= "\t}\n\n";
 $controllerContent .= "}";
 $fp2 = fopen($extPath . DIRECTORY_SEPARATOR . $extensionName . '.php', 'w');
 fwrite($fp2, $controllerContent);
 fclose($fp2);
 }
 private function createModelExtension($extPath, $extensionName, $className, $namespaceName) {
 mkdir($extPath . DIRECTORY_SEPARATOR . 'views');
 $controllerContent = "<?php\n\n";
 $controllerContent .= "namespace $namespaceName;\n";
 $controllerContent .= "use TCMS\ModelExtension;\n\n";
 $controllerContent .= "class $className extends ModelExtension {\n";
 $controllerContent .= "\tprivate \$option = [];\n\n";
 $controllerContent .= "\tpublic function render(\$value, \$option = null) {\n";
 $controllerContent .= "\t\tcopy_option(\$this->option, \$option);\n";
 $controllerContent .= "\t}\n\n";
 $controllerContent .= "\tpublic function onModelChanged(\TCMS\Model \$model, \$isInsert) {\n\n";
 $controllerContent .= "\t}\n\n";
 $controllerContent .= "\tpublic function onModelDeleted(\TCMS\Model \$model, \$id) {\n\n";
 $controllerContent .= "\t}\n\n";
 $controllerContent .= "}";
 $fp2 = fopen($extPath . DIRECTORY_SEPARATOR . $extensionName . '.php', 'w');
 fwrite($fp2, $controllerContent);
 fclose($fp2);
 }
 private function createAuthExtension($extPath, $extensionName, $className, $namespaceName) {
 $controllerContent = "<?php\n\n";
 $controllerContent .= "namespace $namespaceName;\n";
 $controllerContent .= "use TCMS\AuthExtension;\n\n";
 $controllerContent .= "class $className extends AuthExtension {\n\n";
 $controllerContent .= "\tprivate \$option = [];\n\n";
 $controllerContent .= "\tpublic function __construct() {\n";
 $controllerContent .= "\t\t\$this->loginUrl = url('/login');\n";
 $controllerContent .= "\t}\n\n";
 $controllerContent .= "\tpublic function login(string \$username, string \$password, ?array \$option = null) {\n";
 $controllerContent .= "\t\tcopy_option(\$this->option, \$option);\n";
 $controllerContent .= "\t}\n\n";
 $controllerContent .= "\tpublic function logout() {\n\n";
 $controllerContent .= "\t}\n\n";
 $controllerContent .= "\tpublic function auth() {\n\n";
 $controllerContent .= "\t}\n\n";
 $controllerContent .= "\tpublic function hasRole(\$role) {\n\t\treturn true;\n";
 $controllerContent .= "\t}\n\n";
 $controllerContent .= "\tpublic function getName() {\n\n";
 $controllerContent .= "\t}\n\n";
 $controllerContent .= "\tpublic function encodePass(\$password) {\n\n";
 $controllerContent .= "\t}\n\n";
 $controllerContent .= "}";
 $fp2 = fopen($extPath . DIRECTORY_SEPARATOR . $extensionName . '.php', 'w');
 fwrite($fp2, $controllerContent);
 fclose($fp2);
 }
 private function createHookExtension($extPath, $extensionName, $className, $namespaceName) {
 $controllerContent = "<?php\n\n";
 $controllerContent .= "namespace $namespaceName;\n";
 $controllerContent .= "use TCMS\HookExtension;\n\n";
 $controllerContent .= "class $className extends HookExtension {\n\n";
 $controllerContent .= "\tpublic function startup() {\n\n";
 $controllerContent .= "\t}\n\n";
 $controllerContent .= "\tpublic function beforeModuleLoad(\$module) {\n\n";
 $controllerContent .= "\t}\n\n";
 $controllerContent .= "\tpublic function beforeControllerLoad(\$controller) {\n\n";
 $controllerContent .= "\t}\n\n";
 $controllerContent .= "\tpublic function beforeViewLoad(\$view) {\n\n";
 $controllerContent .= "\t}\n\n";
 $controllerContent .= "}";
 $fp2 = fopen($extPath . DIRECTORY_SEPARATOR . $extensionName . '.php', 'w');
 fwrite($fp2, $controllerContent);
 fclose($fp2);
 }
 private function formatExtensionName($options) {
 if(!isset($options['make:extension'])) {
 return false;
 }
 $extensionName = $options['make:extension'];
 $extensionName = strtolower($extensionName);
 $extensionName = preg_replace('/[^a-z0-9]/i', '-', $extensionName);
 $extensionName = str_replace('--', '-', $extensionName);
 $extensionName = str_replace('--', '-', $extensionName);
 $extensionName = str_replace('.php', '', $extensionName);
 return $extensionName;
 }
 private function getExtensionType($options) {
 if(!isset($options['type'])) {
 return false;
 }
 $type = $options['type'];
 if($type == 'control' || $type == 'form' || $type == 'auth' || $type == 'model' || $type == 'hook') {
 return $type;
 }
 return false;
 }
 private function getExtClassName($option, $extensionName) {
 $arr = explode('-', $extensionName);
 $namespaceName = '';
 foreach($arr as $v) {
 if($v != "" && $v != "-") {
 $namespaceName .= strtoupper(substr($v, 0, 1)) . substr($v, 1);
 }
 }
 return $namespaceName;
 }
 private function formatAppNamespace($appId) {
 $arrItem = preg_split("/(_|-|\.| )+/", $appId);
 $namespaceName = "";
 foreach($arrItem as $v) {
 $a = strtolower($v);
 if($a !== "0" && !$a) {
 continue;
 }
 $namespaceName .= strtoupper(substr($a, 0, 1)) . substr($a, 1);
 }
 return $namespaceName;
 }
 public function showHelpCreateExtension() {
 drawLine();
 echo "Description:\n";
 showLogInfo("  Tự động tạo một extension mới");
 echo "\nFormat:\n";
 echo "  make:extension [extension-name] -a [area-name] -t [extension-type] [options]\n\n";
 echo "Required:\n";
 showHelpTextColor("[extension-name]", "Tên extension cần tạo. VD: admin-auth-default");
 showHelpTextColor("-a, --area", "Area của extension này");
 showHelpTextColor("-t, --type", "Loại extension. Có 5 loại:");
 echo ("\t\t\t- control: Tạo ra control extension, để hiển thị control lên giao diện\n");
 echo ("\t\t\t- form: Tạo ra form control extension, để hiển thị control trong form lên giao\n");
 echo ("\t\t\t- auth: Tạo ra auth extension, để xác thực quyền truy cập\n");
 echo ("\t\t\t- hook: Tạo ra hook extension, để tự động gọi khi website chạy\n");
 echo ("\t\t\t- model: Tạo ra model extension, để tự động bắt sự kiện khi model thay đổi\n\n");
 echo "Options:\n";
 showHelpTextColor("-p, --private", "\tTạo private extension");
 drawLine();
 }
 }
