<?php
/**
 * @copyright 2021 Double Bastion LLC <www.doublebastion.com>
 *
 * @author Double Bastion LLC
 *
 * @license GNU AGPL version 3 or any later version
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

declare(strict_types=1);

namespace OCA\PaxFax;

use OCA\PaxFax\AppInfo\Application;

use OCP\IConfig;


class AppConfig {
	private $appName = 'pax_fax';

	/** @var IConfig  */
	private $config;

	/**
	 * AppConfig constructor.
	 *
	 * @param IConfig $config
	 */
	public function __construct(IConfig $config) {
		$this->config = $config;
	}

	/**
	 * Get all setting values as an array
	 * @return array
	 */
	public function getAllValues() {
		$keys = array_keys($this->defaults);
		$values = array_map([$this, 'getAppValue'], $keys);
		$preparedKeys = array_map([$this, 'camelCase'], $keys);
		return array_combine($preparedKeys, $values);
	}

	/**
	 * Get a value by key
	 * @param string $key
	 * @return string
	 */
	public function getAppValue($key) {
		$defaultValue = null;
		if (array_key_exists($key, $this->defaults)){
			$defaultValue = $this->defaults[$key];
		}
		return $this->config->getAppValue($this->appName, $key, $defaultValue);
	}

	/**
	 * Set a value by key
	 * @param string $key
	 * @param string $value
	 */
	public function setAppValue($key, $value) {
		$this->config->setAppValue($this->appName, $key, $value);
	}

	/**
	 * Set a value with magic __call invocation
	 * @param string $key
	 * @param array $args
	 * @throws \BadFunctionCallException
	 */
	protected function setter($key, $args) {
		if (array_key_exists($key, $this->defaults)) {
			$this->setAppValue($key, $args[0]);
		} else {
			throw new \BadFunctionCallException($key . ' is not a valid key');
		}
	}

	/**
	 * Get a value with magic __call invocation
	 * @param string $key
	 * @return string
	 * @throws \BadFunctionCallException
	 */
	protected function getter($key) {
		if (array_key_exists($key, $this->defaults)) {
			return $this->getAppValue($key);
		}

		throw new \BadFunctionCallException($key . ' is not a valid key');
	}

	/**
	 * Translates property_name into propertyName
	 * @param string $property
	 * @return string
	 */
	protected function camelCase($property){
		$split = explode('_', $property);
		$ucFirst = implode('', array_map('ucfirst', $split));
		return lcfirst($ucFirst);
	}

	/**
	 * Does all the someConfig to some_config magic
	 * @param string $property
	 * @return string
	 */
	protected function propertyToKey($property){
		$parts = preg_split('/(?=[A-Z])/', $property);
		$column = null;

		foreach($parts as $part){
			if($column === null){
				$column = $part;
			} else {
				$column .= '_' . lcfirst($part);
			}
		}

		return $column;
	}

	/**
	 * Get/set an option value by calling getSomeOption method
	 * @param string $methodName
	 * @param array $args
	 * @return string|null
	 * @throws \BadFunctionCallException
	 */
	public function __call($methodName, $args){
		$attr = lcfirst( substr($methodName, 3) );
		$key = $this->propertyToKey($attr);
		if(strpos($methodName, 'set') === 0){
			$this->setter($key, $args);
		} elseif(strpos($methodName, 'get') === 0) {
			return $this->getter($key);
		} else {
			throw new \BadFunctionCallException($methodName .
					' does not exist');
		}
	}
}
