<?php
/*
Plugin Name: Rover IDX
Plugin URI: https://roveridx.com/
Description: Very fast, highly customizable! Display MLS Listings and Maps, allow Saved Searches and Favorites.  Simple shortcodes and easy-to-use Search Panel.  Auto-mailings with your branding right at the top!
Author: Rover IDX, LLC
Author URI: https://roveridx.com/
Version: 4.0.0.2812

Copyright (c) 2008-2026 Rover IDX, LLC  All Rights Reserved.

This program is free 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

*/

defined('ABSPATH') || exit;

#
# --------------------------------------------------------------------
# Constants
# --------------------------------------------------------------------
#

if (!defined('ROVER_IDX_PLUGIN_URL')) {
	define('ROVER_IDX_PLUGIN_URL', plugin_dir_url(__FILE__));
}

require_once 'rover-common.php';
require_once 'rover-database.php';
require_once 'rover-version.php';



#
# --------------------------------------------------------------------
# Main Plugin Singleton
# --------------------------------------------------------------------
#
final class Rover_IDX_Instance
	{
	private static $instance = null;

	public static function get_instance(): self
		{
		if (self::$instance === null) {
			self::$instance = new self();
			}

		return self::$instance;
		}

	private function __construct()
		{
		require_once 'rover-init.php';
		}

	#	__clone() and __wakeup() are PHP magic methods used to control how an object behaves
	#	when it is copied or restored. They are integrity guards.
	public function __wakeup(): void
		{
		throw new \Exception('Cannot unserialize singleton');
		}

	private function __clone() {}
	}

#
# --------------------------------------------------------------------
# Bootstrap Plugin
# --------------------------------------------------------------------
#
Rover_IDX_Instance::get_instance();

#
# --------------------------------------------------------------------
# Lifecycle Hooks
# --------------------------------------------------------------------
#
register_activation_hook(__FILE__, 'roveridx_activate');
register_deactivation_hook(__FILE__, 'roveridx_deactivate');
register_uninstall_hook(__FILE__, 'roveridx_uninstall');

#
# --------------------------------------------------------------------
# Activation
# --------------------------------------------------------------------
#
function roveridx_activate(): void
	{
	try {
		if (
			!Rover_IDX_Database::tracking_table_exists() ||
			get_site_option('roveridx_db_version') !== roverVERSIONS::VERSION
			)
			{
			Rover_IDX_Database::update_rover_tables();
			}

		#	Initialize defaults
		if (false === get_option(roverOPTIONS::THEME)) {
			update_option(roverOPTIONS::THEME, rover_idx_theme_defaults());
			}

		$regions = get_option(roverOPTIONS::REGIONS);
		if (!validate_region_slugs($regions)) {
			update_option(roverOPTIONS::REGIONS, rover_idx_setup_defaults());
			}

		if (false === get_option(roverOPTIONS::SEO)) {
			update_option(roverOPTIONS::SEO, rover_idx_seo_defaults());
			}

		if (false === get_option(roverOPTIONS::SOCIAL)) {
			update_option(roverOPTIONS::SOCIAL, rover_idx_social_defaults());
			}

		#	Setup dynamic Rover page
		$post_id					= setup_rover_page();
		if (is_null($post_id)) {
			throw new Exception('Failed to setup Rover dynamic page');
			}

		#	Refresh generated assets if available
		if (isset($GLOBALS['rover_idx']) && is_object($GLOBALS['rover_idx'])) {
			$GLOBALS['rover_idx']->refresh_css();
			}

		#	Cron jobs

		if ( !wp_next_scheduled('roveridx_cron_daily') ) {
			wp_schedule_event( time(), 'daily', 'roveridx_cron_daily' );
			}

		if ( !wp_next_scheduled('roveridx_cron_hourly') ) {
			wp_schedule_event( time(), 'hourly', 'roveridx_cron_hourly' );
			}

		flush_rewrite_rules();

		set_transient('roveridx_activation_success', 'Rover IDX has been activated!', 60);
		}
	catch (Exception $e) {

		#	Log error or set a transient to show admin notice
		error_log('Rover IDX activation failed: ' . $e->getMessage());

		#	Set a transient for admin notice instead of wp_die
		set_transient('roveridx_activation_error', $e->getMessage(), 60);

		deactivate_plugins(plugin_basename(__FILE__));

		wp_die('Rover IDX could not be activated: ' . $e->getMessage());
		}
	}

function rover_idx_setup_defaults() : array {
	$perm										= get_option('permalink_structure');
	$url_ends_with_slash						= true;
	if ($perm && substr($perm, -1) != '/')
		$url_ends_with_slash					= false;

	return array(
				'url_ends_with_slash'			=> $url_ends_with_slash,
				'redirect_for_setup'			=> true,
				);
	}

function rover_idx_theme_defaults($post_id = null) : array {

#	TODO: Implement scheduled JS version checking via Rover_IDX_Schedule
#	to automatically detect when JS files are updated
#	without requiring plugin updates
#
#	require_once 'rover-scheduled.php';

#	$scheduled									= new Rover_IDX_Schedule($this->rover_idx);

	$current_js_ver								= roverVERSIONS::JS;
	if (is_array($theme_opts = get_option(roverOPTIONS::THEME)))
		{
		if (isset($theme_opts['js_version']))
			$current_js_ver						= $theme_opts['js_version'];
		}

	$theme_defaults	= array(
							'css_framework'			=> 'rover',
							'login_button'			=> 'menu-primary',
							'load_admin_bootstrap'	=> 'Yes',
							'load_emojis'			=> 'No',
							'load_google_api'		=> 'Yes',
							'load_google_libraries'	=> null,
							'google_map_key'		=> null,
							'site_version'			=> roverVERSIONS::FULL,
							'js_version'			=> roverVERSIONS::JS
							);

	if (!is_null($post_id))
		$theme_defaults['rover_post_id']		= $post_id;

	return $theme_defaults;
	}

function rover_idx_seo_defaults() : array {

	return array(
				'sitemap_enabled'	=> 'enabled',
				'crawler_redirect'	=> '404'
				);

	}

function rover_idx_social_defaults() : array {
	return array(
						'post_new'					=> 'disabled',
						'post_price_change'			=> 'disabled',
						'post_sold'					=> 'disabled',
						'post_open_houses'			=> 'disabled',
						'post_monthly_data'			=> 'disabled',

						'post_to_wp'				=> 'disabled',
						'post_to_wp_as_user'		=> 1,
						'post_to_wp_comments'		=> 'disabled',

						'email_on_error'			=> 'disabled',
						'email_on_error_to_user'	=> '',

						'publish_office_listings'	=> 'active_agents',

						'fb_access_token'			=> null,
						'facebook_app'				=> 'disabled'
						);
	}

#
# --------------------------------------------------------------------
# Deactivation
# --------------------------------------------------------------------
#
function roveridx_deactivate(): void
	{
	wp_clear_scheduled_hook('roveridx_cron_daily');
	wp_clear_scheduled_hook('roveridx_cron_hourly');

	flush_rewrite_rules();
	}

#
# --------------------------------------------------------------------
# Uninstall
# --------------------------------------------------------------------
#
function roveridx_uninstall(): void
	{
	if (Rover_IDX_Database::tracking_table_exists()) {
		Rover_IDX_Database::delete_tracking_table();
		}

	#	-------------------------------------------------------------
	#	Remove generated sitemaps (best-effort, non-fatal)
	#	-------------------------------------------------------------
	require_once ABSPATH . 'wp-admin/includes/file.php';

	$fs_ready = WP_Filesystem();

	if ($fs_ready) {
		global $wp_filesystem;

		$uploads				= wp_upload_dir();
		$dir					= trailingslashit($uploads['basedir']) . 'rover_idx_sitemap';

		if ($wp_filesystem->is_dir($dir)) {
			roveridx_fs_delete_recursive($dir);
			}
		}

	#	-------------------------------------------------------------
	#	Cleanup options (always runs)
	#	-------------------------------------------------------------
	delete_option('roveridx_db_version');
	delete_option('roveridx_has_diverse_solutions');
	delete_option(roverOPTIONS::THEME);
	delete_option(roverOPTIONS::REGIONS);
	delete_option(roverOPTIONS::SEO);
	delete_option(roverOPTIONS::SOCIAL);
	}

function roveridx_fs_delete_recursive(string $path): void
	{
	global						$wp_filesystem;

	if (!$wp_filesystem->is_dir($path)) {
		return;
		}

	$items = $wp_filesystem->dirlist($path);

	if (!is_array($items)) {
		return;
		}

	foreach ($items as $item) {
		$item_path = trailingslashit($path) . $item['name'];

		if ($item['type'] === 'd')
			{
			roveridx_fs_delete_recursive($item_path);
			}
		else
			{
			$wp_filesystem->delete($item_path, false, 'f');
			}
		}

	$wp_filesystem->delete($path, false, 'd');
	}


#
# --------------------------------------------------------------------
# Helpers
# --------------------------------------------------------------------
#
function validate_region_slugs($value): bool
	{
	return is_array($value) && isset($value['regions']);
	}

function setup_rover_page() : ?int	{

	global								$wpdb;

	$post_id							= $wpdb->get_var(
											$wpdb->prepare(
												"SELECT post_id FROM $wpdb->postmeta WHERE meta_key = %s LIMIT 1",
												roverKEYS::META_PAGE_ID
												)
											);

	if ($post_id)
		return $post_id;

	$rover_post							= array();
	$rover_post['post_title']			= 'Rover IDX page';
	$rover_post['post_content']			= '<!-- Reserved for Rover IDX dynamic pages -->';
	$rover_post['post_type']			= 'page';
	$rover_post['post_status']			= 'draft';
	$rover_post['post_author']			= 0;

	#	Insert the post into the database
	$post_id							= wp_insert_post( $rover_post );

	if (is_wp_error($post_id))
		{
		error_log('Rover IDX: Failed to reserve post ID - ' . $post_id->get_error_message());
		return null;
		}
	else
		{
		#	Add postmeta
		update_post_meta($post_id, roverKEYS::META_PAGE_ID, $post_id);

		#	Delete the post but keep the ID reserved via post_meta
		wp_delete_post($post_id, $force_delete = false);

		Rover_IDX_Database::set_template_meta($post_id, null);
		}

	return $post_id;
	}
