<?php

/**
* SettingsFactory
* Create unlimited settings pages from JSON and PHP
*
* @author Macrura
*
* ProcessWire 3.x
* Copyright (C) 2011 by Ryan Cramer
* Licensed under GNU/GPL v2, see LICENSE.TXT
*
* http://www.processwire.com
* http://www.ryancramer.com
*
*/
class SettingsFactory extends \ProcessWire\WireData implements \ProcessWire\Module, \ProcessWire\ConfigurableModule  {

	public static function getModuleInfo() {
		return array(
			'title' => \ProcessWire\__('Settings Factory', \ProcessWire\wire("config")->paths->root . 'site/modules/SettingsFactory/SettingsFactory.module'),
			'summary' => \ProcessWire\__('Create Unlimited Settings Pages!', \ProcessWire\wire("config")->paths->root . 'site/modules/SettingsFactory/SettingsFactory.module'),
			'version' => '1.0.6',
			'author'    => 'Macrura',
			'permanent' => false,
			'autoload' => true,
			'icon' => 'check-square-o',
			'installs' => 'ProcessSettingsFactory'
		);
	}

	protected static $configDefaults = array(
		'instructions' => '',
	);

	/**
	* Set our configuration defaults
	*
	*/
	public function __construct() {
		$configDefaults = self::$configDefaults;
		foreach($configDefaults as $key => $value) {
			$this->set($key, $value);
		}
	}


	public function init() {
		$this->buildFactory();
	}

	public function ready() {
		//$this->buildFactory();
	}


	public function buildFactory() {

		/**
		* Look for all settings pages, read the name of the page, and and inputfield names into a this module's properties.
		* thanks @Zeka for fixing this pages find
		*/
		$module_id = \ProcessWire\wire('modules')->getModuleInfo('ProcessSettingsFactory')['id'];
		$settingsPages = $this->wire('pages')->find("template=admin, process=$module_id");

		foreach($settingsPages as $sp) {
			if($sp->sp_filepath) {
				$key = $sp->name;
				$settingsArray = array();
				$path = \ProcessWire\wire('config')->paths->templates .  $sp->sp_filepath;
				if(file_exists($path)) {
					$pathParts = pathinfo($path);

					if($pathParts['extension'] == 'json') {
						$json = file_get_contents($path);
						$fArray = json_decode($json, true);
						if($fArray === null) {
							$this->error('Your json file must return valid JSON array of inputfields.');
							continue;
						}
					}

					if($pathParts['extension'] == 'php') {
						$fArray = \ProcessWire\wirerenderfile(\ProcessWire\wire('files')->compile($path,array('includes'=>true,'namespace'=>true,'modules'=>false,'skipIfNamespace'=>false)));
						if($fArray === null) {
							$this->error('Your php file must return valid array of inputfields.');
							continue;
						}
					}

					// support for WireTabs (or nested wrappers are returned by file)
					$fArray = $this->extractInputfields($fArray);
					foreach($fArray as $field) {
						if(!$field['name']) continue;
						$value = isset($field['value']) ? $field['value'] : '';
						$settingsArray[$field['name']] = $value;
					}
					$this->set($key, $settingsArray);
				} // end if file exists
			} // end if there is a filepath specified
		} // end foreach pages


	}


	/**
	* Extract the inputfields from nested tabs/fieldsets
	*/
	public function extractInputfields($inputfields) {
		$inputfieldsArray = new \ProcessWire\InputfieldWrapper();
		foreach($inputfields as $field) {
			if(is_array($field)) $inputfieldsArray->importArray($field);
			elseif($field instanceof \ProcessWire\InputfieldWrapper) $inputfieldsArray->import($field->getAll());
		}
		return $inputfieldsArray->getAll();
	}



	/**
	* Get the settings for frontend api.
	* default to WireArray for returned object
	*/
	public function getSettings($key, $wireData = true) {

		$languages = ($this->wire('languages')) ? $this->wire('languages') : '';
		$nonDefaultLanguages = ($languages) ? $languages->findNonDefault() : '';

		$user = $this->wire('user');
		$settings = $this->modules->getConfig('SettingsFactory'); // or $this?
		if(empty($settings[$key])) return;
		$dataArray = $settings[$key];
		$settingsFields = $this[$key];

		$newDataArray = array();

		foreach ($settingsFields as $key => $value) {
			if ($nonDefaultLanguages && $user->language !== $languages->getDefault()) {
				$key_lang = $key . "__" . $user->language->id;
				if (array_key_exists($key_lang, $dataArray)) {
					$newDataArray[$key] = $dataArray[$key_lang] ? $dataArray[$key_lang] : $dataArray[$key];
				} else {
					$newDataArray[$key] = $dataArray[$key];
				}
			//} else {
			} else if(isset($dataArray[$key])) { // 6/5/20 @martijn
				$newDataArray[$key] = $dataArray[$key];
			}
		}

		if(!$wireData) return $newDataArray;
		// convert to object
		$key = new \ProcessWire\WireData();
		$key->setArray($newDataArray);
		return $key;
	}

	/**
	* Get the settings in plain array for frontend api.
	*/
	public function getSettingsArray($key) {
		return $this->getSettings($key, false);
	}


	/**
	* Called only when your module is installed
	*
	* This version creates a new page with this Process module assigned.
	*
	*/
	public function ___install() {
		// Check for existence of the field below, throw a message if it already exists
		if($this->fields->get('sp_filepath') == NULL) {
			// If it doesn't exist then and create it
			$field = new \ProcessWire\Field();
			$field->type = $this->modules->get("FieldtypeText");
			$field->name = 'sp_filepath';
			$field->label = \ProcessWire\__('Inputfields Definition File Path.');
			$field->description = \ProcessWire\__('Path to the file that defines the inputfields - json or php. Relative to templates folder.');
			$field->notes = \ProcessWire\__('See the examples included in the modules to get started.');
			//$field->placeholder = \ProcessWire\__('settings/site-settings.php');
			$field->showIf = 'process=ProcessSettingsFactory';
			$field->save();
		}

		// add to admin template, set visibility to only for the process
		$adminTemplate = $this->templates->get('admin');
		$adminTemplate->fields->add($field);
		$adminTemplate->fields->save();
		$this->message(\ProcessWire\__("Added field 'sp_filepath' to admin template."));
	}

	/**
	* Called only when your module is uninstalled
	* This should return the site to the same state it was in before the module was installed.
	*
	*/
	public function ___uninstall() {

		// 1) Remove the path field from the template
		$adminTemplate = $this->templates->get('admin');
		if($adminTemplate->fields->get('sp_filepath')) {
			$adminTemplate->fields->remove($adminTemplate->fields->get('sp_filepath'));
			$adminTemplate->fields->save();
		}

		// 2) Remove the field sp_filepath
		if($this->fields->get('sp_filepath')) {
			$field = $this->fields->get('sp_filepath');
			$this->fields->delete($field);
		}

	}


	public static function getModuleConfigInputfields(array $data) {

		foreach(self::$configDefaults as $key => $value) {
			if(!isset($data[$key])||$data[$key]=="") $data[$key] = $value;
		}

		$inputfields = new \ProcessWire\InputfieldWrapper();

		/* INSTRUCTIONS
		------------------------------------------------------------------------ */
		$f = \ProcessWire\wire('modules')->get('InputfieldMarkup');
		$f->name  = 'instructions';
		$f->label = \ProcessWire\__('Instructions', \ProcessWire\wire("config")->paths->root . 'site/modules/SettingsFactory/SettingsFactory.module');
		$f->markupText = \ProcessWire\__('Create your processes then enter a path to the json or php definition file of the fields in the path field.', \ProcessWire\wire("config")->paths->root . 'site/modules/SettingsFactory/SettingsFactory.module');
		$inputfields->add($f);

		return $inputfields;

	}

	/**
	 * @var $key - the settings key
	 * @var $_key - the setting within the key
	 * @var $value - the new value
	 */
	public function changeSetting($key,$_key,$value) {

		$modData = $this->modules->getConfig('SettingsFactory');
		if(!array_key_exists($key, $modData)) return;
		if(!array_key_exists($_key, $modData[$key])) return;
		$modData[$key][$_key] = $value;
		$this->modules->saveModuleConfigData('SettingsFactory', $modData);

	}


}
