<?php



/////////////////////////////////////////

// Include original WPAlchemy Class    //

/////////////////////////////////////////

if(!class_exists('WPAlchemy_MetaBox'))

{

	require_once VP_FileSystem::instance()->resolve_path('includes', 'wpalchemy/MetaBox');

}



class VP_Option extends WPAlchemy_MetaBox

{



	private $_option_key;



	private $_page_slug;



	private $_template;



	private $_is_dev_mode;



	private $_use_util_menu;



	private $_use_auto_group_naming;



	private $_role;



	private $_menu_page;



	private $_page_title;



	private $_menu_label;



	private $_layout;



	private $_options_set = NULL;

	

	private $_options = NULL;



	private $_hook_suffix;



	public static $pool;



	public function __construct(array $configs)

	{



		// extract and set default value

		extract($test = array_merge(array(

			'is_dev_mode'           => false,

			'use_auto_group_naming' => true,

			'use_util_menu'         => true,

			'minimum_role'          => 'edit_theme_options',

			'menu_page'             => 'themes.php',

			'layout'                => 'fixed',

			'page_title'            => __( 'Vafpress Options', BUNCH_NAME ),

			'menu_label'            => __( 'Vafpress Options', BUNCH_NAME ),

			'priority'              => 10,

		), $configs));



		// check and set required configs

		if(isset($option_key)) $this->set_option_key($option_key);

		else throw new Exception(__( 'Option Key is required', BUNCH_NAME ), 1);

		if(isset($template)) $this->set_template($template);

		else throw new Exception(__( 'Template Array/File is required', BUNCH_NAME ), 1);

		if(isset($page_slug)) $this->set_page_slug($page_slug);

		else throw new Exception(__( 'Page Slug is required', BUNCH_NAME ), 1);



		// swim in the pool

		self::$pool[$this->get_option_key()] = &$this;

		

		// check and set the remaining configs

		if(isset($menu_page))             $this->set_menu_page($menu_page);

		if(isset($is_dev_mode))           $this->is_dev_mode($is_dev_mode);

		if(isset($use_util_menu))         $this->use_util_menu($use_util_menu);

		if(isset($use_auto_group_naming)) $this->use_auto_group_naming($use_auto_group_naming);

		if(isset($minimum_role))          $this->set_minimum_role($minimum_role);

		if(isset($page_title))            $this->set_page_title($page_title);

		if(isset($layout))                $this->set_layout($layout);

		if(isset($menu_label))            $this->set_menu_label($menu_label);



		// add first_activation hook to save initial values to db

		add_action('vp_option_first_activation', array($this, 'initial_db_setup'));



		// check if option key not existed init data from default values

		$options = get_option( $this->get_option_key() );

		if( $options === FALSE )

		{

			do_action('vp_option_first_activation');

		}



		// init options from db and expose to the api

		$this->init_options_from_db();



		// setup ajax

		add_action('wp_ajax_vp_ajax_' . $this->get_option_key() . '_export_option', array($this, 'ajax_export_option'));

		add_action('wp_ajax_vp_ajax_' . $this->get_option_key() . '_import_option', array($this, 'ajax_import_option'));

		add_action('wp_ajax_vp_ajax_' . $this->get_option_key() . '_save'         , array($this, 'ajax_save'));

		add_action('wp_ajax_vp_ajax_' . $this->get_option_key() . '_restore'      , array($this, 'ajax_restore'));



		// register menu page

		add_action( 'admin_menu', array($this, 'register_menu_page'), $priority );

	}



	public static function get_pool()

	{

		return self::$pool;

	}



	public function init_options_from_db()

	{

		$options = get_option( $this->get_option_key() );

		if( $options !== FALSE )

		{

			$this->set_options($options);

		}

	}



	// register menu page as configured

	public function register_menu_page()

	{

		if( is_array( $this->get_menu_page() ) )

		{

			$menu_page = $this->get_menu_page();



			// check and set required configs

			if(!isset($menu_page['icon_url'])) $menu_page['icon_url'] = '';

			if(!isset($menu_page['position'])) $menu_page['position'] = null;



			$hook_suffix = add_menu_page(

				$this->get_page_title(),

				$this->get_menu_label(),

				$this->get_minimum_role(),

				$this->get_page_slug(),

				array($this, 'option_page_display'),

				$menu_page['icon_url'],

				$menu_page['position']

			);

		}

		else

		{

			$hook_suffix = add_submenu_page(

				$this->get_menu_page(),

				$this->get_page_title(),

				$this->get_menu_label(),

				$this->get_minimum_role(),

				$this->get_page_slug(),

				array($this, 'option_page_display')

			);

		}

		$this->set_hook_suffix($hook_suffix);



		// register option page load

		add_action( 'load-' . $this->get_hook_suffix(), array($this, 'setup') );

	}



	public function setup()

	{

		$this->init_options_set();

		$this->init_options();

		$this->enqueue_scripts_and_styles();

		// show dev mode notice

		if( $this->is_dev_mode() )

			add_action( 'admin_notices', array( $this, 'dev_mode_notice' ) );

	}



	public function dev_mode_notice()

	{

		VP_WP_Util::admin_notice(__("Development Mode is Active, options' values won't be saved into database.", BUNCH_NAME), false);

	}



	public function enqueue_scripts_and_styles()

	{	

		$opt_loader = VP_WP_Loader::instance();

		$opt_loader->add_types( $this->get_field_types(), 'option' );

		$opt_loader->add_main_js( 'vp-option' );

		$opt_loader->add_main_css( 'vp-option' );

		$opt_loader->add_js_data( 'vp-option', 'custom_local.name', $this->_option_key );

		$opt_loader->add_js_data( 'vp-option', 'custom_local.SAVE_SUCCESS', VP_Option_Control_Set::SAVE_SUCCESS );

		$opt_loader->add_js_data( 'vp-option', 'custom_local.SAVE_NOCHANGES', VP_Option_Control_Set::SAVE_NOCHANGES );

		$opt_loader->add_js_data( 'vp-option', 'custom_local.SAVE_FAILED', VP_Option_Control_Set::SAVE_FAILED );

	}



	function save_and_reinit()

	{

		// do saving

		$result = $this->get_options_set()->save($this->get_option_key());

		// re-init $opt

		$this->init_options_from_db();



		return $result;

	}



	function ajax_save()

	{//printr($_POST);

		$result = $this->vp_verify_nonce();

		

		if($result['status'])

		{

			$this->init_options_set();

			$this->init_options();



			$option  = $_POST;

			$nonce   = $_POST['nonce'];



			//$option  = VP_Util_Array::unite( $option, 'name', 'value' );

			//$option  = $this->get_options_set()->normalize_values($option);



			// stripslashes added by WP in $_GET / $_POST

			$option  = stripslashes_deep($option);



			// get old options from set

			$old_opt = $this->get_options_set()->get_values();



			//$this->get_options_set()->populate_values($option, true);

			//printr($this->get_options_set()->get_values());

			// get back options from set

			$opt = $option;//$this->get_options_set()->get_values();

			//printr($opt);

			// before ajax save action hook

			do_action('vp_option_before_ajax_save', $opt);



			// save and re-init options

			//$result = $this->save_and_reinit();

			update_option( $this->get_option_key(), $opt );

			$result = array( "status"=>true,"code"=>2,"message"=>"Changes are saved" );



			// after ajax save action hook

			do_action('vp_option_after_ajax_save', $opt, $old_opt, $result['status'], $this->get_option_key());



			// option key specific after ajax save action hook

			do_action('vp_option_after_ajax_save-' . $this->get_option_key(), $opt, $old_opt, $result['status']);

		}



		if (ob_get_length()) ob_clean();

		header('Content-type: application/json');

		echo json_encode($result);

		die();

	}



	function ajax_restore()

	{

		$result = $this->vp_verify_nonce();

		

		if( $result['status'] )

		{

			$this->init_options_set();

			$set     = $this->get_options_set();

			$options = $set->get_defaults();



			// get old options from set

			$old_opt = $this->get_options_set()->get_values();



			// set options so that default value can be accessed in binding done in `setup`

			$this->set_options($options);



			// setup and process values

			$set->setup($options);



			// before ajax save action hook

			do_action('vp_option_before_ajax_restore', $options);



			// save and re-init options

			$result  = $this->save_and_reinit();



			$options = $this->get_options_set()->get_values();



			// after ajax restore action hook

			do_action('vp_option_after_ajax_restore', $options, $old_opt, $result['status'], $this->get_option_key());



			// after ajax restore action hook

			do_action('vp_option_after_ajax_restore-' . $this->get_option_key(), $options, $old_opt, $result['status']);

		}



		if (ob_get_length()) ob_clean();

		header('Content-type: application/json');

		echo json_encode($result);

		die();

	}



	function ajax_import_option()

	{

		global $vp_set, $vp_config;



		$options = null;

		$old_opt = null;



		$result = $this->vp_verify_nonce();

		

		if($result['status'])

		{

			$this->init_options_set();



			$option = $_POST['option'];



			if(empty($option))

			{

				$result['status']  = false;

				$result['message'] = __("Can not be empty", BUNCH_NAME);

			}

			else

			{

				$option = json_decode(stripslashes($option), true);



				if( is_array($option) )

				{

					$set = $this->get_options_set();

					

					// get old options from set

					$old_opt = $this->get_options_set()->get_values();



					// populate new values

					$set->populate_values($option, true);



					// save and re-init options

					$result  = $this->save_and_reinit();



					// get new options

					$options = $this->get_options_set()->get_values();

				}

				else

				{

					$result['status']  = false;

					$result['message'] = __("Invalid data", BUNCH_NAME);

				}

			}

		}



		// after ajax import action hook

		do_action('vp_option_after_ajax_import', $options, $old_opt, $result['status'], $this->get_option_key());



		// after ajax import action hook

		do_action('vp_option_after_ajax_import-' . $this->get_option_key(), $options, $old_opt, $result['status']);



		if (ob_get_length()) ob_clean();

		header('Content-type: application/json');

		echo json_encode($result);

		die();

	}



	function ajax_export_option()

	{

		global $wpdb;



		$sr_options = null;

		$db_options = null;



		$result = $this->vp_verify_nonce();



		if($result['status'])

		{

			$db_options = get_option($this->get_option_key());

			$sr_options = json_encode($db_options);



			$result = array(

				'status' => true,

				'message'=> __("Successful", BUNCH_NAME),

				'option' => $sr_options,

			);

		}



		// after ajax export action hook

		do_action('vp_option_after_ajax_export', $db_options, $sr_options, $result['status'], $this->get_option_key());



		// after ajax export action hook

		do_action('vp_option_after_ajax_export-' . $this->get_option_key(), $db_options, $sr_options, $result['status']);





		if (ob_get_length()) ob_clean();

		header('Content-type: application/json');

		echo json_encode($result);

		die();

	}



	function vp_verify_nonce()

	{

		$nonce  = $_POST['nonce'];

		$verify = check_ajax_referer('vafpress', 'nonce', false);

		if($verify)

		{

			$result['status']  = true;

			$result['message'] = __("Successful", BUNCH_NAME);	

		}

		else

		{

			$result['status']  = false;

			$result['message'] = __("Unverified Access.", BUNCH_NAME);

		}

		return $result;

	}



	function initial_db_setup()

	{

		// init set and options

		$this->init_options();

		$set = $this->get_options_set();



		// get baked values from options set

		$opt = $set->get_values();



		// before db options db action hook

		do_action('vp_option_before_db_init', $opt);



		// save to db

		$result = $this->save_and_reinit();



		// after db options db action hook

		do_action('vp_option_after_db_init', $opt, $result['status'], $this->get_option_key());

		do_action('vp_option_after_db_init-' . $this->get_option_key(), $opt, $result['status']);

	}



	public function init_options()

	{

		$this->init_options_set();

		$set = $this->get_options_set();



		// try load option from DB

		$db_options = is_array(get_option($this->get_option_key())) ? get_option($this->get_option_key()) : array();

		$default    = $set->get_defaults();

		if (!empty($db_options))

		{

			// unify, preserve option from DB but appends anything new from default

			$options = $db_options;

			$options = $options + $default;

		}

		else

		{

			$options = $set->get_defaults();

		}



		// If dev mode, always use default, no db interaction

		if($this->is_dev_mode())

			$options = $set->get_defaults();



		// set options so that default value can be accessed in binding done in `setup`

		$this->set_options($options);



		// setup and process values

		$set->setup($options);

		

	}



	public function init_options_set()

	{

		if(!is_null($this->get_options_set()))

			return;



		if( is_string($this->get_template()) and is_file($this->get_template()) )

			$template = include $this->get_template();

		else if(is_array($this->get_template()))

			$template = $this->get_template();

		else

			throw new Exception(__( 'Invalid template supplied', BUNCH_NAME ), 1);



		$parser = new VP_Option_Parser();

		$set    = $parser->parse_array_options($template, $this->use_auto_group_naming());

		$set->set_layout($this->get_layout());



		// assign set object

		$this->set_options_set($set);



		if( $this->use_util_menu() )

		{

			// setup utility menu

			$util_menu = new VP_Option_Control_Group_Menu();

			$util_menu->set_title(__('Utility', BUNCH_NAME));

			$util_menu->set_name('menu_util');

			$util_menu->set_icon('font-awesome:icon-ambulance');



			// setup restore default section

			$restore_section = new VP_Option_Control_Group_Section();

			$restore_section->set_title(__('Restore Default', BUNCH_NAME));

			$restore_section->set_name('section_restore');



			// setup restore button

			$restore_button = new VP_Option_Control_Field_Restore();

			$restore_section->add_field($restore_button);



			// setup exim section

			$exim_section = new VP_Option_Control_Group_Section();

			$exim_section->set_title(__('Export/Import', BUNCH_NAME));

			$exim_section->set_name('section_exim');



			// setup exim field

			$exim_field = new VP_Option_Control_Field_ImpExp();

			$exim_section->add_field($exim_field);



			// add exim section

			$util_menu->add_control($exim_section);



			$util_menu->add_control($restore_section);

			$set->add_menu($util_menu);

		}

	}



	public function option_page_display()

	{

		echo $this->get_options_set()->render();

	}



	public function get_field_types()

	{

		// $this->init_options_set();

		return $this->get_options_set()->get_field_types();

	}



	// @todo return `vp_option` like function

	public function create_get_option_helper()

	{



	}



	//////////////////////////////

	// GETTER AND SETTER CHUNKS //

	//////////////////////////////



	/**

	 * Get _hook_suffix

	 *

	 * @return String _hook_suffix

	 */

	public function get_hook_suffix()

	{

		return $this->_hook_suffix;

	}



	/**

	 * Set _hook_suffix

	 *

	 * @param String $_hook_suffix _hook_suffix

	 */

	public function set_hook_suffix($_hook_suffix)

	{

		$this->_hook_suffix = $_hook_suffix;

		return $this;

	}



	/**

	 * Get _template

	 *

	 * @return String _template

	 */

	public function get_template()

	{

		return $this->_template;

	}



	/**

	 * Set _template

	 *

	 * @param String $_template _template

	 */

	public function set_template($_template)

	{

		$this->_template = $_template;

		return $this;

	}



	/**

	 * Get _options

	 *

	 * @return String _options

	 */

	public function get_options()

	{

		return $this->_options;

	}

	

	/**

	 * Set _options

	 *

	 * @param String $_options _options

	 */

	public function set_options($_options)

	{

		$this->_options = $_options;

		return $this;

	}



	/**

	 * Get _options_set

	 *

	 * @return String _options_set

	 */

	public function get_options_set()

	{

		return $this->_options_set;

	}

	

	/**

	 * Set _options_set

	 *

	 * @param String $_options_set _options_set

	 */

	public function set_options_set($_options_set)

	{

		$this->_options_set = $_options_set;

		return $this;

	}



	/**

	 * Get _menu_page

	 *

	 * @return String _menu_page

	 */

	public function get_menu_page()

	{

		return $this->_menu_page;

	}

	

	/**

	 * Set _menu_page

	 *

	 * @param String $_menu_page _menu_page

	 */

	public function set_menu_page($_menu_page)

	{

		$this->_menu_page = $_menu_page;

		return $this;

	}



	/**

	 * Set _layout

	 *

	 * @return String _layout

	 */

	public function get_layout()

	{

		return $this->_layout;

	}

	

	/**

	 * Get _layout

	 *

	 * @param String $_layout _layout

	 */

	public function set_layout($_layout)

	{

		$this->_layout = $_layout;

		return $this;

	}



	/**

	 * Get _menu_page_slug

	 *

	 * @return String _menu_page_slug

	 */

	public function get_page_slug()

	{

		return $this->_page_slug;

	}

	

	/**

	 * Set _page_slug

	 *

	 * @param String $_page_slug _page_slug

	 */

	public function set_page_slug($_page_slug)

	{

		$this->_page_slug = $_page_slug;

		return $this;

	}



	/**

	 * Get _menu_label

	 *

	 * @return String _menu_label

	 */

	public function get_menu_label()

	{

		return $this->_menu_label;

	}

	

	/**

	 * Set _menu_label

	 *

	 * @param String $_menu_label _menu_label

	 */

	public function set_menu_label($_menu_label)

	{

		$this->_menu_label = $_menu_label;

		return $this;

	}



	/**

	 * Get _page_title value

	 *

	 * @return String _page_title

	 */

	public function get_page_title()

	{

		return $this->_page_title;

	}

	

	/**

	 * Set _page_title

	 *

	 * @param String $_page_title _page_title

	 */

	public function set_page_title($_page_title)

	{

		$this->_page_title = $_page_title;

		return $this;

	}



	/**

	 * Get _minimum_role value

	 *

	 * @return String $_minimum_role

	 */

	public function get_minimum_role()

	{

		return $this->_minimum_role;

	}

	

	/**

	 * Set _minimum_role value

	 *

	 * @param String $_minimum_role _minimum_role

	 */

	public function set_minimum_role($_minimum_role)

	{

		$this->_minimum_role = $_minimum_role;

		return $this;

	}



	/**

	 * Get _option_key value

	 *

	 * @return String $_option_key

	 */

	public function get_option_key()

	{

		return $this->_option_key;

	}

	

	/**

	 * Set _option_key value

	 *

	 * @param String $_option_key $_option_key

	 */

	public function set_option_key($_option_key)

	{

		$this->_option_key = $_option_key;

		return $this;

	}



	/**

	 * Get/Set whether to use auto group naming or not

	 *

	 * @return bool $_use_auto_group_naming

	 */

	public function use_auto_group_naming($_use_auto_group_naming = NULL)

	{

		if(is_null($_use_auto_group_naming))

			return $this->_use_auto_group_naming;

		$this->_use_auto_group_naming = $_use_auto_group_naming;

	}



	/**

	 * Get/Set whether to use export import menu or not

	 *

	 * @return bool $_use_util_menu

	 */

	public function use_util_menu($_use_util_menu = NULL)

	{

		if(is_null($_use_util_menu))

			return $this->_use_util_menu;

		$this->_use_util_menu = $_use_util_menu;

	}



	/**

	 * Get/Set whether it's development mode or not

	 *

	 * @return bool $_dev_mode

	 */

	public function is_dev_mode($_dev_mode = NULL)

	{

		if(is_null($_dev_mode))

			return $this->_dev_mode;

		$this->_dev_mode = $_dev_mode;

	}



}



/**

 * EOF

 */