<?php
/*
 * This file modified by Dominika Rauk and Jonathan Hall
 *  Last modified 2020-02-25
 */

// phpcs:disable WordPress.Security.NonceVerification -- Nonce is verified in main plugin file before include
class DiviSwitchPluginExport {
	
	public static function getDiviOptions() {
		return array(
			[
				"name" => esc_html__("Export Plugin Name", "divi-switch"),
				"id" => "swtch-plugin-export-name",
				"type" => "text",
				'std' => '',
				"desc" => esc_html__('Enter the plugin name that should be displayed when the exported plugin is installed.', 'divi-switch'),
			],
			[
				"name" => esc_html__("Export Plugin Description", "divi-switch"),
				"id" => "swtch-plugin-export-desc",
				"type" => "text",
				'std' => '',
				"desc" => esc_html__('Enter the plugin description that should be displayed when the exported plugin is installed.', 'divi-switch'),
			],
			[
				"name" => esc_html__("Export Plugin Author", "divi-switch"),
				"id" => "swtch-plugin-export-author",
				"type" => "text",
				'std' => '',
				"desc" => esc_html__('Enter the plugin author that should be displayed when the exported plugin is installed.', 'divi-switch'),
			],
			[
				"name" => esc_html__("Export Plugin Author URL", "divi-switch"),
				"id" => "swtch-plugin-export-author-url",
				"type" => "text",
				'std' => '',
				"desc" => esc_html__('Enter a URL for the plugin author.', 'divi-switch'),
			],
			[
				"name" => esc_html__("Export Plugin Version", "divi-switch"),
				"id" => "swtch-plugin-export-version",
				"type" => "text",
				'std' => '1.0.0',
				"desc" => esc_html__('Enter the version number that should be displayed when the exported plugin is installed.', 'divi-switch'),
			],
			[
				"name" => "",
				"id" => "swtch-plugin-export",
				"type"          => "callback_function",
				"function_name" => array('DiviSwitchPluginExport', 'outputDiviOptionUi'),
				'desc' => ''
			]
		);
	}
	
	public static function outputDiviOptionUi() {
?>
	<p><?php echo esc_html__('Please save your switches before exporting a plugin.', 'divi-switch');?></p><br>
	<button name="divi_switch_action" class="et-button" value="proPluginExport"><?php echo esc_html__('Export Plugin', 'divi-switch');?></button>
<?php
	}
	
	public static function export() {
		$phpFiles = array('functions.php', 'includes/switch-htaccess.php', 'includes/output/divi-style.css.php');
		$stringSub = array();
		
		
		$pluginName = isset($_POST['swtch-plugin-export-name']) ? sanitize_text_field( wp_unslash($_POST['swtch-plugin-export-name']) ) : '';
		if (empty($pluginName)) {
			$pluginClass = 'DiviSwitchCustom';
		} else {
			$stringSub['Divi Switch'] = $pluginName;
			$pluginClass = preg_replace('/[^a-z]/i', '', ucwords(trim($pluginName)));
		}
		$stringSub['DiviSwitch'] = $pluginClass;
		
		$pluginAuthor = isset($_POST['swtch-plugin-export-author']) ? sanitize_text_field( wp_unslash($_POST['swtch-plugin-export-author']) ) : '';

		if (!empty($pluginAuthor)) {
			$stringSub['Divi Space'] = $pluginAuthor;
			$stringSub['Aspen Grove Studios'] = $pluginAuthor;
		}
		
		$phpCode = '';
		foreach ($phpFiles as $i => $phpFile) {
			$phpFileContents = trim(file_get_contents(__DIR__.'/../../'.$phpFile));
			if ($i && substr($phpFileContents, 0, 5) == '<?php') {
				$phpFileContents = trim(substr($phpFileContents, 5));
			}
			if (substr($phpFileContents, -2) == '?>') {
				$phpFileContents = trim(substr($phpFileContents, -2));
			}
			$phpCode .= $phpFileContents."\n";
		}
		
		// Do string replacement throughout entire code
		$phpCode = str_replace(array_keys($stringSub), array_values($stringSub), $phpCode);
		
		$phpCode = self::processPhpDirectives($phpCode, array(
			'name' => $pluginName,
			'author' => $pluginAuthor
		));
		
		// Temporary debugging code
		// file_put_contents(__DIR__.'/../output/temp/plugin.php', $phpCode);
		
		$pluginZip = new ZipArchive();
		
		do {
			$pluginZipFilename = __DIR__.'/../output/temp/'.rand().'.zip';
		} while (file_exists($pluginZipFilename));
		$pluginZip->open($pluginZipFilename, ZipArchive::CREATE);
		$pluginZip->addFromString('plugin.php', $phpCode);
		$diviStylePhp = file_get_contents(__DIR__.'/../output/divi-style.css.php');
		$pluginZip->addFromString('includes/output/divi-style.css.php',
			self::processPhpDirectives(
				str_replace(array_keys($stringSub), array_values($stringSub), $diviStylePhp)
			)
		);
		
		if (file_exists(__DIR__.'/../output/style.css')) {
			$pluginZip->addFile(__DIR__.'/../output/style.css', 'includes/output/style.css');
		}
		if (file_exists(__DIR__.'/../output/script.js')) {
			$pluginZip->addFile(__DIR__.'/../output/script.js', 'includes/output/script.js');
		}
		$pluginZip->close();
		
		header('Content-Type: application/zip');
		header('Content-Disposition: attachment; filename="'.$pluginClass.'.zip"');
		
		readfile($pluginZipFilename);
		unlink($pluginZipFilename);
	}

	private static function processPhpDirectives($phpCode, $pluginHeaderFields=null) {
		// Process code line-by-line
		$phpCode = explode("\n", trim($phpCode));
		$output = 'echo(\'';
		
		if ($pluginHeaderFields === null) {
			$inPluginHeader = false; // skip processing plugin header
		}
		
		foreach ($phpCode as $line) {
			if (!isset($inPluginHeader)) {
				// Plugin header has not yet been processed; we're looking for a comment as the start of header
				if (trim($line) == '/*') {
					$inPluginHeader = true;
				}
			} else if ($inPluginHeader) {
				if (trim($line) == '*/') {
					$inPluginHeader = false;
				} else {
					$colonPos = strpos($line, ':');
					if ($colonPos !== false) {
						$headerField = strtolower(trim(substr($line, 0, $colonPos)));
						switch ($headerField) {
							case 'plugin name':
								if (!empty($pluginHeaderFields['name'])) {
									$line = 'Plugin Name: '.$pluginHeaderFields['name'];
								}
								break;
							case 'description':
								$option = isset($_POST['swtch-plugin-export-desc']) ? sanitize_text_field( wp_unslash($_POST['swtch-plugin-export-desc']) ) : '';
								$line = empty($option) ? '' : 'Description: '.$option;
								break;
							case 'author':
								if (!empty($pluginHeaderFields['author'])) {
									$line = 'Author: '.$pluginHeaderFields['author'];
								}
								break;
							case 'author uri':
								$option = isset($_POST['swtch-plugin-export-author-url']) ? sanitize_text_field( wp_unslash($_POST['swtch-plugin-export-author-url']) ) : '';
								if (!empty($option)) {
									$line = 'Author URI: '.$option;
								}
								break;
							case 'version':
								$option = isset($_POST['swtch-plugin-export-version']) ? sanitize_text_field( wp_unslash($_POST['swtch-plugin-export-version']) ) : '';
								if (!empty($option)) {
									$line = 'Version: '.$option;
								}
								break;
							case 'license':
							case 'license uri':
								break;
							default:
								$line = '';
								
						}
					}
				}
			} else {
				// Process directives
				switch (strtolower(trim($line))) {
					case '/* dsx-include':
						$inInclude = true;
						continue 2;
					case '/dsx-include */':
						unset($inInclude);
						continue 2;
					case '/* dsx-exclude */':
						$inExclude = true;
						continue 2;
					case '/* /dsx-exclude */':
						unset($inExclude);
						continue 2;
					case '/* dsx-execute */':
					case '/* dsx-execute':
						$inExecute = true;
						$output .= '\');';
						continue 2;
					case '/* /dsx-execute */':
					case '/dsx-execute */':
						unset($inExecute);
						$output .= 'echo(\'';
						continue 2;
				}
				
				// This code doesn't do anything at the moment (unfinished)
				// Not sure if we need to strip comments from the plugin - if we do, finish this code
				$commentPos = strpos($line, '//');
				if ($commentPos !== false) {
					//$line = substr($line, 0, $commentPos);
				}
				
				$commentPos = strpos($line, '/*');
				if ($commentPos !== false) {
					$commentEndPos = strpos($line, '*/', $commentPos + 2);
					if ($commentEndPos === false) {
						//$line = substr($line, 0, $commentPos);
						$inComment = true;
					} else {
					}
				}
				// End unfinished comment removal code
				
				if (isset($inExclude)) {
					continue;
				} else if (isset($inInclude)) {
					$line = preg_replace_callback('/\^\((.*)\)\^/U', function($subExpression) {
						$subExpression = str_replace(array('\\\'', '\\\\'), array('\'', '\\'), $subExpression[1]);
						return '\'.('.$subExpression.').\'';
					}, str_replace(array('\\', '\''), array('\\\\', '\\\''), $line));
				}
			}
			
			if (strlen(trim($line))) {
				$output .= (isset($inExecute) || isset($inInclude) ? $line : str_replace(array('\\', '\''), array('\\\\', '\\\''), $line))."\n";
			}
		}
		
		$output .= '\');';
		
		do {
			$tempFile = __DIR__.'/../output/temp/'.rand().'.php';
		} while (file_exists($tempFile));
		
		file_put_contents($tempFile, '<?php '.$output);
		
		ob_start();
		include($tempFile);
		$phpCode = ob_get_clean();
		unlink($tempFile);
		
		return $phpCode;
	}
}