<?php

class NP_XBEL extends NucleusPlugin {

   /* ==========================================================================================
	* XBEL Reader 0.14 for Nuclues CMS
	* Display bookmarks from an XBEL file on your blog
	*
	* Copyright 2004 by Niels Leenheer
	* ==========================================================================================
	* This program is free software and open source software; you can redistribute
	* it and/or modify it under the terms of the GNU General Public License as
	* published by the Free Software Foundation; either version 2 of the License,
	* or (at your option) 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 General Public License for
	* more details.
	*
	* You should have received a copy of the GNU General Public License along
	* with this program; if not, write to the Free Software Foundation, Inc.,
	* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  or visit
	* http://www.gnu.org/licenses/gpl.html
	* ==========================================================================================
	*
	* 0.14   - Again rewritten large parts of the charset conversion
	* 0.13   - Replaced code for charset conversion with faster optimized version
	* 0.12   - Added proper support for UTF-8 encoded RSS and Atom feeds
	*        - Added charset conversion for more exotic feeds
	* 0.11   - Changed version number to reflect updated XMLSupport
	* 0.10.1 - Minor bugfix: export of RSS feed did not work
	* 0.10   - Large rewrite of the plugin code
	*        - Reorganized template settings
	*        - Now making use of the TEMPLATE class to fill values in templates
	* 0.9.8  - Split of parsing of XBEL and RSS/Atom to XMLParserClasses
	*        - Misc bugfixes
	* 0.9.7  - Fixed parsing problem with entities in titles and urls
	*        - Misc bugfixes in feed parsing
	*        - Added more template configuration options
	*        - Added the option to hide retrieval and parsing errors
	* 0.9.6  - Added bugfix for Atoms reader
	* 0.9.5  - Added support for Livemark by using a RSS/Atoms reader
	* 0.9.2  - Some bugfixes and addition of RSS feed export
	* 0.9.1  - Added more options for customization
	* 0.9.0  - Initial release
	*/
	
	

	// PLUGIN INFORMATION
	function getName() {
		return 'XBEL Reader';
	}

	function getAuthor()  {
		return 'Niels Leenheer';
	}

	function getURL() {
		return 'http://www.rakaz.nl/nucleus/extra/plugins';
	}

	function getVersion() {
		return '0.14';
	}

	function getDescription() {
		return 'This plugin imports bookmarks from an XBEL file. 
				The bookmarks are can be shown in any skin using
				the skinvar &lt;%XBEL%&gt;. In addition
				to this, the plugin can also export the bookmarks
				as a RSS2 feed.';
	}
	
	function supportsFeature($feature) {
    	switch($feature) {
	        case 'SqlTablePrefix':
	        	return 1;
	        default:
	    		return 0;
		}
	}

	

	// CONFIGURATION VARIABLES
	var $showDebug = false;
	var $showEmpty;
	var $showErrors;
	var $showFolders;
	var $showLivemark;
	var $showSeparators;
	var $showRSS;

	var $xbelFilename;
	
	var $defaultCount;
	var $defaultLength;

	var $XMLSupport;



	// PLUGIN INITIALISATION
	function init() {
		global $manager;
	
		$this->xbelFilename = $this->getOption('xbelFilename');
		$this->showEmpty = ($this->getOption('showEmpty') == 'yes') ? true : false; 
		$this->showFolders = ($this->getOption('showFolders') == 'yes') ? true : false; 
		$this->showLivemark = ($this->getOption('showLivemark') == 'yes') ? true : false; 
		$this->showSeparators = ($this->getOption('showSeparators') == 'yes') ? true : false; 
		$this->showRSS = ($this->getOption('showRSS') == 'yes') ? true : false; 
		$this->defaultCount = (int) $this->getOption('defaultCount');
		$this->defaultLength = (int) $this->getOption('defaultLength');
		
		if ($manager) if ($manager->pluginInstalled('NP_XMLSupport')) 
			$this->XMLSupport =& $manager->getPlugin('NP_XMLSupport');
	}	
	
	function install() {
    	$this->createOption('xbelFilename','XBEL file location','text','bookmarks.xbel');
    	$this->createOption('showRSS','Export bookmarks as a RSS 2.0 feed','yesno','yes');
		$this->createOption('showEmpty',"Show box when there are no items available",'yesno','yes');
	   	$this->createOption('showSeparators','Show Separators between Bookmarks','yesno','no');
	    $this->createOption('showFolders','Show Hierarchical Folders','yesno','no');
	    $this->createOption('showLivemark','Show Livemarks','yesno','no');
    	$this->createOption('defaultCount','Maximum number of Livemarks','text','10');
    	$this->createOption('defaultLength','Maximum length of entries (0 = no limit)','text','0');

		$this->createOption('tplBoxHeader','Box Header','textarea',"<div class='XBEL'>");
		$this->createOption('tplTitle','Title','textarea',"<h4><%title%></h4>");
		$this->createOption('tplHeader','Header','textarea',"<ul>");
    	$this->createOption('tplBookmark','Bookmark','textarea',"<li class='bookmark'><a href='<%url%>' target='_blank' title='<%description%>'><%title%></a></li>");
    	$this->createOption('tplFolder','Folder','textarea',"<li class='folder'><span><%title%></span><%contents%></li>");
    	$this->createOption('tplLivemark','Livemark (without link)','textarea',"<li class='livemark'><span><%title%></span><%contents%></li>");
    	$this->createOption('tplLivemarkLink','Livemark (with link)','textarea',"<li class='livemark'><a href='<%url%>' target='_blank' title='<%description%>'><%title%></a><%contents%></li>");
		$this->createOption('tplSeparator','Separator','textarea','<hr />');
		$this->createOption('tplEmpty',"'No items available' message",'textarea',"<p>No items available</p>");
		$this->createOption('tplFooter','Footer','textarea','</ul>');
    	$this->createOption('tplBoxFooter','Box Footer','textarea',"</div>");
		
    	$this->createOption('showErrors','Show errors','yesno','no');
	} 
	 
	function getEventList() {
		return array ('PreSkinParse');
	} 
	
	function doSkinVar($skinType) {
		$this->_prepare ('bookmarks');
	}
	
	function event_PreSkinParse(&$data) {
		if ($this->showRSS &&
			$data['type'] == 'index' &&
			$data['skin']->name == 'feeds/rss20' &&
			requestVar('xbel') == 'yes')
		{
			$this->_prepare ('rssfeed');
			exit;
		}
	}

	function _prepare ($type) {
		$feed = $this->XMLSupport->createXBELParser();
		$feed->setError($this->showErrors);
		$feed->setDebug($this->showDebug);
		$output = $feed->readFile ($this->xbelFilename);

		if ($type == 'bookmarks')
			$this->_output_html ($output);
			
		if ($type == 'rssfeed')
			$this->_output_rssfeed ($output);
	}


	function _output_html ($content, $depth = 0) {
	
		$buffer = '';
		$noItems = is_array($content['children']) ? count($content['children']) : 0;
	
		if ($depth == 0)
		{
			if ($noItems > 0 || $this->showEmpty)
			{
				$aGeneralVars = array (
					'title' => $this->_cut_string($content['title'])
				);
				
				$buffer .= TEMPLATE::fill($this->getOption('tplBoxHeader'), $aGeneralVars);
				$buffer .= TEMPLATE::fill($this->getOption('tplTitle'), $aGeneralVars);
				$buffer .= TEMPLATE::fill($this->getOption('tplHeader'), $aGeneralVars);
			}
		}
		
		if ($noItems > 0)
		{
			reset ($content['children']);
			while (list($k,$v) = each ($content['children']))
			{
				if ($v['type'] == 'bookmark' || ($v['type'] == 'livemark' && !$this->showLivemark))
				{
					if (isset($v['url']) && $v['url'] != '')
					{
						$aVars = array (
							'url' 			=> $v['url'],
							'title' 		=> $this->_cut_string($v['title']),
							'description' 	=> $v['title'] . ($v['description'] != '' ? ' - '.$v['description'] : '')
						);
						
						$buffer .= TEMPLATE::fill($this->getOption('tplBookmark'), $aVars);
					}
				}
				elseif ($v['type'] == 'livemark' && $this->showLivemark)
				{
					$livemarkbuffer = '';
					
					$parser = $this->XMLSupport->createRSSAtomParser();
					$parser->setError($this->showErrors);
					$parser->setDebug($this->showDebug);
					$feed = $parser->readURL ($v['feed']);
					
					$noMarks = is_array($feed['items']) ? count($feed['items']) : 0;
					
					if ($noMarks > 0) 
					{
						$feed['items'] = array_slice($feed['items'], 0, $this->defaultCount);
						$noMarks = count($feed['items']);
			
						$livemarkbuffer .= TEMPLATE::fill($this->getOption('tplHeader'), $aGeneralVars);
				
						while (list($k2,$v2) = each ($feed['items']))
						{
							if (isset($v2['href']))
							{
								$fVars = array (
									'url' 			=> $v2['href'],
									'title' 		=> $this->_cut_string($v2['title']),
									'description' 	=> $this->_strip_newline($v2['title'])
								);
								
								$livemarkbuffer .= TEMPLATE::fill($this->getOption('tplBookmark'), $fVars);
							}
						}
				
						$livemarkbuffer .= TEMPLATE::fill($this->getOption('tplFooter'), $aGeneralVars);


						$aVars = array (
							'url' 			=> $v['url'],
							'title' 		=> $this->_cut_string($v['title']),
							'description' 	=> $this->_strip_newline($v['title'] . ($v['description'] != '' ? ' - '.$v['description'] : '')),
							'contents' 		=> $livemarkbuffer
						);
						
						if ($v['url'] != '')
							$buffer .= TEMPLATE::fill($this->getOption('tplLivemarkLink'), $aVars);
						else
							$buffer .= TEMPLATE::fill($this->getOption('tplLivemark'), $aVars);
					}
					else
					{
						if ($v['url'] != '')
						{
							$aVars = array (
								'url' 			=> $v['url'],
								'title' 		=> $this->_cut_string($v['title']),
								'description' 	=> $v['title'] . ($v['description'] != '' ? ' - '.$v['description'] : '')
							);
						
							$buffer .= TEMPLATE::fill($this->getOption('tplBookmark'), $aVars);
						}
					}
				}
				elseif ($v['type'] == 'separator' && $this->showSeparators)
				{
					$buffer .= TEMPLATE::fill($this->getOption('tplFooter'), $aVars);
					$buffer .= TEMPLATE::fill($this->getOption('tplSeparator'), $aVars);
					$buffer .= TEMPLATE::fill($this->getOption('tplHeader'), $aVars);
				}
				elseif ($v['type'] == 'folder')
				{
					$folderbuffer = '';
					
					$noChilds = is_array($v['children']) ? count($v['children']) : 0;
						
					if ($noChilds > 0)
					{
						if ($this->showFolders)
						{
							$folderbuffer .= TEMPLATE::fill($this->getOption('tplHeader'), $aGeneralVars);
							$folderbuffer .= $this->_output_html ($v, $depth+1);
							$folderbuffer .= TEMPLATE::fill($this->getOption('tplFooter'), $aGeneralVars);

							$aVars = array (
								'url' 			=> $v['url'],
								'title' 		=> $this->_cut_string($v['title']),
								'description' 	=> $v['title'] . ($v['description'] != '' ? ' - '.$v['description'] : ''),
								'contents' 		=> $folderbuffer
							);
						
							$buffer .= TEMPLATE::fill($this->getOption('tplFolder'), $aVars);						
						}
						else
						{
							$buffer .= $this->_output_html ($v, $depth+1);
						}
					}
				}
			}
		}
		
		if ($depth == 0)
		{
			if ($noItems > 0 || $this->showEmpty)
			{
				if ($noItems == 0)
					$buffer .= TEMPLATE::fill($this->getOption('tplEmpty'), $aGeneralVars);

				$buffer .= TEMPLATE::fill($this->getOption('tplFooter'), $aGeneralVars);
				$buffer .= TEMPLATE::fill($this->getOption('tplBoxFooter'), $aGeneralVars);
			}
			
			echo $buffer;
		}
		else
		{
			return $buffer;
		}
	}
	
	function _output_rssfeed($content, $depth = 0) {
		if ($depth == 0)
		{
			echo "<?xml version='1.0' encoding='ISO-8859-1'?>";
			echo "<rss version='2.0'>";
			echo "<channel>";
	   		
			if (isset($content['title']))
				echo '<title>' . $content['title'] . '</title>';
		}
		
		if (isset($content['children']))
		{
			reset ($content['children']);
			while (list($k,$v) = each ($content['children']))
			{
				if ($v['type'] == 'bookmark' || $v['type'] == 'livemark')
				{
					if (isset($v['url']) && $v['url'] != '')
					{
						echo '<item>';
						echo '<title>' . $v['title'] . '</title>';
						echo '<link>' . $v['url'] . '</link>';
						echo isset($v['description']) ? "<description>" . $v['description'] . "</description>" : "";
						echo '</item>';
					}
				}
				
				elseif ($v['type'] == 'folder')
				{
					if (isset($v['children']))
						$this->_output_rssfeed ($v, $depth+1);
				}
			}
		}
		
		if ($depth == 0)
		{
			echo "</channel>";
			echo "</rss>";
		}
	}

	function _cut_string($string) {
	
		if ($this->defaultLength < 1)
			return $string;

		$i        = 0;
		$count    = 0;
		$ent_mode = false;
		$output   = '';

		while ($i < strlen($string) && $count <= $this->defaultLength)
		{
			$char = substr($string, $i, 1);
			if ($ent_mode == false && $char == '&') $ent_mode = true;
			if ($ent_mode == true && $char == ';') $ent_mode = false;
			if ($ent_mode == false) $count++;
			if ($char == ' ' && $count >= $this->defaultLength - 10) break;
			$output .= $char;
			$i++;
		}
		
		if (strlen($string) != strlen($output)) $output .= '...';
	
		return ($output);
	}
	
	function _strip_newline($string) {
		return preg_replace( "/(\r\n|\n|\r)/", " ", $string );    
	}
}

?>