<?php


namespace IPS\chatbox\Member;

/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
	header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
	exit;
}

/**
 * Member Conversation Model
 */
class _Conversation extends \IPS\Content\Item
{

	/**
	 * @brief	Database Table
	 */
	public static $databaseTable = 'chatbox_conversations';
	
	/**
	 * @brief	Database Prefix
	 */
	public static $databasePrefix = 'con_';
	
	/**
	 * @brief	Multiton Store
	 */
	protected static $multitons;

	/**
	 * @brief	[Content\Item]	Include the ability to search this content item in global site searches
	 */
	public static $includeInSiteSearch = FALSE;

	/**
	 * @brief	[Content\Comment]	Icon
	 */
	public static $icon = 'comments';

	/**
	 * Delete Record
	 *
	 * @return	void
	 */
	public function delete()
	{
		\IPS\Db::i()->delete( 'chatbox_conversations_user_map', array( 'map_con_id=?', $this->id ) );
		\IPS\Task::queue( 'chatbox', 'deleteMsg', array( 'convo' => $this->id ), 4 );
		
		parent::delete();
	}
	
	/**
	 * @brief	Title
	 */
	public static $title = 'chatbox_conversation';
	
	/**
	 * @brief	Database Column Map
	 */
	public static $databaseColumnMap = array(
		'title'				=> 'name',
		'date'				=> 'started_date',
		'author'			=> 'starter_id'
	);
	
	/**
	 * @brief	Application
	 */
	public static $application = 'chatbox';
	
	/**
	 * @brief	Module
	 */
	public static $module = 'conversation';
	
	/**
	 * @brief	Language prefix for forms
	 */
	public static $formLangPrefix = 'chatbox_con_';
	
	/**
	 * @brief	Comment Class
	 */
	public static $commentClass = 'IPS\chatbox\Member\Post';
	
	/**
	 * @brief	[Content\Item]	First "comment" is part of the item?
	 */
	//public static $firstCommentRequired = FALSE;
	
	/**
	 * Should posting this increment the poster's post count?
	 *
	 * @param	\IPS\Node\Model|NULL	$container	Container
	 * @return	void
	 */
	public static function incrementPostCount( \IPS\Node\Model $container = NULL )
	{
		return FALSE;
	}
	
	/**
	 * [Node] Get Title
	 *
	 * @return	string|null
	 */
	public function get_title()
	{
		if ( $this->name )
		{
			return strip_tags( preg_replace( "/\r|\n|\t/", "", html_entity_decode( $this->name ) ) );
		}
			
		if ( !$this->isGroup )
		{
			foreach ( $this->participants() as $u )
			{
				$chatters[] = $u->name;
			}
			return implode(' - ', $chatters);
		}
		else
		{
			$el = \IPS\chatbox\Member\Conversation::elGroup( $this->id, $this->participants() );
			return $el['title'];
		}
	}		
	
	/*-------------------------------------------------------------------------*/
	// Display a conversation
	/*-------------------------------------------------------------------------*/	
	public function show()
	{
		# Disable sound by default?
		if ( \IPS\Settings::i()->chatbox_sound_disable == 1 && !isset( \IPS\Request::i()->cookie[ 'chatbox_con_nosound_' . $this->id ] ) )
		{
			\IPS\Request::i()->setCookie( 'chatbox_con_nosound_' . $this->id, 1, NULL, FALSE );
		}	

		# Returl html
		return \IPS\Theme::i()->getTemplate( 'conversation', 'chatbox', 'front' )->conversation( $this );		
	}
	 
	 
	/**
	 * Can Merge?
	 *
	 * @param	\IPS\Member|NULL	$member	The member to check for (NULL for currently logged in member)
	 * @return	bool
	 */
	public function canMerge( $member=NULL )
	{
		return FALSE;
	}

	/**
	 * Permissions
	 */
	public function canView( $member=NULL )
	{
		return $this->canChat( $member );
	}
	
	public function canChat( $member=NULL )
	{
		$member = $member ?: \IPS\Member::loggedIn();
		
		if ( !self::_canStart() && !self::_canJoin() )
		{
			return FALSE;
		}
		
		foreach ( $this->maps() as $map )
		{
			if ( $map['map_user_id'] === \IPS\Member::loggedIn()->member_id )
			{
				return TRUE;
			}
		}
		
		return FALSE;		
	}
	
	public static function _canUse( $member=NULL )
	{
		$member = $member ?: \IPS\Member::loggedIn();

		if ( self::_isBan() )
		{
			return FALSE;
		}
		
		if ( $member->inGroup( explode( ",", \IPS\Settings::i()->chatbox_con_can ) ) || $member->inGroup( explode( ",", \IPS\Settings::i()->chatbox_con_get ) ) )
		{
			return TRUE;		
		}
		
		return FALSE;	
	}		
	
	public static function _canStart( $member=NULL )
	{
		$member = $member ?: \IPS\Member::loggedIn();

		if ( ! \IPS\Settings::i()->chatbox_bar_con || \IPS\chatbox\Member\Conversation::_isBan() )
		{
			return FALSE;
		}
		
		if ( $member->inGroup( explode( ",", \IPS\Settings::i()->chatbox_con_can ) ) )
		{
			return TRUE;		
		}
		
		return FALSE;		
	}	
	
	public static function _canJoin( $member=NULL )
	{
		$member = $member ?: \IPS\Member::loggedIn();
		
		if ( ! \IPS\Settings::i()->chatbox_bar_con || \IPS\chatbox\Member\Conversation::_isBan() )
		{
			return FALSE;
		}		
		
		if ( $member->inGroup( explode( ",", \IPS\Settings::i()->chatbox_con_get ) ) )
		{
			return TRUE;		
		}
		
		return FALSE;		
	}	
	

	public static function _canCreateGroup( $member=NULL )
	{
		$member = $member ?: \IPS\Member::loggedIn();
		
		if ( \IPS\chatbox\Member\Conversation::_canStart() && $member->inGroup( explode( ",", \IPS\Settings::i()->chatbox_con_can_groups ) ) )
		{
			return TRUE;
		}

		return FALSE;		
	}		

	public function canEditMsg( $chat, $member=NULL )
	{
		$member = $member ?: \IPS\Member::loggedIn();
		
		if ( $member->group['g_edit_cutoff'] )
		{
			if( \IPS\DateTime::ts( $chat->time )->add( new \DateInterval( "PT{$member->group['g_edit_cutoff']}M" ) ) <= \IPS\DateTime::create() )
			{
				return FALSE;
			}
		}
		
		if ( self::_canManage() )
		{
			return TRUE;
		}

		if ( !$chat->item()->canChat() )
		{
			return FALSE;
		}
		
		if ( $chat->member_id > 0 && $member->member_id == $chat->member_id )
		{
			$opts = self::options();
			return $opts['bar_perm_edit'] == 1 ? TRUE : FALSE;	
		}
		
		return FALSE;		
	}
	
	public static function _canDelete( $chatterID=0, $member=NULL )
	{
		if ( self::_canManage() )
		{
			return TRUE;
		}

		$member = $member ?: \IPS\Member::loggedIn();
		
		if ( $chatterID > 0 && $member->member_id == $chatterID )
		{
			$opts = self::options();
			return $opts['bar_perm_del'] == 1 ? TRUE : FALSE;
		}
		
		return FALSE;		
	}		
	
	public function canDeleteCon( $member=NULL )
	{
		$member = $member ?: \IPS\Member::loggedIn();
		
		if ( !$this->canChat() )
		{
			return FALSE;
		}

		if ( $this->isGroup )
		{
			return $this->isGroupOwner() ? TRUE : FALSE;		
		}
		else
		{
			return $member->inGroup( explode( ",", \IPS\Settings::i()->chatbox_con_can_delete_con ) ) ? TRUE : FALSE;
		}

		return FALSE;		
	}
	
	public function canInviteGroup( $member=NULL )
	{
		$member = $member ?: \IPS\Member::loggedIn();
		
		if ( !$this->isGroup || !$this->canChat() )
		{
			return FALSE;
		}
		
		$opts = $this->groupOptions();
		
		if ( $opts['mem_invite'] || $this->isGroupOwner() )
		{
			return TRUE;
		}
		
		return FALSE;
	}
	
	public static function _canBypassFlood( $member=NULL )
	{
		$member = $member ?: \IPS\Member::loggedIn();

		if ( $member->inGroup( explode( ",", \IPS\Settings::i()->chatbox_con_can_bypass_flood ) ) )
		{
			return TRUE;		
		}		
		
		return FALSE;		
	}
	
	public static function _isBan( $member=NULL )
	{
		$member = $member ?: \IPS\Member::loggedIn();
	
		if ( ( $member->member_id > 0 && ( $member->restrict_post !== 0 || $member->temp_ban !== 0 ) ) || !$member->member_id )
		{
			return TRUE;
		}
		
		if ( $member->inGroup( explode( ",", \IPS\Settings::i()->chatbox_con_ban_groups ) ) )
		{
			return TRUE;		
		}		
		
		if ( \in_array( $member->member_id, explode( "\n", \IPS\Settings::i()->chatbox_con_ban_users ) ) )
		{
			return TRUE;
		}
		
		return FALSE;		
	}
	
	public function canDonate( $member=NULL )
	{
		return FALSE;	
	}
	
	public function canUpload( $member=NULL )
	{
		$member = $member ?: \IPS\Member::loggedIn();
		
		$opts = self::options();
		
		if ( !$opts['allow_img'] || $opts['use_editor'] )
		{
			return FALSE;
		}

		if ( $member->inGroup( explode( ",", \IPS\Settings::i()->chatbox_con_can_upload ) ) )
		{
			return TRUE;		
		}

		return FALSE;	
	}
	
	/**
	 * Can Manage?
	 */		
	public static function _canManage( $member=NULL )
	{
		$member = $member ?: \IPS\Member::loggedIn();
		
		if ( $member->isAdmin() )
		{
			return TRUE;		
		}

		return FALSE;		
	}

	/**
	 * @brief	Cached URLs
	 */
	protected $_url	= array();

	/**
	 * Get URL
	 *
	 * @param	string|NULL		$action		Action
	 * @return	\IPS\Http\Url
	 */
	public function url( $action=NULL )
	{
		$_key	= md5( $action );

		if( !isset( $this->_url[ $_key ] ) )
		{
			$this->_url[ $_key ] = \IPS\Http\Url::internal( "app=chatbox&module=conversation&controller=conversation&id={$this->id}", 'front', 'chatbox_convo' );
		
			if ( $action )
			{
				$this->_url[ $_key ] = $this->_url[ $_key ]->setQueryString( 'do', $action );
			}
		}
	
		return $this->_url[ $_key ];
	}
	
	/**
	 * Get the map for the current member
	 *
	 * @return	mixed
	 */
	public function get_map()
	{
		$maps = $this->maps();
		
		if ( isset( $maps[ \IPS\Member::loggedIn()->member_id ] ) )
		{
			return $maps[ \IPS\Member::loggedIn()->member_id ];
		}
		
		throw new \OutOfRangeException;
	}
	
	
	/**
	 * @brief	Maps cache
	 */
	protected $maps = NULL;
	
	/**
	 * Get maps
	 */
	public function maps( $refresh = FALSE )
	{
		if ( $this->maps === NULL || $refresh === TRUE )
		{
			$this->maps = iterator_to_array( \IPS\Db::i()->select( '*', 'chatbox_conversations_user_map', array( 'map_con_id=?', $this->id ) )->setKeyField( 'map_user_id' ) );
		}
		return $this->maps;
	}

	/*-------------------------------------------------------------------------*/
	// Options
	/*-------------------------------------------------------------------------*/		
	protected static $_opts = NULL;
	
	public static function options()
	{
		if ( static::$_opts !== NULL )
		{
			return static::$_opts;
		}
		
		$data = json_decode( \IPS\Settings::i()->chatbox_con_configs, true );

		if ( !$data )
		{
			$data = array (
				'style' 				=> 'standard',
				'skin' 					=> 'white',
				'height' 				=> 420,
				'sort' 					=> 'asc',
				'limit' 				=> 20,
				'interval' 				=> 10000,
				'flood' 				=> 5,
			);
		}
		
		if ( \IPS\Settings::i()->chatbox_con_notifile )
		{
			try
			{
				$data['soundfile'] = (string) \IPS\File::get( 'chatbox_Nofifile', \IPS\Settings::i()->chatbox_con_notifile )->url;
			}
			catch( \Exception $ex ) { }			
		}
		
		static::$_opts = $data;
		return static::$_opts;		
	}
	
	public static function jsVars()
	{
		$opts = self::options();

		$data = array(
			'interval' 			=> (int) $opts['interval'],
			'flood' 			=> (int) $opts['flood'],
			'limit' 			=> (int) $opts['limit'],		
			'length' 			=> (int) $opts['length'],
			'sort' 				=> $opts['sort'],
			'style' 			=> $opts['style'],
			'giphy' 			=> $opts['giphy'],
			'autogrow' 			=> $opts['autogrow'],
			'allow_img' 		=> $opts['allow_img'] ? true : false,
			'allow_video' 		=> $opts['allow_video'] ? true : false,		
			'allow_audio' 		=> $opts['allow_audio'] ? true : false,	
			'allow_select_skins'=> $opts['allow_select_skins'] ? true : false,		
			'autoload' 			=> $opts['autoload'] ? true : false,		
			'use_editor' 		=> $opts['use_editor'] ? true : false,
			'enter_editor' 		=> $opts['enter_editor'] ? true : false,
			'soundfile' 		=> $opts['soundfile']? $opts['soundfile'] : NULL,
			'no_counter_popup' 	=> $opts['no_counter_popup'] ? true : false,
			'canManage' 		=> self::_canManage() ? true : false,
			'canBypassFlood' 	=> self::_canBypassFlood() ? true : false,
		);

		# Return js vars
		$vars[ 'chatbox_conversations' ] = $data;
		\IPS\Output::i()->endBodyCode .= \IPS\Theme::i()->getTemplate( 'embed', 'chatbox', 'front' )->chatvars( $vars );
	}
	
	/**
	 * Display conversations & rooms
	 */	
	public static function showPopupCon()
	{
		if ( \IPS\Request::i()->cookie['chatbox_disable_member_chat'] == 1 || \IPS\Settings::i()->chatbox_bar_con != 1 || ! \IPS\chatbox\Member\Conversation::_canUse() )
		{
			return;
		}
		
		self::jsVars();
		
		$settings = self::options();
		
		if ( \IPS\Settings::i()->chatbox_bar_pos == 'right' )
		{
			$html .= self::restoreOpenedPopups();
		}
		
		$html .= \IPS\Theme::i()->getTemplate( 'conversation', 'chatbox', 'front' )->main( $settings );
		
		if ( \IPS\Settings::i()->chatbox_bar_pos == 'left' )
		{
			$html .= self::restoreOpenedPopups();
		}
		
		return $html;
	}	
	
	/*-------------------------------------------------------------------------*/
	// Get participants
	/*-------------------------------------------------------------------------*/
	protected $participants = NULL;
	
	public function participants()
	{
		if( $this->participants !== NULL )
		{
			return $this->participants;
		}
		
		foreach( $this->maps() as $mid => $data )
		{
			$member = \IPS\Member::load( $mid );
			
			if ( !$member->member_id )
			{
				if ( !$this->isGroup )
				{
					$this->delete();
				}
				else \IPS\Db::i()->delete( 'chatbox_conversations_user_map', array( 'map_con_id=? AND map_user_id=?', $this->id, $mid ) );
			}
			else
			{
				$this->participants[ $mid ] = $member;
			}
		}
		
		return $this->participants;
	}

	/*-------------------------------------------------------------------------*/
	// Restore opened popups
	/*-------------------------------------------------------------------------*/	 
	protected static function restoreOpenedPopups()
	{
		$mid = \IPS\Member::loggedIn()->member_id;
		
		if ( $mid > 0 )
		{
			$cookieName = 'chatbox_tabs_' . $mid;
			
			if ( ! \IPS\Request::i()->cookie[ $cookieName ] )
			{
				return;
			}
			
			$popups = explode( "|", \IPS\Request::i()->cookie[ $cookieName ] );

			foreach( $popups as $k => $p )
			{
				$v = explode("_", $p);
				
				if ( $v[0] == "r" ) // room popups
				{
					try
					{
						$room = \IPS\chatbox\Rooms\Room::load( $v[1] );
						if ( ! $room->_canView() )
						{
							unset( $popups[$k] );
						}
						$html .= (string) $room->show(NULL, TRUE, TRUE);
					}
					catch( \OutOfRangeException $e ) 
					{
						unset( $popups[$k] );
					}
				}
				elseif ( $v[0] == "c" ) // chat popups
				{
					try
					{
						$con = \IPS\chatbox\Member\Conversation::load( $v[1] );

						if ( ! $con->canChat() || $con->maps()[$mid]['map_online'] == -1 )
						{
							unset( $popups[$k] );
						}
						else
						{
							$html .= (string) $con->show();
						}
					}
					catch( \OutOfRangeException $e ) 
					{
						unset( $popups[$k] );
					}					
				}
			}
			
			if ( $popups )
			{
				\IPS\Request::i()->setCookie( $cookieName, implode("|", $popups), NULL, FALSE );
			}
			else
			{
				\IPS\Request::i()->setCookie( $cookieName, NULL );
			}
			
			return $html;
		}
	}
	 	
	/*-------------------------------------------------------------------------*/
	// Find existing conversation with someone
	/*-------------------------------------------------------------------------*/	 
	public static function findConvo( $receiver )
	{	
		$convo = NULL;
		$me = \IPS\Member::loggedIn();
		
		$mConWhere[] = array( 'con.con_isGroup=0 AND map.map_user_id=? AND map.map_online=?', $me->member_id, 1 );
		$myCons = iterator_to_array( \IPS\Db::i()->select( 'map.map_con_id', array( 'chatbox_conversations_user_map', 'map' ), $mConWhere )->join( array('chatbox_conversations', 'con'), 'con.con_id=map.map_con_id' ) );	
		
		if ( $myCons )
		{
			try
			{
				$where[] = array( 'map_user_id=?', $receiver->member_id );
				$where[] = array( \IPS\Db::i()->in( 'map_con_id', $myCons ) );
				$conID = \IPS\Db::i()->select( 'map_con_id', 'chatbox_conversations_user_map', $where )->first();
				$convo = \IPS\chatbox\Member\Conversation::load( $conID );
			}
			catch ( \UnderflowException $e ){}			
		}

		if ( !$convo )
		{
			$convo = \IPS\chatbox\Member\Conversation::createItem( $me, NULL, \IPS\DateTime::create(), NULL );
			$convo->save();
			
			\IPS\Db::i()->insert( 'chatbox_conversations_user_map', array(
				'map_user_id'		=> \IPS\Member::loggedIn()->member_id,
				'map_con_id'		=> $convo->id
			) );
			
			\IPS\Db::i()->insert( 'chatbox_conversations_user_map', array(
				'map_user_id'		=> $receiver->member_id,
				'map_con_id'		=> $convo->id
			) );				
		}

		return $convo;
	}

	/*-------------------------------------------------------------------------*/
	// Update last post ID
	/*-------------------------------------------------------------------------*/	 
	public function updateLastID()
	{
		$this->lastID = $this->comments(1, 0, 'chat_id', 'desc')->id;
		$this->save();
	}
	
	/*-------------------------------------------------------------------------*/
	// Mark message as edited or deleted
	/*-------------------------------------------------------------------------*/
	public function markMsg( $id, $content=NULL )
	{
		$cache = array();
		
		if ( isset( \IPS\Data\Store::i()->chatbox_con_changes ) )
		{
			$cache = \IPS\Data\Store::i()->chatbox_con_changes;
		}
		
		foreach ( $this->maps() as $map )
		{
			if ( $map['map_user_id'] != \IPS\Member::loggedIn()->member_id )
			{
				$cache[ $map['map_user_id'] ][ $id ] = $content;
			}
		}

		\IPS\Data\Store::i()->chatbox_con_changes = $cache;
	}
	

	/**
	 * Load Editor
	 */	
	public function editor( $chat=NULL )
	{
		$opts = self::options();
		
		$editorName = 'chatCON_' . $this->id;
		
		$url = \IPS\Http\Url::internal( "app=chatbox&module=conversation&controller=main" )->setQueryString( array( 'conID' => $this->id ) );
		
		if ( $chat )
		{
			$url = $url->setQueryString( array( 'do' => 'editEditor', 'chatID' => $chat->id ) );
			$btn = 'chatbox_edit';
			$editorName .= '_' . $chat->id;
		}
		else
		{
			$url = $url->setQueryString( array( 'do' => 'postEditor' ) );
			$btn = 'chatbox_send';
		}
	
		$form = new \IPS\Helpers\Form( 'cbForm', $btn, $url );
		$form->class = 'ipsForm_vertical chatboxEditor';
		
		if ( $opts['use_editor'] )
		{
			$form->add( new \IPS\Helpers\Form\Editor( $editorName, ( $chat ) ? $chat->content : NULL, TRUE, array(
				'app'			=> 'chatbox',
				'key'			=> 'conMSG',
				'autoSaveKey' 	=> 'con_msg' . ( ( $chat !== NULL ) ? '_' . $chat->id : '' ),
				'minimize'		=> NULL,
				'attachIds'		=> ( $chat === NULL ) ? NULL : array( $chat->id, NULL, $chat->member_id ),
				'autoGrow'		=> TRUE,
				'maxLength'		=> $opts['length'] > 0 ? $opts['length'] : NULL,
			) ) );
		}
		else
		{
			$form->add( new \IPS\Helpers\Form\TextArea( $editorName, ( $chat ) ? $chat->content : NULL, FALSE, array( 
				'rows' 			=> 1,
				'class'			=> 'chatInput',
				'placeholder'	=> \IPS\Member::loggedIn()->language()->addToStack('chatbox_input_pl'),
			) ) );
			
			if ( $this->canUpload() )
			{
				$form->add( \IPS\Application::load('chatbox')->uploader( 'file_con_' . $this->id, $chat ) );
			}			
		}
		
		return $form;		
	}	

	/*-------------------------------------------------------------------------*/
	// Generate title and avatar for group chat
	/*-------------------------------------------------------------------------*/
	protected static $_elGroups = NULL;
	
	public static function elGroup( $conID, $data )
	{
		if( static::$_elGroups[ $conID ] !== NULL )
		{
			return static::$_elGroups[ $conID ];
		}

		$names = array();
		$photos = array();
		$cnt = 0;
		$totalUsers = $data ? \count( $data ) : 0;
		$maxNameInTitle = 5;

		foreach ( $data as $mid => $r )
		{
			if ( $mid != \IPS\Member::loggedIn()->member_id )
			{
				$cnt++;
				$names[] = \is_array( $r ) ? $r['name'] : $r->name;
				$photos[] = \is_array( $r ) ? \IPS\Member::photoUrl( $r ) : $r->photo;
				if ( $cnt == $maxNameInTitle )
				{
					break;
				}
			}
		}
		
		$icon = \IPS\Theme::i()->getTemplate( 'conversation', 'chatbox', 'front' )->groupAvatar( $photos );
		
		if ( !$names )
		{
			$title = \IPS\Member::loggedIn()->language()->addToStack( 'chatbox_new_group_title' );
		}
		else
		{
			$t = implode(', ', $names);
			$title = $totalUsers <= $maxNameInTitle ? $t : \IPS\Member::loggedIn()->language()->addToStack( 'chatbox_group_title_more', FALSE, array( 'sprintf' => array( $t, $totalUsers - $maxNameInTitle ) ) );
		}	
		
		static::$_elGroups[ $conID ] = array( 'icon' => $icon, 'title' => $title );
		
		return static::$_elGroups[ $conID ];
	}	
	
	/*-------------------------------------------------------------------------*/
	// Is Group Owner
	/*-------------------------------------------------------------------------*/
	public function isGroupOwner()
	{
		if ( $this->isGroup == 1 && $this->starter_id == \IPS\Member::loggedIn()->member_id )
		{
			return TRUE;
		}
		return FALSE;
	}	
	
	/*-------------------------------------------------------------------------*/
	// Add system msg
	/*-------------------------------------------------------------------------*/		
	public function addSystemMsg( $type, $content )
	{
		$time = time();
		
		$id = \IPS\Db::i()->insert( 'chatbox_conversations_posts', array(
			'chat_con'			=> $this->id,
			'chat_member_id'	=> -1,
			'chat_content'		=> $content,
			'chat_sys'			=> $type,
			'chat_time'			=> $time,
		) );
		
		$this->lastID = $id;
		$this->save();		
	}
	
	/*-------------------------------------------------------------------------*/
	// Group Options
	/*-------------------------------------------------------------------------*/		
	protected static $_gopts = NULL;
	
	public function groupOptions()
	{
		if ( static::$_gopts !== NULL )
		{
			return static::$_gopts;
		}
		
		$data = json_decode( $this->group_options, true );

		static::$_gopts = $data;
		
		return static::$_gopts;		
	}	
}