<?php
namespace JExtstore\Component\JChat\Administrator\Model;
/**
 *
 * @package JCHAT::MESSAGES::administrator::components::com_jchat
 * @subpackage models
 * @author Joomla! Extensions Store
 * @Copyright (C) 2015 - Joomla! Extensions Store
 * @license GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html 
 */
defined ( '_JEXEC' ) or die ( 'Restricted access' );
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\Language\Text;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Component\ComponentHelper;
use JExtstore\Component\JChat\Administrator\Framework\Model as JChatModel;
use JExtstore\Component\JChat\Administrator\Framework\Exception as JChatException;

/**
 * Messages model responsibilities contract
 *
 * @package JCHAT::MESSAGES::administrator::components::com_jchat
 * @subpackage models
 * @since 1.0
 */
interface IMessagesModel {
	/**
	 * Esplica la funzione di esportazione della lista messaggi
	 * in formato CSV per i record estratti dai filtri userstate attivi
	 * @access public
	 * @param array $fieldsToLoadArray
	 * @param array& $fieldsFunctionTransformation
	 * @return Object[]&
	 */
	public function exportMessages($fieldsToLoadArray, &$fieldsFunctionTransformation);
}
 
/**
 * Messages model responsibilities
 *
 * @package JCHAT::MESSAGES::administrator::components::com_jchat
 * @subpackage models
 * @since 1.0
 */
class MessagesModel extends JChatModel implements IMessagesModel {
	/**
	 * Restituisce la query string costruita per ottenere il wrapped set richiesto in base
	 * allo userstate, opzionalmente seleziona i campi richiesti
	 * 
	 * @access private
	 * @return string
	 */
	protected function buildListQuery($fields = 'a.*') {
		// WHERE
		$where = array();
		$whereString = null;
				
		//Filtro testo
		if($this->state->get('searchword')) {
			$where[] = "\n (a.actualfrom LIKE " .
						$this->dbInstance->quote('%' . $this->state->get('searchword') . '%') .
						"\n OR a.actualto LIKE " . 
						$this->dbInstance->quote('%' . $this->state->get('searchword'). '%')  . 
						"\n OR a.message LIKE " . 
						$this->dbInstance->quote('%' . $this->state->get('searchword'). '%') . ")";
		}
		
		//Filtro periodo
		if($this->state->get('fromPeriod')) {
			$strToTimeFrom = strtotime($this->state->get('fromPeriod'));
			if($strToTimeFrom) {
				$where[] = "\n a.sent > " . $strToTimeFrom;
			}
		}
		
		if($this->state->get('toPeriod')) {
			$strToTimeTo = strtotime($this->state->get('toPeriod'));
			if($strToTimeTo) {
				$where[] = "\n a.sent < " . ($strToTimeTo + 60*60*24);
			}
		}
		
		if($this->state->get('msgType')) {
			$where[] = "\n a.type = " .  $this->dbInstance->quote($this->state->get('msgType'));
		}
		
		if($this->state->get('msgStatus')) {
			$status = (int)$this->state->get('msgStatus') - 1;
			switch($status) {
				case 1:
				case 0:
					$where[] = "\n a.read = $status AND a.to != " . $this->dbInstance->quote('0');
					break;
					
				case -2:
					$where[] = "\n a.read = 0 AND a.to = " . $this->dbInstance->quote('0');
					break;
			}
		}
		
		if($this->state->get('roomsFilter')) {
			$where[] = "\n a.sentroomid = " . (int)$this->state->get('roomsFilter');
		}
		  
		if (count($where)) {
			$whereString = "\n WHERE " . implode ("\n AND ", $where);
		}
		
		// ORDERBY
		if($this->state->get('order')) {
			$orderString = "\n ORDER BY " . $this->state->get('order') . " ";
		}
		
		//Filtro testo
		if($this->state->get('order_dir')) {
			$orderString .= $this->state->get('order_dir');
		}
		
		$query = "SELECT $fields, r.name AS roomname" .
				 "\n FROM #__jchat AS a" .
				 "\n LEFT JOIN #__jchat_rooms AS r" .
				 "\n ON a.sentroomid = r.id" .
				 $whereString .
				 $orderString;
		return $query;
	}
	
	/**
	 * Main get data method
	 * 
	 * @access public
	 * @return Object[]
	 */
	public function getData(): array {
		// Build query
		$query = $this->buildListQuery ();
		try {
			$dbQuery = $this->dbInstance->getQuery ( true )->setQuery ( $query )->setLimit ( $this->getState ( 'limit' ), $this->getState ( 'limitstart' ) );
			$this->dbInstance->setQuery ( $dbQuery );
			$result = $this->dbInstance->loadObjectList ();
		} catch ( JChatException $e ) {
			$this->app->enqueueMessage ( $e->getMessage (), $e->getErrorLevel () );
			$result = array ();
		} catch ( \Exception $e ) {
			$jchatException = new JChatException ( $e->getMessage (), 'error' );
			$this->app->enqueueMessage ( $jchatException->getMessage (), $jchatException->getErrorLevel () );
			$result = array ();
		}
		return $result;
	}
	
	/**
	 * Restituisce le select list usate dalla view per l'interfaccia
	 * @access public
	 * @return array
	 */
	public function getFilters(): array {
		$lists = [];
		$types = [];
		$status = [];
		 
		$types[] = HTMLHelper::_('select.option',  '0', '- '. Text::_('COM_JCHAT_MESSAGE_TYPE' ) .' -' ); 
		$types[] = HTMLHelper::_('select.option', 'file', Text::_('COM_JCHAT_FILE_MESSAGE' ) );
		$types[] = HTMLHelper::_('select.option', 'message', Text::_('COM_JCHAT_TEXT_MESSAGE' ) );
		$lists['type'] 	= HTMLHelper::_('select.genericlist', $types, 'msg_type', 'class="inputbox input-medium d-none d-md-inline-flex" size="1" onchange="document.adminForm.task.value=\'messages.display\';document.adminForm.submit( );"', 'value', 'text', $this->state->get('msgType'));
			
		$status[] = HTMLHelper::_('select.option',  '', '- '. Text::_('COM_JCHAT_STATUS_MSGS' ) .' -' );
		$status[] = HTMLHelper::_('select.option', '2', Text::_('COM_JCHAT_DISPLAYED_MSGS' ) );
		$status[] = HTMLHelper::_('select.option', '1', Text::_('COM_JCHAT_NOT_DISPLAYED_MSGS' ) );
		$status[] = HTMLHelper::_('select.option', '-1', Text::_('COM_JCHAT_TO_GROUP_MSGS' ) );
		$lists['status'] = HTMLHelper::_('select.genericlist', $status, 'msg_status', 'class="inputbox input-medium d-none d-md-inline-flex" size="1" onchange="document.adminForm.task.value=\'messages.display\';document.adminForm.submit( );"', 'value', 'text', $this->state->get('msgStatus'));
			
		// Select rooms to filter messages exchanged
		$query = "SELECT" .
				 "\n " . $this->dbInstance->quoteName('id') . " AS value," .
				 "\n " . $this->dbInstance->quoteName('name') . " AS text" .
				 "\n FROM #__jchat_rooms" .
				 "\n WHERE" .
				 "\n " . $this->dbInstance->quoteName('published') . " = 1";
		$rooms = $this->dbInstance->setQuery($query)->loadObjectList();
		array_unshift($rooms, HTMLHelper::_('select.option',  '', '- '. Text::_('COM_JCHAT_ROOMS_FILTER' ) .' -' ));
		$lists['rooms'] = HTMLHelper::_('select.genericlist', $rooms, 'rooms_filter', 'class="inputbox input-medium d-none d-md-inline-flex" size="1" onchange="document.adminForm.task.value=\'messages.display\';document.adminForm.submit( );"', 'value', 'text', $this->state->get('roomsFilter'));
		
		return $lists;
	}
 
	/**
	 * Esplica la funzione di esportazione della lista messaggi
	 * in formato CSV per i record estratti dai filtri userstate attivi
	 * @access public
	 * @param array $fieldsToLoadArray
	 * @param array& $fieldsFunctionTransformation
	 * @return Object[]&
	 */
	public function exportMessages($fieldsToLoadArray, &$fieldsFunctionTransformation) { 
		$fieldsName = array(); 
		if(is_array($fieldsToLoadArray) && count($fieldsToLoadArray)) {
			$arrayIter = new \ArrayIterator($fieldsToLoadArray);
			while ($arrayIter->valid()) { 
				$fieldName = $arrayIter->key();
				$transformedFieldName = $arrayIter->current();
				// Assegnamento duplice name->transformation
				$fieldsName[] = $fieldName;
				$fieldsFunctionTransformation[] = $transformedFieldName;
		
				// Increment pointer
				$arrayIter->next();
			}
		}
		
		$fieldsFunctionTransformation[] = Text::_('COM_JCHAT_ROOM');
		$joinedFieldsName = implode(',', $fieldsName);
		
		// Obtain query string
		$query = $this->buildListQuery($joinedFieldsName);
		$dbQuery = $this->dbInstance->getQuery ( true )->setQuery ( $query )->setLimit ( $this->getState ( 'limit' ), $this->getState ( 'limitstart' ) );
		$this->dbInstance->setQuery ( $dbQuery );
		$resultSet = $this->dbInstance->loadAssocList();
		
		if(!is_array($resultSet) || !count($resultSet)) {
			return false;
		}
		
		return $resultSet;
	}
	
	/**
	 * Purge the cache of all messages in a single operation
	 * 
	 * @access public
	 * @param boolean $oldest
	 * @return boolean
	 */
	public function deleteEntities($oldest) {
		$where = null;
		try {
			if($oldest) {
				$daysSaved = (int)($this->getState('cparams')->get('keep_latest_msgs', 7));
				if($daysSaved) {
					$where = "\n WHERE chat.sent < " . strtotime("-$daysSaved days", time());
				}
			}
			$query = "DELETE " . 
					 $this->dbInstance->quoteName('chat') . "," .
					 $this->dbInstance->quoteName('readmsgs') . "," .
					 $this->dbInstance->quoteName('deletedmsgs') .
					 "\n FROM #__jchat AS chat" .
					 "\n LEFT JOIN #__jchat_public_readmessages AS readmsgs" .
					 "\n ON chat.id = readmsgs.messageid" .
					 "\n LEFT JOIN #__jchat_messaging_deletedmessages AS deletedmsgs" .
					 "\n ON chat.id = deletedmsgs.messageid" .
					 $where;
			$this->dbInstance->setQuery($query);
			$this->dbInstance->execute();
		} catch (JChatException $e) {
			$this->setError($e);
			return false;
		} catch (\Exception $e) {
			$jchatException = new JChatException($e->getMessage(), 'error');
			$this->setError($jchatException);
			return false;
		}
		return true;
	}
	
	/**
	 * Class constructor
	 *
	 * @access public
	 * @param $config array
	 * @return Object&
	 */
	public function __construct($config = array(), MVCFactoryInterface $factory = null) {
		parent::__construct ( $config, $factory );

		$componentParams = ComponentHelper::getParams($this->option);
		$this->setState('cparams', $componentParams);
	}
} 