<?php
/**
 * Workflow Helper
 *
 * @author Noriko Arai <arai@nii.ac.jp>
 * @author Shohei Nakajima <nakajimashouhei@gmail.com>
 * @link http://www.netcommons.org NetCommons Project
 * @license http://www.netcommons.org/license.txt NetCommons License
 * @copyright Copyright 2014, NetCommons Project
 */

App::uses('AppHelper', 'View/Helper');
App::uses('Topic', 'Topics.Model');
App::uses('Block', 'Blocks.Model');

/**
 * Workflow Helper
 *
 * @author Shohei Nakajima <nakajimashouhei@gmail.com>
 * @package NetCommons\Workflow\View\Helper
 */
class TopicsHelper extends AppHelper {

/**
 * Other helpers used by FormHelper
 *
 * @var array
 */
	public $helpers = array(
		'NetCommons.NetCommonsForm',
		'NetCommons.NetCommonsHtml',
		'Rooms.RoomsForm',
		'PluginManager.PluginsForm',
		'Users.DisplayUser',
		'Workflow.Workflow',
	);

/**
 * Before render callback. beforeRender is called before the view file is rendered.
 *
 * Overridden in subclasses.
 *
 * @param string $viewFile The view file that is going to be rendered
 * @return void
 */
	public function beforeRender($viewFile) {
		$this->NetCommonsHtml->css('/topics/css/style.css');
		$this->NetCommonsHtml->script('/topics/js/topics.js');
		parent::beforeRender($viewFile);
	}

/**
 * Camelize処理
 *
 * @param array $orig 変換元データ
 * @return array 変換後データ
 */
	public function camelizeKeyRecursive($orig) {
		$newResult = [];

		foreach ($orig as $key => $value) {
			if (Hash::get($value, 'TrackableCreator')) {
				$avatar = $this->DisplayUser->avatar($value, [], 'TrackableCreator.id');
				$value = Hash::insert(
					$value, 'TrackableCreator.avatar', $avatar
				);
			}
			if (Hash::get($value, 'TrackableUpdater')) {
				$avatar = $this->DisplayUser->avatar($value, [], 'TrackableUpdater.id');
				$value = Hash::insert(
					$value, 'TrackableUpdater.avatar', $avatar
				);
			}
			$newResult[$key] = $this->__camelizeKeyRecursive($value);

			$displayStatus = $this->__getStatusLabel($newResult[$key]);
			$newResult[$key]['topic']['displayStatus'] = $displayStatus;
		}

		return $newResult;
	}

/**
 * Camelize処理
 *
 * @param array $orig 変換元データ
 * @return array 変換後データ
 */
	private function __camelizeKeyRecursive($orig) {
		$newResult = [];
		$callback = ['Inflector', 'variable'];

		foreach ($orig as $key => $value) {
			$camelKey = call_user_func($callback, $key);

			if (is_array($value)) {
				$newResult[$camelKey] = $this->__camelizeKeyRecursive($value);
			} else {
				$newResult = $this->__parseValueForCamelize($newResult, $camelKey, $value);
			}
		}

		return $newResult;
	}

/**
 * keyによる変換処理
 *
 * self::camelizeKeyRecursiveから実行される
 *
 * @param array $newResult keyをcamel形式に変換して戻す配列
 * @param string $camelKey key値
 * @param string $value 値
 * @return string 変換後の値
 */
	private function __parseValueForCamelize($newResult, $camelKey, $value) {
		$callback = ['Inflector', 'variable'];

		if ($camelKey === 'title') {
			$newResult[$camelKey] = $value;
			$camelKey = call_user_func($callback, 'display_' . $camelKey);
			$newResult[$camelKey] = mb_strimwidth($value, 0, Topic::DISPLAY_TITLE_LENGTH, '...');

		} elseif ($camelKey === 'name') {
			$newResult[$camelKey] = $value;
			$camelKey = call_user_func($callback, 'display_' . $camelKey);
			$newResult[$camelKey] = mb_strimwidth($value, 0, Topic::DISPLAY_ROOM_NAME_LENGTH, '...');

		} elseif ($camelKey === 'summary') {
			$newResult[$camelKey] = $value;
			$camelKey = call_user_func($callback, 'display_' . $camelKey);
			$newResult[$camelKey] = mb_strimwidth($value, 0, Topic::DISPLAY_SUMMARY_LENGTH, '...');

		} elseif (in_array($camelKey, ['publishStart', 'created', 'modified'], true)) {
			$newResult[$camelKey] = $value;
			$camelKey = call_user_func($callback, 'display_' . $camelKey);
			$newResult[$camelKey] = $this->NetCommonsHtml->dateFormat($value);

		} elseif ($camelKey === 'titleIcon') {
			$newResult[$camelKey] = $this->NetCommonsHtml->titleIcon($value);

		} else {
			$newResult[$camelKey] = $value;
		}

		return $newResult;
	}

/**
 * keyによる変換処理
 * ※self::camelizeKeyRecursiveから実行される
 *
 * PHPMDでエラーになるが、別関数にすると見づらくなるため、PHPMD.CyclomaticComplexityで除外する
 *
 * @param array $newResult keyをcamel形式に変換して戻す配列
 * @return string 変換後の値
 * @SuppressWarnings(PHPMD.CyclomaticComplexity)
 */
	private function __getStatusLabel($newResult) {
		$topicStatus = Hash::get($newResult, 'topic.status');
		$blockPublicType = Hash::get($newResult, 'block.publicType');
		$topicPublishStart = Hash::get($newResult, 'topic.publishStart');
		$topicPublishEnd = Hash::get($newResult, 'topic.publishEnd');
		$answerPeriodEnd = Hash::get($newResult, 'topic.answerPeriodEnd');
		$labels = (new Topic())->statuses;

		$now = gmdate('Y-m-d H:i:s');

		if (in_array((int)$topicStatus, array_keys($labels), true)) {
			//承認待ち、差し戻し、一時保存
		} elseif ($now < $topicPublishStart) {
			//公開前
			$topicStatus = Topic::STATUS_BEFORE_PUBLISH;
		} elseif (Hash::get($newResult, 'topic.isAnswer')) {
			if ($topicPublishEnd && $topicPublishEnd < $now) {
				//公開終了
				$topicStatus = Topic::STATUS_BLOCK_END_PUBLISH;
			} elseif (Hash::get($newResult, 'topicUserStatus.answered')) {
				//回答済み
				$topicStatus = Topic::STATUS_ANSWERED;
			} elseif ($answerPeriodEnd && $answerPeriodEnd < $now) {
				//受付終了
				$topicStatus = Topic::STATUS_ANSWER_END;
			} elseif (Hash::get($newResult, 'topicUserStatus.read')) {
				//未回答
				$topicStatus = Topic::STATUS_UNANSWERED;
			} elseif (Current::read('User.id')) {
				//未確認
				$topicStatus = Topic::STATUS_UNCONFIRMED;
			}
		} elseif ($blockPublicType === Block::TYPE_PRIVATE) {
			//ブロック非公開
			$topicStatus = Topic::STATUS_BLOCK_PRIVATE;
		} elseif ($blockPublicType === Block::TYPE_LIMITED) {
			if ($now <= Hash::get($newResult, 'block.publishStart', '0000-00-00 00:00:00')) {
				//ブロック期限付き公開(公開前)
				$topicStatus = Topic::STATUS_BLOCK_BEFORE_PUBLISH;
			} elseif ($now > Hash::get($newResult, 'block.publishEnd', '9999-99-99 99:99:99')) {
				//ブロック期限付き公開(公開終了)
				$topicStatus = Topic::STATUS_BLOCK_END_PUBLISH;
			} else {
				//ブロック期限付き公開(公開中)
				$topicStatus = Topic::STATUS_BLOCK_PUBLISH;
			}
		} else {
			//公開中
		}

		return $this->Workflow->label($topicStatus, $labels);
	}

/**
 * ヘルプの表示
 *
 * @param string $content メッセージ内容(オリジナルタグの内容)
 * @param string $placement ポジション
 * @return string ヘルプHTML出力
 */
	public function rssSettingHelp($content = '', $placement = 'bottom') {
		$html = '';

		$content = __d('topics', 'Each of the embedded keywords, will be sent is converted ' .
				'to the corresponding content. <br />') . $content;

		$html .= __d('topics', 'Can use an embedded keyword in the channel title line and summary') . ' ';
		$html .= '<a href="" data-toggle="popover" data-placement="' . $placement . '"' .
					' title="' . __d('topics', 'Embedded keyword?') . '"' . ' data-content="' . $content . '">';
		$html .= '<span class="glyphicon glyphicon-question-sign"></span>';
		$html .= '</a>';
		$html .= '<script type="text/javascript">' .
			'$(function () { $(\'[data-toggle="popover"]\').popover({html: true}) });</script>';

		return $html;
	}

/**
 * ステータスの絞り込み
 *
 * @return string HTML出力
 */
	public function dropdownStatus() {
		$named = $this->_View->Paginator->params['named'];
		$named['page'] = '1';
		$named['limit'] = null;

		$options = Hash::merge(
			array('0' => __d('net_commons', 'All Statuses')),
			Hash::combine((new Topic())->statuses, '{n}.key', '{n}.message')
		);

		return $this->_View->element('Topics.Topics/select_status', array(
			'options' => $options,
			'current' => Hash::get($named, 'status', '0'),
			'url' => $named,
		));
	}

/**
 * 特定のブロックを表示する選択ボックス群の初期処理
 *
 * @return string HTML出力
 */
	public function initSelectBlock() {
		$selectBlocks = NetCommonsAppController::camelizeKeyRecursive(
			$this->_View->viewVars['selectBlocks']
		);
		$topicFramesBlock['topicFramesBlock'] = NetCommonsAppController::camelizeKeyRecursive(
			$this->_View->request->data['TopicFramesBlock']
		);

		$html = 'initBlocks(' .
			h(json_encode($selectBlocks, true)) . ', ' .
			h(json_encode($topicFramesBlock, true)) .
		')';
		return $html;
	}

/**
 * 特定のブロックを表示する選択ボックス群の
 *
 * @return string HTML出力
 */
	public function selectBlock() {
		$html = '';

		if ($this->_View->viewVars['selectBlocks']) {
			$html .= '<div class="form-inline form-group">';
			//ルーム選択
			$html .= $this->RoomsForm->selectRooms('TopicFramesBlock.room_id',
				array(
					'ng-model' => 'topicFramesBlock.roomId',
					//'ng-init' => 'selectBlockPluginKey = \'' . Hash::get($first, '0') . '\'',
					'ng-click' => 'blockOptions = optionBlocks()',
				)
			);

			//プラグイン選択
			$options = Hash::combine(
				$this->_View->viewVars['pluginsRoom'], '{n}.Plugin.key', '{n}.Plugin.name'
			);
			foreach (TopicFrameSetting::$outPlugins as $plugin) {
				$options = Hash::remove($options, $plugin);
			}
			$html .= $this->PluginsForm->selectPluginsRoom('TopicFramesBlock.plugin_key',
				array(
					'div' => false,
					'label' => false,
					'options' => $options,
					'ng-model' => 'topicFramesBlock.pluginKey',
					//'ng-init' => 'selectBlockPluginKey = \'' . Hash::get($first, '0') . '\'',
					'ng-click' => 'blockOptions = optionBlocks()',
				)
			);

			$html .= '</div>';
		}

		//ブロック選択
		$html .= '<div class="form-group" ng-init="blockOptions = optionBlocks()">';

		if ($this->_View->viewVars['selectBlocks']) {
			$html .= $this->NetCommonsForm->select('TopicFramesBlock.block_key',
				Hash::combine($this->_View->viewVars['selectBlocks'], '{s}.{s}.key', '{s}.{s}.name'),
				array(
					'size' => 10, 'class' => 'form-control', 'empty' => false,
					'ng-options' => 'item as item.name for item in blockOptions track by item.key',
					'ng-model' => 'topicFramesBlock.blockKey',
					'ng-show' => 'blockOptions',
				)
			);
		}
		$html .= '<div ng-hide="blockOptions">';
		$html .= __d('topics', 'No block found.');
		$html .= '</div>';

		$html .= '</div>';

		return $html;
	}

}
