array(
 *                      'href' => $_SERVER['PHP_SELF'] . '?view=true',
 *                      'dynamic' => true,
 *                      'active' => !$this->isEditable,
 *                  ),
 *                  _t('_Edit') => array(
 *                      'href' => $_SERVER['PHP_SELF'] . '?edit=true',
 *                      'dynamicPopup' => true,
 *                      'active' => $this->isEditable,
 *                  )
 *              )
 *        );
 *     }
 * }
 * 
 * $_page['name_index']	= 0; // choose your own index of template or leave if in doubt
 * $_page['header'] = 'Example page';
 * $_ni = $_page['name_index'];
 * 
 * $oEPV = new BxExamplePageView();
 * $_page_cont[$_ni]['page_main_code'] = $oEPV->getCode();
 * 
 * PageCode();
 * 
 * ?>
 * 
 * 2. Insert into your sys_page_compose_pages table one line.
 *    Name - Unique identification name of the page. Used for association page with its blocks.
 *           We recommend use only latin symbols and digits. (In our example use "example")
 *    Title - Title of your page, it is shown in the Page Builder. ("Example page")
 *    Order - Just the order in list of pages in the Page Builder.
 * 
 * 3. Insert into sys_page_compose lines for each block.
 *    ID - ID of the block. System field. Leave it by default (0). Will be passed to the function as first argument.
 *    Page - ID name of page which you inserted to sys_page_compose_pages ("example").
 *    PageWidth - System field. Leave it by default ("960px"). Customized later.
 *    Desc - Few words about this block. Description.
 *    Caption - Title of this block. ("Block One", "Block Two")
 *    Column - System field. Leave it by default (0). Customized later.
 *    Order - System field. Leave it by default (0). Customized later.
 *    Func - Name of function in your class (without prefix) which will be called to generate the block. ("BlockOne", "BlockTwo")
 *    Content - Optional argument. Rarely used. Passed as the second argument to the function.
 *    DesignBox - Number of Design Box (container). Leave it by default if in doubt (1).
 *    ColWidth - System field. Leave it by default (0). Customized later.
 *    Visible - System field. Leave it by default (0). Customized later.
 *    MinWidth - Minimum recommended width of the block.
 * 
 * 4. Now go to the Page Builder, select your page in the list of pages and customize it (width, columns and blocks order).
      Then customize every block (caption, visibility, etc.).
 * 
 * 5. Open http://yoursite.com/example.php in your browser and you will see your new customized columned page.
 *
 */
class BxDolPageView {
	var $sPageName;
	var $aPage; // cache of this page
	var $sCode = '';
	var $sWhoViews = 'non';
	var $iMemberID = 0;
	var $bAjaxMode = false;
    var $aColumnsWidth = array ();
    
    var $sTableName = 'sys_page_compose';
    var $sCacheFile ;
    var $oCacher = null;
    
	function BxDolPageView( $sPageName ) {
		$this -> sCacheFile = 'sys_page_compose.inc';
		$this -> sPageName = $sPageName;
		
		if( !$this -> load() )
			return false;
		
		$this -> getViewerInfo();
		
		$this -> checkAjaxMode();
	}
	
	function checkAjaxMode() {
		if( isset( $_SERVER['HTTP_X_REQUESTED_WITH'] ) and $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest' )
			$this -> bAjaxMode = true;
	}
    
    function createCache() {
        if ($this->oCacher == null)
            $this->oCacher = new BxDolPageViewCacher($this->sTableName, $this->sCacheFile);
       return $this->oCacher->createCache();
    }
    
	function load() {
        $oCache = $GLOBALS['MySQL']->getDbCacheObject();
        $aCache = $oCache->getData($GLOBALS['MySQL']->genDbCacheKey($this->sCacheFile));
        if (null === $aCache) {
            if (!$this->createCache() ) {
                echo '
Warning PageView cache not found';
    			return false;
		    }
            $aCache = $oCache->getData($GLOBALS['MySQL']->genDbCacheKey($this->sCacheFile));
        }
				
		if( !$aCache ) {
		    echo '
Warning! PageView cache cannot be evaluated. Please recompile.';
			return false;
		}
		
		if( !array_key_exists( $this -> sPageName, $aCache ) ) {
			//echo '
Warning! The page not found in PageView cache.';
			return false;
		}
		
		$this -> aPage = $aCache[ $this->sPageName ];
		if (BxDolRequest::serviceExists('pageac', 'page_blocks_filter')) {
			BxDolService::call('pageac', 'page_blocks_filter', array(&$this));
		}        
		return true;
	}
	
    function isLoaded() {
        return (isset($this->aPage) && !empty($this->aPage));
    } 
    
    function getPageTitle() {
        return $this->aPage['Title'];
    }
    
	function getViewerInfo() {
		if (isMember()) {
			$this -> sWhoViews = 'memb';
			$this -> iMemberID = (int)$_COOKIE['memberID'];
		}
	}
	
	function gen() {
		global $_page_cont, $_ni, $_page, $oSysTemplate;
		
		if( !$this -> aPage )
			return false;
		$this -> genColumnsHeader();
		
		$oSysTemplate->setPageWidth($this -> aPage['Width']);
		$oSysTemplate->addJs('view_edit.js');
        if (isset($this -> aPage['Columns']) && !empty($this -> aPage['Columns'])){
    		foreach( array_keys( $this -> aPage['Columns'] ) as $iColumn )
    			$this -> genColumn( $iColumn );
		} else {
            $this->genPageEmpty();
        }
        
		$this -> genColumnsFooter();
	}
	
    function genPageEmpty() {
        $this->genColumnsHeader();
        $this->genColumnHeader(1, 100);
        $this->sCode .= MsgBox(_t('_Empty'));
        $this->genColumnFooter(1);
        $this->genColumnsFooter();
    }
    
	function genOnlyBlock( $iBlockID, $sDynamicType = 'tab' ) {
		if( !$iBlockID )
			return false;
		// search block
		foreach( array_keys( $this -> aPage['Columns'] ) as $iColumn ) {
			$aColumn = $this -> aPage['Columns'][ $iColumn ];
			if( !$aColumn )
				return false;
			
            if (isset($aColumn['Blocks'][$iBlockID])) {
                $this -> genBlock( $iBlockID, $aColumn['Blocks'][$iBlockID], false, $sDynamicType );
                return true;
            }
		}
        
		return false;
	}
	function getCode() {
		
		if( !($this -> bAjaxMode and (int)$_REQUEST['pageBlock']) )
			$this -> gen();
		else {
            $this -> genOnlyBlock( (int)$_REQUEST['pageBlock'], $_REQUEST['dynamic'] );
            header( 'Content-type:text/html;charset=utf-8' );
			echo $this -> sCode;
			exit;
		}
		return $this -> sCode;
	}
	
	//for customizability
	function genColumnsHeader() {
	}
	
	//for customizability
	function genColumnsFooter() {
	}
	
	function genColumn( $iColumn ) {
		$aColumn = $this -> aPage['Columns'][ $iColumn ];
		if( !$aColumn )
			return false;
		$bShowDebugBlockInfo = !empty($_REQUEST['debug_mode']);
		$this -> genColumnHeader( $iColumn, $aColumn['Width'] );
		foreach( $aColumn['Blocks'] as $iBlockID => $aBlock ) {
			if ($bShowDebugBlockInfo)
				$iCurTime = getmicrotime();
			$this -> genBlock( $iBlockID, $aBlock );
			if ($bShowDebugBlockInfo) {
				$iCurTime2 = getmicrotime();
				$iGenTime = $iCurTime2 - $iCurTime;
				$this -> sCode .= "";
			}
		}
		$this -> genColumnFooter( $iColumn );
	}
	function getBlockCode_Topest($iColumn) {
		return '';
	}
	function genColumnHeader( $iColumn, $fColumnWidth ) {
        $iColumnsCount = count($this -> aPage['Columns']);
        if(count($this -> aPage['Columns']) == 1)
            $sAddClass = ' page_column_single';
		else if($iColumn == 1)
			$sAddClass = ' page_column_first';
		else if($iColumn == $iColumnsCount)
			$sAddClass = ' page_column_last';
		else
			$sAddClass = '';
        switch (preg_replace('/\d+/', '', $this->aPage['Width'])) {
            case 'px':
                // calc width in pixels
				if ('px' == $GLOBALS['oTemplConfig']->PageComposeColumnCalculation) {
                    if ($iColumn == $iColumnsCount) // sum of all columns must not be more/less than page width
	                    $sColumnWidth = ($this -> aPage['Width'] - array_sum($this->aColumnsWidth)) . 'px';
                    else
                        $sColumnWidth = round(($fColumnWidth * $this -> aPage['Width']) / 100) . 'px';
                    $this->aColumnsWidth[$iColumn] = (int)$sColumnWidth;
			        break;
				} // else calculate in percentages below
            case '%':
                $sColumnWidth = $fColumnWidth . '%';
            break;
        }
		$this -> sCode .= '
';
		$sBlockFunction = 'getBlockCode_Topest';
		$this -> sCode .=  $this -> $sBlockFunction($iColumn);
	}
	
	function genColumnFooter( $iColumn ) {
		$this -> sCode .= '
';
	}
	
    /*
        Note: if bStatic == false, it is popup
    */
	function genBlock( $iBlockID, $aBlock, $bStatic = true, $sDynamicType = 'tab' ) {
		if( !$this -> isBlockVisible( $aBlock['Visible'] ) )
			return false;
        if (isset($GLOBALS['bx_profiler'])) $GLOBALS['bx_profiler']->beginPageBlock(_t($aBlock['Caption']), $iBlockID);
        if ($aBlock['Cache'] > 0 && getParam('sys_pb_cache_enable') == 'on') {
            $oCache = $this->getBlocksCacheObject ();            
            $sBlock = $oCache->getData($this->genBlocksCacheKey ($iBlockID.$bStatic.$sDynamicType.isMember()), $aBlock['Cache']);
            if ($sBlock !== null) {
                if (isset($GLOBALS['bx_profiler'])) $GLOBALS['bx_profiler']->endPageBlock($iBlockID, $sBlock ? false : true, true);
                $this->sCode .= $sBlock;
                return;
            }
        }
        $sBlockFunction = 'getBlockCode_' . $aBlock['Func'];
		
		$mBlockCode = '';
		if( method_exists( $this, $sBlockFunction ) ) {
			$mBlockCode = $this -> $sBlockFunction( $iBlockID, $aBlock['Content'] );
		}
        
		// $sBlockFunction can return simple string or array with few values:
		// 0 - content, 1 - array of caption links, 2 - bottom links, 3 - caption addon (array or string)
		
		$sTopCode  = '';
		$sBottomCode = '';
		if( is_array( $mBlockCode ) ) {
			$sCaptionCode = $this->_getBlockCaptionCode($iBlockID, $aBlock, $mBlockCode, $bStatic, $sDynamicType);
			$sTopCode = $this->_getBlockTopCode($iBlockID, $aBlock, $mBlockCode, $bStatic, $sDynamicType);
			$sBlockCode = !isset($mBlockCode[3]) || (isset($mBlockCode[3]) && $mBlockCode[3] === false) ? '' . $mBlockCode[0] . '
' : $mBlockCode[0];
			$sBottomCode = $this->_getBlockBottomCode($iBlockID, $aBlock, $mBlockCode, $bStatic, $sDynamicType);					
		} 
		else if(is_string($mBlockCode)) {
			$sCaptionCode = $this->_getBlockCaptionCode($iBlockID, $aBlock, $mBlockCode, $bStatic, $sDynamicType);
			$sBlockCode = $mBlockCode;
		} 
		else
			$sBlockCode = false;
	
        $sBlock = '';
		if ($sBlockCode) {
            $sCodeDB = DesignBoxContent( $sCaptionCode, $sBlockCode, $aBlock['DesignBox'], $sTopCode, $sBottomCode);
        
            if ($bStatic) {
    	    	$sBlock .= '' . $sCodeDB . '
';
            } else {
                if ($sDynamicType == 'tab')
                    $sBlock .= $sCodeDB;
                elseif ($sDynamicType == 'popup')
                    $sBlock .= $GLOBALS['oFunctions']->transBox($sCodeDB, true);
            }
        }
        $this->sCode .= $sBlock;
        if ($aBlock['Cache'] > 0 && getParam('sys_pb_cache_enable') == 'on') {
            $oCache = $this->getBlocksCacheObject ();
            $oCache->setData($this->genBlocksCacheKey ($iBlockID.$bStatic.$sDynamicType.isMember()), $sBlock, $aBlock['Cache']);
        }
        if (isset($GLOBALS['bx_profiler'])) $GLOBALS['bx_profiler']->endPageBlock($iBlockID, $sBlockCode ? false : true, false );
        if (!$sBlockCode)
            return false;
	}
	function _getBlockCaptionCode($iBlockID, $aBlock, $aBlockCode, $bStatic = true, $sDynamicType = 'tab') {
		$sCode = "";
 		if(is_array($aBlockCode) && isset($aBlockCode[3]) && (is_array($aBlockCode[3]) || (is_string($aBlockCode[3]) && $aBlockCode[3]))) {
   			// if array is passed, pass it to the original caption translation 
   			if(is_array($aBlockCode[3]))
    			$sCode = _t($aBlock['Caption'], $aBlockCode[3][0], $aBlockCode[3][1], $aBlockCode[3][2]);
			// if string is passed, replace the caption
			else if(is_string($aBlockCode[3]) && $aBlockCode[3])
				$sCode = _t($aBlockCode[3]);
  		} 
  		// else pass the original caption
		else
			$sCode = _t($aBlock['Caption']);
		return $sCode;
 	}
	function _getBlockTopCode($iBlockID, $aBlock, $aBlockCode, $bStatic = true, $sDynamicType = 'tab') {
		$sCaptionMenuFunc = !isset($aBlockCode[4]) ? 'getBlockCaptionItemCode' : $aBlockCode[4];
		$sCode = "";
		if(!$bStatic && $sDynamicType == 'popup')
			$sCode = '';
		else if( is_array($aBlockCode[1]))
			$sCode = $this -> $sCaptionMenuFunc($iBlockID, $aBlockCode[1]);
		
		return $sCode;
	}
	
	function _getBlockBottomCode($iBlockID, $aBlock, $aBlockCode, $bStatic = true, $sDynamicType = 'tab') {
		$sCode = "";
		if(!empty($aBlockCode[2]) && is_array($aBlockCode[2]))
			$sCode = $this->getBlockBottomCode($iBlockID, $aBlockCode[2]);
		else
			$sCode = empty($aBlockCode[2]) ? '' : $aBlockCode[2];
		return str_replace('{id}', $iBlockID, $sCode);
	}
	
	function isBlockVisible( $sVisible ) {
		if( strpos( $sVisible, $this -> sWhoViews ) === false )
			return false;
		else
			return true;
	}
	
	function getBlockCaptionItemCode( $iBlockID, $aLinks ) {
		$aItems = array();
		foreach( $aLinks as $sTitle => $aLink ) {
		    $sTitle = htmlspecialchars_adv(_t( $sTitle ));
		    $sClass = !empty($aLink['class']) ? $aLink['class'] : 'top_members_menu';
		    $sClass .= isset($aLink['icon']) ? ' with_icon' : '';
		    if(!empty($aLink['onclick']))
                $sOnclick = 'onclick="' . $aLink['onclick'] . '"';
            else if($aLink['dynamic'])
                $sOnclick = 'onclick="return !loadDynamicBlock(' . $iBlockID . ', this.href);"';
            else if($aLink['dynamicPopup'])
                $sOnclick = 'onclick="loadDynamicPopupBlock(' . $iBlockID . ', this.href); return false;"';
            else
                $sOnclick = '';
		    $aItems[] = array(
                'bx_if:item_act' => array(
                    'condition' => (bool)$aLink['active'],
                    'content' => array(
                        'bx_if:icon_act' => array(
                            'condition' => isset($aLink['icon']),
                            'content' => array(
                                'class' => $sClass,
                                'src' => empty($aLink['icon']) ? '' : $aLink['icon']
                            )
                        ),
                        'title' => $sTitle
                    )
                ),
                'bx_if:item_pas' => array(
                    'condition' => !(bool)$aLink['active'],
                    'content' => array(
                        'bx_if:icon_pas' => array(
                            'condition' => isset($aLink['icon']),
                            'content' => array(
                                'class' => $sClass,
                                'src' => empty($aLink['icon']) ? '' : $aLink['icon']
                            )
                        ),
                        'id' => (!empty($aLink['id'])  ? 'id="' . $aLink['id'] . '"' : ''),
                        'href' => htmlspecialchars_adv($aLink['href']),
                        'class' => $sClass,
                        'target' => (!empty($aLink['target'])  ? ' target="' . $aLink['target'] . '"' : ''),
                        'on_click' => $sOnclick,
                        'title' => $sTitle
                    )
                )
		    );		    			
		}		
		return $GLOBALS['oSysTemplate']->parseHtmlByName('designbox_menu_1.html', array(
            'id' => '' . $iBlockID,
            'bx_repeat:items' => $aItems
		));
	}
	function getBlockCaptionMenu( $iBlockID, $aLinks ) {
	    $aItems = array();
		foreach( $aLinks as $sId => $aLink ) {
		    if(isset($aLink['icon']))
                $aLink['class'] = isset($aLink['class']) ? $aLink['class'] . ' with_icon' : 'with_icon';
		    $sHidden = ' style="display:none"';
            $bActive = isset($aLink['active']) && $aLink['active'] == 1;
            $sClass = isset($aLink['class']) ? ' class="' . $aLink['class'] . '"' : '';
		    $aItems[] = array(
                'id' => $sId,
                'show_active' => !$bActive ? $sHidden : '',
                'show_passive' => $bActive ? $sHidden : '',
                'bx_if:icon_act' => array(
                    'condition' => isset($aLink['icon']),
                    'content' => array(
                        'class' => $sClass,
                        'src' => $aLink['icon']
                    )                    
                ),
                'bx_if:icon_pas' => array(
                    'condition' => isset($aLink['icon']),
                    'content' => array(
                        'class' => $sClass,
                        'src' => $aLink['icon']
                    )                    
                ),
                'class' => $sClass,
                'title' => htmlspecialchars_adv(_t($aLink['title'])),
                'href' => (isset($aLink['href']) ? 'href="' . htmlspecialchars_adv($aLink['href']) . '"' : ''),
                'target' => (isset($aLink['target'])  ? 'target="' . $aLink['target'] . '"' : ''),
                'on_click' => (isset($aLink['onclick']) ? 'onclick="' . $aLink['onclick'] . '"' : '')
		    );			
		}
		
		return $GLOBALS['oSysTemplate']->parseHtmlByName('designbox_menu_2.html', array(
            'id' => '' . $iBlockID,
            'bx_repeat:items' => $aItems
		));
	}	
	
	function getBlockBottomCode( $iBlockID, $aLinks ) {
		if (empty($aLinks))
			return;
			
		$sCode = '
			';
		return $sCode;
	}
	/* * * * Page Blocks * * * */
	/**
	 * members statistic block
	 */
	function getBlockCode_MemberStat() {
		return getSiteStatUser();
	}
	function getBlockCode_Echo( $iBlockID, $sContent ) {
$sContent = "XXX ".$sContent;
$res = db_res("select `ID`,`Key` from sys_localization_keys"); // FOR 7.0.0 only
while ( $arr = mysql_fetch_array($res) )
{
if ( strpos($sContent,$arr[Key]) > 0 )
$sContent = str_replace($arr[Key],_t($arr[Key]),$sContent);
}
$sContent = str_replace("XXX","",$sContent); 
		return '' . $sContent . '
';
	}
	
	function getBlockCode_XML( $iBlockID, $sContent ) {
		$sApplication = BxDolService::call('open_social', 'gen_application', array($sContent));
		return <<
	{$sApplication}
EOF;
	}
	
	function getBlockCode_PHP( $iBlockID, $sContent ) {
		ob_start();
		$aResult = eval($sContent);
		$sContent = ob_get_clean();		
		return !empty($aResult) ? $aResult : $sContent;
	}
	
	function getBlockCode_RSS( $iBlockID, $sContent ) {
		list( $sUrl, $iNum ) = explode( '#', $sContent );
		$iNum = (int)$iNum;
		$iAddID = 0;
		if (isset( $this -> oProfileGen -> _iProfileID))
			$iAddID = $this -> oProfileGen -> _iProfileID;
		elseif (isMember())
			$iAddID = $_COOKIE['memberID'];
		return '
	';
	}
	
	
	function getBlockCode_LoginSection($iBlockID, $sParams = '') {
		$sDolUrl = BX_DOL_URL_ROOT;
		$sAdminUrl = BX_DOL_URL_ADMIN;
		$sAdminPanelC = _t('_Admin Panel');
		$sLogoutC = _t('_Log Out');
		$sControlPanelC = _t('_Control Panel');
		$sHelloMemberC = _t( '_Hello member', getNickName( $this -> iMemberID ) );
		$ret = '';
		if (isAdmin()) {
			$ret .= <<
	{$sAdminPanelC}
	 | | 
	{$sLogoutC}
EOF;
		/*} elseif (isModerator()) {
			$ret .= '';
				$ret .= '
';
					$ret .= 'Moderator Panel';
				$ret .= '';
				$ret .= '
';
					$ret .= '| |';
				$ret .= '';
				$ret .= '
';
					$ret .= '{$sLogoutC}';
				$ret .= '';
			$ret .= '
';
				$ret .= '
';
					$ret .= 'Affiliate Panel';
				$ret .= '';
				$ret .= '
';
					$ret .= '| |';
				$ret .= '';
				$ret .= '
';
					$ret .= '{$sLogoutC}';
				$ret .= '';
			$ret .= '
'.$ret.'
';
	}
	
    function GenFormWrap($sMainContent, $sPage, $sFunctionName, $iMaxThumbWidth, $iThumbsCnt) {
		$sBlockWidthSQL = "SELECT `PageWidth`, `ColWidth` FROM `sys_page_compose` WHERE `Page`='{$sPage}' AND (`Func`='{$sFunctionName}' OR `Caption`='{$sFunctionName}')";
		$aBlockWidthInfo = db_arr($sBlockWidthSQL);
		$aBlockWidth = (int)((int)($aBlockWidthInfo['PageWidth'] - 20) * (int)$aBlockWidthInfo['ColWidth'] / 100) - 14;
		$iDestWidth = $iThumbsCnt * $iMaxThumbWidth;
		$iDestWidth = getBlockWidth($aBlockWidth, $iMaxThumbWidth, $iThumbsCnt);
		$sWidthCent = ($iDestWidth>0) ? "width:{$iDestWidth}px;" : '';
		return <<
	
		{$sMainContent}
	
	
EOF;
	}
    function getBlocksCacheObject () {
        if ($this->oCacher == null)
            $this->oCacher = new BxDolPageViewCacher($this->sTableName, $this->sCacheFile);
        return $this->oCacher->getBlocksCacheObject ();
    }
    function genBlocksCacheKey ($sId) {
        if ($this->oCacher == null)
            $this->oCacher = new BxDolPageViewCacher($this->sTableName, $this->sCacheFile);
        return $this->oCacher->genBlocksCacheKey ($sId);
    }
}
?>