<?php
/*	CLASS MANAGING EXTERNAL CONNECTIONS REQUIRING COMPLEX / MULTI-STEP AUTHORIZATIONS
 *	html part showing wizard in magnificPopup through ajax + PHP logical part
 */

class gg_connection_hub {
	
	public $gid; // (int) gallery ID
	public $src; // (string) images source type
	public $to_consider = array( // types to consider for the hub
		'g_drive',
		'onedrive',
	); 
	
	private $tax_name = 'gg_connect_hub'; // connections taxonomy name
	private $main_term_id; // ID of specific source's main term
	
    
	public function __construct($gid, $src = false) {
		$this->gid = $gid;
		$this->src = (empty($src)) ? get_post_meta($gid, 'gg_type', true) : $src;
        
        
	}
	
    
    
    // retrieve data for an hub connection
    public static function get_data($gid, $conn_id = false) {
        if(empty($conn_id)) {
            $conn_id = get_post_meta($gid, 'gg_connect_id', true);
            
            if(empty($conn_id)) {
                return false;
            }
        }

        $term = get_term($conn_id, 'gg_connect_hub');

        if(!is_object($term)) {
            return false;
        }
        return  unserialize(base64_decode($term->description));
    }
    
    
	
	/*****************************************************************************************************************
	**************** WIZARD PART *****************
	**********************************************/
	
	// PRINT CODE
	// shows saved connections for selected source
	// JS code to add and call ajax script
	public function wizard() {
        if($this->src == 'g_drive' && version_compare(PHP_VERSION, '8.0.2', '<')) {
            echo 'Google SDK requires PHP version 8.0.2 or higher';
            return false;
        } 
        
        $connections = $this->src_connections();

		// start code
		$code = '
		<h3>'. $this->source_name() .'</h3>';
		
		// list connections
		if(is_array($connections) && count($connections)) {
			$code .= '<table>';
			
			foreach($connections as $conn) {
				$term = get_term_by('id', $conn, $this->tax_name);
				
				$code .= '
				<tr rel="'. $conn .'">
					<td><span class="dashicons dashicons-no-alt gg_del_row" title="'. esc_attr__('delete connection', 'gg_ml') .'"></span></td>
					<td>'. $term->name .'</td>
				</tr>';	
			}
			
			$code .= '</table>';
		}
		else {
			$code .= '<p><em>'. esc_html__('no connections', 'gg_ml') .' ..</em><br/><br/></p>';	
		}
		
		$code .= '
		<div id="gg_add_conn_wrap">
			<span>'. esc_html__('add connection', 'gg_ml') .'</span>
			<form id="gg_add_conn_form" class="gg_displaynone">'. $this->add_conn_form() .'</form>
		</div>';
		
		echo $code;
		?>
		<script type="text/javascript">
		(function($) { 
            "use strict";
            
            // show add-conn form
            $(document).on('click', '#gg_add_conn_wrap > span', function()  {
                $(this).addClass('gg_displaynone');
                $(this).parent().find('form').removeClass('gg_displaynone');
            });
        })(jQuery);
		</script>
		<?php
	}
	
	
	/* form code with specific fields - source based */
	private function add_conn_form() {
        $form = '';
        if($this->src == 'g_drive') {
            $form .= '
            <style>
            #gg_gdrive_dispute_warn {
                background: #fff8c4;
                display: block;
                padding: 15px;
                margin: -25px -15px 0;
                font-size: 96%;
                line-height: normal;
                color: #714c03;
            }
            </style>
            <p>
                <span id="gg_gdrive_dispute_warn">Despite of a validation process actually taking months, Google is not giving the definitive clearance to use a specific API scope in Global Gallery. Please ignore the alert shown while connecting and proceed</span>
            </p>';   
        }
        
		$form .= '
		<p>
			<label>'. esc_html__('Connection Name', 'gg_ml') .'</label>
			<input type="text" name="conn_name" autocomplete="off" maxlength="250" />
		</p>';
		
		switch($this->src) {

			case 'g_drive' :
				include_once(GG_DIR . '/classes/source_helpers/gdrive_integration.php');
				$gdrive = new gg_gdrive_integration($this->gid);
				
				$form .= '
				<p>
					<label>'. esc_html__('Google Username', 'gg_ml') .'</label>
					<input name="gdrive_user" type="text" />
				</p>
				<p>
					<label>'. esc_html__('Google Token', 'gg_ml') .'</label>
					<input name="gdrive_token" type="text" autocomplete="off" /> <br/>
					<a href="'. $gdrive->accept_app() .'" target="_blank">'. esc_html__("Get your Google Drive token", 'gg_ml') .' &raquo;</a>
				</p>';
				break;	
				
				
				
			case 'onedrive' :
				include_once(GG_DIR . '/classes/source_helpers/onedrive_integration.php');
				$onedrive = new gg_onedrive_integration($this->gid);
				
				$form .= '
				<p>
					<label>'. esc_html__('Microsoft Username', 'gg_ml') .'</label>
					<input name="onedrive_user" type="text" />
				</p>
				<p>
					<label>'. esc_html__('Microsoft Token', 'gg_ml') .'</label>
					<input name="onedrive_token" type="text" autocomplete="off" /> <br/>
					<a href="'. $onedrive->accept_app() .'" target="_blank">'. esc_html__("Get your OneDrive token", 'gg_ml') .' &raquo;</a>
				</p>';
				break;	
				
			
			default : return 'invalid source'; break;
		}

		
		$form .= '
		<section></section>
		<input type="button" value="'. esc_attr__('submit', 'gg_ml') .'" name="gg_conn_hub_submit" id="gg_conn_hub_submit" class="button-primary" />';
		
		return $form;
	}
	
	
	/* be sure main term for this source exists - eventually create it - put it in class property */
	private function main_term_exists() {
		$slug = 'gg-'. $this->src;  
		$result = term_exists($slug, $this->tax_name);
		
		// create it
		if(empty($result)) {
			$inserted = wp_insert_term($slug, $this->tax_name, array('slug' => $slug));
			
			if(is_wp_error($inserted)) {
				trigger_error( $inserted->get_error_message(), E_USER_ERROR);
				return false;		
			}
			
			$this->main_term_id = $inserted->term_id;
		}
		else {
			$this->main_term_id = $result['term_id'];
		}
		
		return $this->main_term_id;
	}
	
	
	/* retrieve connections (terms) for a specific source */
	private function src_connections() {
		$this->main_term_exists();
		return get_term_children($this->main_term_id, $this->tax_name);	
	}
	
	
	/* source clear name */
	private function source_name() {
		switch($this->src) {
			case 'g_drive'		: return 'Google Drive';		break;
			case 'onedrive'		: return 'Microsoft OneDrive';	break;
		}
	}
	

	/* CONNECTIONS DROPDOWN for chosen type - used to connect */
	public function src_connections_dd() {
		$connections = $this->src_connections();
		$sel_opt = get_post_meta($this->gid, 'gg_connect_id', true);
		
		if(!is_array($connections) || !count($connections)) {	
			$dd = '<span class="gg_displaynone">'. esc_html__('No connections for this source','gg_ml'). ' ..</span>';
		}
		else {
			$dd = '
			<label>'. esc_html__('Choose connection') .'</label>
			<select name="gg_connect_id" id="gg_connect_id" autocomplete="off">';
			
			foreach($connections as $conn) {
				$term = get_term_by('id', $conn, $this->tax_name);	
				$dd .= '<option value="'.$conn.'" '. selected($sel_opt, $conn, false) .'>'. $term->name .'</option>';
			}
			
			$dd .= '</select>';
		}
		
		return $dd . 
				'<a href="#gg_conn_hub_wizard_wrap" id="gg_launch_conn_wizard">'. esc_html__("manage connections", 'gg_ml') .'</a>' .
				'<div id="gg_conn_hub_wizard_outer_wrap" class="gg_displaynone">
					<div id="gg_conn_hub_wizard_wrap"></div>
				</div>';
	}



	
	/*****************************************************************************************************************
	**************** LOGICAL PART *****************
	**********************************************/
	
	
	// associative array containing fetched data for connection setup
	public $ajax_data; 
	
	// variable containing data retrieved from test_connection()
	private $connect_data;
	
	// created (term) connection ID
	public $connect_id;
	 
	
	
	/* 
	 * WRAP-UP function to be used in AJAX - validate / tries connection / saves data 
	 * @return (string) succcess if everything is ok - otherwise the error message
	 */
	public function setup_connection() {
		/* debug
		ini_set('display_errors', 1);
		ini_set('display_startup_errors', 1);
		error_reporting(E_ALL);*/
		
		$validation = $this->handle_data();
		if($validation !== true) {return $validation;}
		
		$conn_check = $this->test_connection();
		if($conn_check !== true) {return $conn_check;}
		
		//
		$saving = $this->save_connection();
		if($saving !== true) {return $saving;}
		
		return 'success';
	}
	
	
	
	/* 
	 * HANDLE DATA - passed via ajax and different for every source 
	 * @return (true/string) true if data has been handled successfully - otherwise error validation message
	 */
	private function handle_data() {
		include_once('simple_form_validator.php');
		
		$validator = new simple_fv(GG_ML);
		$indexes = array();
		$indexes[] = array('index'=>'conn_name', 'label'=>esc_html__('Connection Name', 'gg_ml'), 'max_len'=>250, 'required'=>true);
		
		switch($this->src) {
			case 'g_drive' :
				$indexes[] = array('index'=>'gdrive_user', 'label'=>esc_html__('Google Username', 'gg_ml'), 'required'=>true);
				$indexes[] = array('index'=>'gdrive_token', 'label'=>esc_html__('Google Token', 'gg_ml'), 'required'=>true);
				break;	
				
			case 'onedrive' :
				$indexes[] = array('index'=>'onedrive_user', 'label'=>esc_html__('Microsoft Username', 'gg_ml'), 'required'=>true);
				$indexes[] = array('index'=>'onedrive_token', 'label'=>esc_html__('Microsoft Token', 'gg_ml'), 'required'=>true);
				break;	
		}

		$validator->formHandle($indexes);
		$error = $validator->getErrors();
		
		if(!empty($error)) {
			return $error;	
		} 
		else {
			$this->ajax_data = $validator->form_val;	
			return true;
		}
	}
	
	
	
	/* 
	 * TEST SOURCE CONNECTION 
	 * @return (true/string) true if data has been handled successfully - otherwise error validation message
	 */
	public function test_connection() {
		$data = $this->ajax_data;
        $existing_connections = $this->src_connections();
        
        foreach($existing_connections as $ec) {
            $ec_term = get_term_by('id', $ec, $this->tax_name);    
            
            if($data['conn_name'] == $ec_term->name) {
                return esc_html__('There is already a connection with the same name', 'gg_ml');		        
            }
        }
        
		switch($this->src) {
			case 'g_drive' :
				// check if username already exists in stored ones
				$stored = get_option('gg_gdrive_base_tokens_db', array());
				if(isset($stored[ $data['gdrive_user'] ])) {
					return esc_html__('Username already used in another connection', 'gg_ml');		
				}
				
				// test connection (already storing tokens in case of success)
				include_once(GG_DIR .'/classes/source_helpers/gdrive_integration.php');
				
				$gdrive = new gg_gdrive_integration(false, $data['gdrive_user']);
				$connection = $gdrive->get_access_token($data['gdrive_token']);
				
				return ($connection) ? true : esc_html__('Connection failed - Check username and access token', 'gg_ml');
				break;	
			
			
			/*
			case 'onedrive' :
				// check if username already exists in stored ones
				$stored = get_option('gg_onedrive_base_tokens_db', array());
				if(isset($stored[ $data['onedrive_user'] ])) {
					return esc_html__('Username already used in another connection', 'gg_ml');		
				}
				
				// test connection (already storing tokens in case of success)
				include_once(GG_DIR .'/classes/source_helpers/onedrive_integration.php');
				
				$onedrive = new gg_onedrive_integration(false, $data['onedrive_user']);
				$connection = $onedrive->setup_first_access_token($data['onedrive_token']);
				
				return ($connection) ? true : esc_html__('Connection failed - Check username and authorization token', 'gg_ml');
				break;*/	
			
			
			default : return 'invalid source'; break;
		}
	}
	
	
	
	/* SAVE CONNECTION as term */
	public function save_connection() {
		
		// specific data to store for each source
		switch($this->src) {
			case 'g_drive' :
				$data = array(
					'gdrive_user' => $this->ajax_data['gdrive_user'] // dynamic token stored in gg_gdrive_base_tokens_db option
				);
				break;	
			

			case 'onedrive' :
				$data = array(
					'onedrive_user' => $this->ajax_data['onedrive_user'] // dynamic token stored in gg_onedrive_base_tokens_db option
				);
				break;	

			default : $data = $this->ajax_data; break;
		}
		
		
		// be sure main term and data exists 
		$parent = $this->main_term_exists();
		if(empty($data)) {
            return esc_html__('no data to store', 'gg_ml');
        }
		
		// create term	
		$args = array(
			'description' => base64_encode(serialize($data)),
			'slug' => uniqid(),
    		'parent'=> $parent
		);
		$result = wp_insert_term($this->ajax_data['conn_name'], $this->tax_name, $args);
		
		if(is_wp_error($result)) {
			//echo $result->get_error_message(); // debug
			return 'error creating connection term';
		} else {
			$this->connect_id = $result['term_id'];
			return true;
		}
	}
}
