<?php
/**
 * cms_startup - Load startup functions. This code has to be very efficient since all requestes will execute this.
 *
 * @author $Author: dtong $
 * @version $Id: cms_startup.php,v 1.5 2011/05/16 08:56:29 dtong Exp $
 * @copyright Copyright (c) 2011, Tiller Software Co., Ltd.
*/

class Cms_startup {
	const FILE_EXTENSION = 'todcm';
	const FILE_PATH = FCPATH;
	const CMD_STOP = 'stop';
	const CMD_MAINTENANCE = 'main';
	const CMD_MESSAGE = 'msg';

	private static $run_functions = array('maintenance_mode_check');
	// All functions should check for null value and init. if necessary
	// This is for performance reason.
	private $CI=NULL;
	private $cmd_filename = FALSE;

	function __construct() {
		foreach (self::$run_functions as $function) {
			$this->$function();
		}
	}

	/**
	 * File driven site maintenance mode. Files are located at the web root folder.
	 * Also supports setting to maintenance mode from the admid config menu.
	 *
	 * stop.todcm - prevents any one to login including admins
	 * main.todcm - maintenance mode, admins can login
	 * msg.todcm - prints message on login page
	 *
	 * All the 3 files can be prepended with unit_org such as zis_stop.todcm.
	 */
	private function maintenance_mode_check(){
		$site_filename = $this->get_site_filename(); // only defined site.* list
		if ( !$site_filename ) {
			$this->CI = & get_instance();
			if ($this->CI->config->item('cms_manage_mode')) {
				//This is for checking non-file based maintenance mode. Admin using the config
				//menu to turn maintenance mode on.
				$this->set_maintenance_mode();
			}
			return;
		}
		// must be called before any actual output is sent
		// call this function if has maintenance file
		osa_header_nocache();
		switch ($site_filename):
			 case self::CMD_STOP:
			 	$this->CI->config->set_item('cms_sitestop', TRUE);
			 	$this->set_notice_message();
			 	$this->set_stop_mode();
			 	break;
			 case self::CMD_MAINTENANCE:
			 	$this->CI->config->set_item('cms_manage_mode', TRUE);
			 	$this->set_notice_message();
			 	$this->set_maintenance_mode();
			 	break;
			 case self::CMD_MESSAGE:
			 	$this->set_notice_message();
			 	break;
		endswitch;
	}

	/**
	 * get a site filename and full path in target folder
	 * order(case-insensitive): site, [unit_org]_site, main and msg
	 * @return string|false command of site file name
	 */
	private function get_site_filename(){
		// get all specific file extension ( *.[FILE_EXTENSION] )
		$search_pattern = self::FILE_PATH . '*.' . self::FILE_EXTENSION;
		// glob function: return array, empty array if no file matched, or FALSE on error
		$dir_list = @glob($search_pattern);
		if ( !is_array($dir_list) ) {
			// Not using lang file becuase we are not even sure can we load a lang file if this error happens.
			// Have to hard code the error message.
			// but hard to occur
			exit('Sorry, critical file system error, your request has aborted.');
		}
		elseif ( count($dir_list) <= 0 ) {
			 return FALSE;
		}
		if ( $this->CI == NULL ) {
			$this->CI =& get_instance();
		}
		$dir_filelist = array();
		$real_files = array();
		//This loop will get the command(s) from the filelist and save the real file pathname to the classe variable
		foreach ( $dir_list as $full_filepath ) {
			$filename_noextension = strtolower(pathinfo($full_filepath, PATHINFO_FILENAME));
			if ( strpos($filename_noextension, '_') !== FALSE ) {
				if ( osa_str_extract($filename_noextension, '_', TRUE) != strtolower($this->CI->config->item('cms_unit_org'))) {
					continue;
				}
				$cmd = osa_str_extract($filename_noextension, '_', FALSE);
			}
			else {
				$cmd = strtolower($filename_noextension);
			}
			if ( $cmd == self::CMD_STOP ) {
				$this->cmd_filename = $full_filepath;
				return self::CMD_STOP;
			}
			$dir_filelist[] = $cmd;
			$real_files[$cmd] = $full_filepath;
		}
		$sites_array = array(self::CMD_MAINTENANCE, self::CMD_MESSAGE);
		//Loops thru the command array in the order assigned. The order is important.
		//Returns the command if a match is found compare to the command(s) extracted from file list
		foreach ( $sites_array as $sitefile ) {
			if ( in_array($sitefile, $dir_filelist) ) {
				$this->cmd_filename = $real_files[$sitefile];
				return $sitefile;
			}
		}
		return FALSE;
	}

	/**
	 * read string from a site file
	 * @return string message in a file and already line breaks in every newlines
	 */
	private function set_notice_message(){
		if ( !$this->cmd_filename ) {
			return;
		}
		$string_message = file_get_contents( $this->cmd_filename );
		if ( !empty($string_message) ) {
			// '<br />' or '<br>' inserted before all newlines (\r\n, \n\r, \n and \r).
			$string_message = nl2br($string_message);
			return $this->CI->config->set_item('cms_login_message', $string_message);
		}
		else {
			return;
		}
	}

	/**
	 * Kick all users except user who has pass through sesssion
	 * use the same way that maintenance mode do
	 */
	private function set_stop_mode(){
		if ( !$this->check_auth() ) {
			return;
		}
		$login_obj = osa_login_object();
		// no magic password, use maintenance function
		if ( !isset($login_obj->cms_stopmode_passthrough) || empty($login_obj->cms_stopmode_passthrough) ) {
			$this->set_maintenance_mode(TRUE);
		}
		return;
	}
	/**
	 * set system to maintenance mode means clear the current session and redirect to root page
	 * @param bool $kick_admin in stop mode, kick all users including admin (except pass through session)
	 */
	private function set_maintenance_mode($kick_admin = FALSE){
		if ( !$this->check_auth() ) {
			return;
		}
		$login_obj = osa_login_object();
		// login by using magic password
		if ( isset($login_obj->cms_stopmode_passthrough) && $login_obj->cms_stopmode_passthrough === TRUE ) {
	   	return;
		}
		$access_id = $login_obj->accessid;
		// normal user(s) who doesn't has admin role
    	if ( $access_id != CMS_ACCESS_ADMIN || $kick_admin === TRUE ) {
			// using ajax, print or popup the message
			if( osa_is_ajax() ) {
				$msg = '<li style=\'display:block;color:red;\'>'. $this->CI->config->item('cms_login_message') .'<br>'.
						 lang('gen_maintenance_ajaxmsg') .'</li>';
				echo osa_ajaxmsg_redirecthome($msg);
				$this->CI->login_model->destroyLogin();
				exit;
			}
			// if not ajax, clear session and redirect
			else {
				$this->CI->login_model->destroyLogin();
				redirect();
				exit;
			}
    	}
    	return;
	}

	/**
	 * check authenticated or not
	 * @return boolean
	 */
	private function check_auth(){
		static $auth = NULL;
		if ($auth === NULL) {
			$this->CI->load->model('auth/login_model');
			$login_auth = $this->CI->login_model->isAuthenticated();
			if ( $login_auth ) {
				return $auth = $login_auth;
			}
			// if no login in system, check in survey
			$this->CI->load->model('auth/survey_login_model');
			$survey_auth = $this->CI->survey_login_model->isAuthenticated();
			$auth = $survey_auth;
		}
		return $auth;
	}

}
