<?php
// describes an editable list template that can be saved
// WPFB_ListTpl::Generate generates output for front-end file lists
class WPFB_ListTpl {
	
	var $tag;
	var $header;
	var $footer;
	var $file_tpl_tag;
	var $cat_tpl_tag;
	var $ajax_scroll;
	var $ajaxloader_cssclass;
	var $current_list = null;
        
		
	static function Get($tag) {
		$tag = trim($tag, '\'');
		$tpls = get_option(WPFB_OPT_NAME.'_list_tpls');
		return isset($tpls[$tag]) ? new WPFB_ListTpl($tag, $tpls[$tag]) : null;
	}
	
	static function GetAll() {
		$tpls = get_option(WPFB_OPT_NAME.'_list_tpls');
		if(empty($tpls)) return array();
		foreach($tpls as $tag => $tpl)
			$tpls[$tag] = new WPFB_ListTpl($tag, $tpl);
		return $tpls;
	}
	
	function __construct($tag=null, $data=null) {
		if(!empty($data)) {
			$vars = array_keys(get_class_vars(get_class($this)));
			foreach($vars as $var)
				if(isset($data[$var]))
					$this->$var = $data[$var];
		}				
		$this->tag = $tag;
	}
	
	function Save() {
		$tpls = get_option(WPFB_OPT_NAME.'_list_tpls');
		if(!is_array($tpls)) $tpls = array();
		$data = (array)$this;
		unset($data['tag'], $data['current_list']);
		$tpls[$this->tag] = $data; 
		update_option(WPFB_OPT_NAME.'_list_tpls', $tpls);
	}
	
	private function ParseHeaderFooter($str, $uid=null) {
		$str = preg_replace_callback('/%sort_?link:([a-z0-9_]+)%/i', array(__CLASS__, 'GenSortlink'), $str);
		
		if(strpos($str, '%search_form%') !== false) {
			wpfb_loadclass('Output');
			$str = str_replace('%search_form%', WPFB_Output::GetSearchForm("", $_GET), $str);
		}
		
		$str = preg_replace_callback('/%print_?(script|style):([a-z0-9_-]+)%/i', array(__CLASS__, 'PrintScriptCallback'), $str);

		if(empty($uid)) $uid = uniqid();
		$str = str_replace('%uid%', $uid, $str);
		
		// TODO: add doc
		$str = str_replace('%search_term%', empty($_GET['wpfb_s']) ? '' : esc_html(stripslashes($_GET['wpfb_s'])), $str);
		
		
		$count = 0;
		$str = preg_replace("/jQuery\((.+?)\)\.dataTable\s*\((.*?)\)(\.?.*?)\s*;/", 'jQuery($1).dataTable((function(options){/*%WPFB_DATA_TABLE_OPTIONS_FILTER%*/})($2))$3;', $str, -1, $count);
		if($count > 0)
		{
			$this->ajax_scroll = false; // AJAX not supported with DataTables yet!
			$dataTableOptions = array();
			list($sort_field, $sort_dir) = wpfb_call('Item','ParseSorting', $this->current_list->file_order);
			$file_tpl = WPFB_Core::GetTpls('file', $this->file_tpl_tag);
			if(($p = strpos($file_tpl, "%{$sort_field}%")) > 0)
			{
				// get the column index of field to sort
				$col_index = substr_count($file_tpl,"</t", 0, $p);				
				$dataTableOptions["aaSorting"] = array(array($col_index, strtolower($sort_dir)));
			}
			
			if($this->current_list->page_limit > 0)
					$dataTableOptions["iDisplayLength"] = $this->current_list->page_limit;
			
			
			$str = str_replace('/*%WPFB_DATA_TABLE_OPTIONS_FILTER%*/', 
	" var wpfbOptions = ".json_encode($dataTableOptions)."; ".
	" if('object' == typeof(options)) { for (var v in options) { wpfbOptions[v] = options[v]; } }".
	" return wpfbOptions; "
, $str);
		}	
		
		return $str;
	}
	
	static function PrintScriptCallback($ms)
	{
		ob_start();
		if($ms[1] == 'style') wp_print_styles($ms[2]);
		else  wp_print_scripts($ms[2]);
		return ob_get_clean();
	}
	
	static function GenSortlink($ms) {
		static $link;
		$by = $ms[1];
		if(empty($link)) {
			$link = remove_query_arg('wpfb_file_sort');
			$link .= ((strpos($link, '?') > 0)?'&':'?').'wpfb_file_sort=&';	
		}
		$desc = !empty($_GET['wpfb_file_sort']) && ($_GET['wpfb_file_sort'] == $by || $_GET['wpfb_file_sort'] == "<$by"); 
		return $link.($desc?'gt;':'lt;').$by;
	}

    /**
     * @param string $content
     * @param WPFB_Category[] $categories
     * @param array $list_args
     * @return int
     */
	function GenerateList(&$content, $categories, $list_args=null)
	{
		if(!empty($list_args)) {
			$this->current_list = (object)$list_args;
			unset($list_args);
		}
		
		$hia = WPFB_Core::$settings->hide_inaccessible;
		$sort = WPFB_Core::GetSortSql($this->current_list->file_order);
		
		if($this->current_list->page_limit > 0) { // pagination
			$page = (empty($_REQUEST['wpfb_list_page']) || $_REQUEST['wpfb_list_page'] < 1) ? 1 : intval($_REQUEST['wpfb_list_page']);
			$start = $this->current_list->page_limit * ($page-1);
		} else $start = -1;
		
		$search_term = empty($_GET['wpfb_s']) ? (empty($this->current_list->search)?null:$this->current_list->search) : stripslashes($_GET['wpfb_s']);
		
		if($search_term || WPFB_Core::$file_browser_search) { // search
			wpfb_loadclass('Search');
			$where = WPFB_Search::SearchWhereSql(WPFB_Core::$settings->search_id3, $search_term);
		} else $where = '1=1';
		
		$num_total_files = 0;
		if(is_null($categories)) { // if null, just list all files!
			$files = WPFB_File::GetFiles2($where, $hia, $sort, $this->current_list->page_limit, $start);
			$num_total_files = WPFB_File::GetNumFiles2($where, $hia);
				foreach($files as $file) $content .= $file->GenTpl2($this->file_tpl_tag);
		} else {
			if(!empty($this->current_list->cat_order))
				WPFB_Item::Sort($categories, $this->current_list->cat_order);
		
			$cat = reset($categories); // get first category
			// here we check if single category and cat has at least one file (also secondary cat files!)
			if(count($categories) == 1 && ($cat->cat_num_files > 0 || count(WPFB_File::GetFiles2(WPFB_File::GetSqlCatWhereStr($cat->cat_id),false,null,1)))) { // single cat
				if(!$cat->CurUserCanAccess()) return 0;
				
				$where = "($where) AND ".WPFB_File::GetSqlCatWhereStr($cat->cat_id);
				$files = WPFB_File::GetFiles2($where, $hia, $sort, $this->current_list->page_limit, $start);
				$num_total_files = WPFB_File::GetNumFiles2($where, $hia);
				
				if($this->current_list->cat_grouping && $num_total_files > 0) $content .= $cat->GenTpl2($this->cat_tpl_tag);

					 foreach($files as $file) $content .= $file->GenTpl2($this->file_tpl_tag);
			} else { // multi-cat
				// TODO: multi-cat list pagination does not work properly yet
		
				// special handling of categories that do not have files directly: list child cats!
				if(count($categories) == 1 && $cat->cat_num_files == 0) {
					$categories = $cat->GetChildCats(true, true);
					if(!empty($this->current_list->cat_order))
						WPFB_Item::Sort($categories, $this->current_list->cat_order);
				}
		
				if($this->current_list->cat_grouping) { // group by categories
					$n = 0;
					foreach($categories as $cat)
					{
						if(!$cat->CurUserCanAccess()) continue;
		
						$num_total_files = max($nf = WPFB_File::GetNumFiles2("($where) AND ".WPFB_File::GetSqlCatWhereStr($cat->cat_id), $hia), $num_total_files); // TODO
		
						//if($n > $this->current_list->page_limit) break; // TODO!!
						if($nf > 0) {
							$files = WPFB_File::GetFiles2("($where) AND ".WPFB_File::GetSqlCatWhereStr($cat->cat_id), $hia, $sort, $this->current_list->page_limit, $start);                                                     
							if(count($files) > 0) {
								$content .= $cat->GenTpl2($this->cat_tpl_tag); // check for file count again, due to pagination!
								foreach($files as $file) $content .= $file->GenTpl2($this->file_tpl_tag); 
							}
						}
					}
				} else {
					// this is not very efficient, because all files are loaded, no pagination!
					$all_files = array();
					foreach($categories as $cat)
					{
						if(!$cat->CurUserCanAccess()) continue;
						$all_files += WPFB_File::GetFiles2("($where) AND ".WPFB_File::GetSqlCatWhereStr($cat->cat_id), $hia, $sort);
					}
					$num_total_files = count($all_files);

					{
						 WPFB_Item::Sort($all_files, $sort);

						 $keys = array_keys($all_files);
						 if($start == -1) $start = 0;
						 $last = ($this->current_list->page_limit > 0) ? min($start + $this->current_list->page_limit, $num_total_files) : $num_total_files;

						 for($i = $start; $i < $last; $i++)
							  $content .= $all_files[$keys[$i]]->GenTpl2($this->file_tpl_tag);
					 }
				}
			}
		}
		
		return $num_total_files;
	}

        
	function Generate($categories=null, $args = array())
	{	  
		$this->current_list = (object)wp_parse_args($args, array(
			 'cat_grouping' => false,
			 'cat_order' => null,
			 'file_order' => null,
			 'page_limit' => 0,			 
			 'hide_pagenav' => false,
			 'search' => null
		));
		unset($args);
		
		
		$uid = uniqid();
      
		
		$content = $this->ajax_scroll ? "<div id='wpfb-list-wrap-$uid'>" : ""; 
		$content .= $this->ParseHeaderFooter($this->header, $uid);
		if($this->ajax_scroll) {
			$this->current_list->hide_pagenav = true;
			$is_table = (strpos($content, "<table") !== false);
		}
		
		$num_total_files = $this->GenerateList($content, $categories);
		
		$footer = $this->ParseHeaderFooter($this->footer, $uid);		
		$is_datatable = strpos($footer, ").dataTable(")!==false;
		
		// TODO: no page_limit when dataTable? 
		// hide pagenav when using datatable
		$this->current_list->hide_pagenav = $this->current_list->hide_pagenav || $is_datatable;
		
		$page_break = $this->current_list->page_limit > 0 && $num_total_files > $this->current_list->page_limit;
		
		if($page_break && !$this->current_list->hide_pagenav) {
			$pagenav = paginate_links( array(
				'base' => add_query_arg( 'wpfb_list_page', '%#%'),
				'format' => '',
				'total' => ceil($num_total_files / $this->current_list->page_limit),
				'current' => empty($_GET['wpfb_list_page']) ? 1 : absint($_GET['wpfb_list_page']),
				 'add_args' => array() // necessary!
			));

			if(strpos($footer, '%page_nav%') === false)
				$footer .= $pagenav;
			else
				$footer = str_replace('%page_nav%', $pagenav, $footer);
		} else {
			$footer = str_replace('%page_nav%', '', $footer);
		}
		
		if($page_break && $this->ajax_scroll) {
			if(!$is_table) {
				$ajax_wrapper_id = "wpfb-ajax-scroll-$uid";
				$loader_style = empty($this->ajaxloader_cssclass) ? "style=\"background: url('".WPFB_PLUGIN_URI."images/ajax-list-loader.gif') no-repeat center bottom; width:auto; height: 30px; display:none;\"" : "style=\"display:none;\" class=\"{$this->ajaxloader_cssclass}\"";
				$content .= "<div id='$ajax_wrapper_id'></div><div id=\"ajax-loader-$uid\" $loader_style>"; // style='display:none;'
			} else {
				$loader_style = empty($this->ajaxloader_cssclass) ? "style=\"background: url('".WPFB_PLUGIN_URI."images/ajax-list-loader.gif') no-repeat center bottom; width:auto; height: 30px; display:none;\"" : "style=\"display:none;\" class=\"{$this->ajaxloader_cssclass}\"";
				$content .= "<tr id=\"ajax-loader-$uid\" $loader_style><td colspan='10'></td></tr>";			
			}
		}
		
		$content .= $footer;
		
		if($this->ajax_scroll)
			$content .= "</div>";
				
		if($page_break && $this->ajax_scroll) {
			wp_print_scripts('jquery');
		  
			$ajax_data = array_merge(array_map(create_function('$v','return is_bool($v) ? ($v?1:0) : $v;'), (array)$this->current_list), array(
				'wpfb_action' => 'list',
				'tpl' => $this->tag,
				'cats' => empty($categories) ? '' : implode(',',array_map(create_function('$c','return $c->cat_id;'), $categories)),
				'wpfb_list_page' => (max(1,(int)@$_GET['wpfb_list_page'])+1)
			));
			
			$content .= "<script type=\"text/javascript\">\n//<![CDATA[
var list$uid = {loading:false,complete:false};
var ajaxData$uid = ".json_encode($ajax_data).";
function wpfb_listOnScroll{$uid}(){
	if(list$uid.complete) return;
	var w = jQuery(window), t = ".($is_table ? "jQuery('#wpfb-list-wrap-$uid').children('table')" : "jQuery('#{$ajax_wrapper_id}')").";
	if( (w.scrollTop()+w.height()) >= (t.offset().top+t.height()) ){
		if(list$uid.loading) return;
		list$uid.loading = true;
		jQuery('#ajax-loader-$uid').show();
		jQuery.ajax({url:wpfbConf.ajurlpub,data:ajaxData$uid}).done(function ( data ) {
			jQuery('#ajax-loader-$uid').hide();
			list$uid.loading = false;
			ajaxData$uid.wpfb_list_page++;
			if(!data || data == '') {
				list$uid.complete = true;
				return;
			}
			". ($is_table ? "jQuery('#ajax-loader-$uid').before(data);" : "jQuery('#$ajax_wrapper_id').append(data);")."
			wpfb_listOnScroll{$uid}();
		});
	}
}
jQuery(window).scroll(wpfb_listOnScroll{$uid});
//]]>\n</script>\n";
		}
		return $content;
	}
		
	function Sample($cat, $file) {
		$uid = uniqid();
		$this->current_list = (object)array('cat_grouping' => false, 'file_order' => null, 'page_limit' => 3, 'cat_order' => null);
	
		$footer = str_replace('%page_nav%', paginate_links(array(
			'base' => add_query_arg( 'wpfb_list_page', '%#%' ), 'format' => '',
			'total' => 3,
			'current' => 1
		)), $this->ParseHeaderFooter($this->footer, $uid));
		return $this->ParseHeaderFooter($this->header, $uid) . $cat->GenTpl2($this->cat_tpl_tag) . $file->GenTpl2($this->file_tpl_tag) . $footer;		
	}
	
	function Delete() {
		$tpls = get_option(WPFB_OPT_NAME.'_list_tpls');
		if(!is_array($tpls)) return;
		unset($tpls[$this->tag]);
		update_option(WPFB_OPT_NAME.'_list_tpls', $tpls);
	}
	
	function GetTitle() { return __(__(esc_html(WPFB_Output::Filename2Title($this->tag))),'wp-filebase'); }
}