<?php
/**
 * Main WPSyncSheets_WPForms\WPSSLWP_Google_API namespace.
 *
 * @since 1.0.0
 * @package wpsyncsheets-for-wpforms
 */

namespace WPSyncSheets_WPForms;

/**
 * Google API Method Class
 *
 * @since 1.0.0
 */
class WPSSLWP_Google_API_Functions extends \WPSSLWP_Google_API
{
	/**
	 * Google Sheet Object
	 *
	 * @var object
	 * @since 1.0.0
	 */
	private static $instance_service = null;
	/**
	 * Google Drive Object
	 *
	 * @var object
	 * @since 1.0.0
	 */
	private static $instance_drive = null;
	/**
	 * Primary class constructor.
	 *
	 * @since 1.0.0
	 */
	public function __construct()
	{
		if (self::checkcredenatials()) {
			self::loadobject();
		}
	}
	/**
	 * Load Google API Library.
	 *
	 * @since 1.0.0
	 */
	public function loadobject()
	{
		self::$instance_service = self::get_client_object();
		self::$instance_drive = self::get_drive_object();
	}
	/**
	 * Include Google API Library.
	 *
	 * @since 1.0.0
	 */
	public function wpsslwp_load_library()
	{
		if (!class_exists('ComposerAutoloaderInita672e4231f706419bd66ef535c4ab40e')) {
			require_once WPSSLWP_DIR . 'lib/vendor/autoload.php';
		}
	}
	/**
	 * Generate Google Sheet Object.
	 *
	 * @since 1.0.0
	 */
	public function get_client_object()
	{
		if (null === self::$instance_service) {
			$client = self::getClient();
			self::$instance_service = new \Google_Service_Sheets($client);
		}
		return self::$instance_service;
	}
	/**
	 * Regenerate Google Sheet Object.
	 *
	 * @since 1.0.0
	 */
	public function refreshobject()
	{
		self::$instance_service = null;
		self::get_client_object();
	}
	/**
	 * Regenerate Google Drive Object.
	 *
	 * @since 1.0.0
	 */
	public function get_drive_object()
	{
		if (null === self::$instance_drive) {
			$client = self::getClient();
			self::$instance_drive = new \Google_Service_Drive($client);
		}
		return self::$instance_drive;
	}
	/**
	 * Get Google Drive Object.
	 */
	public static function get_object_drive_object()
	{
		self::$instance_drive = null;
	}
	/**
	 * Check Google Credenatials.
	 *
	 * @since 1.0.0
	 */
	public function checkcredenatials()
	{
		$wpsslwp_google_settings_value = self::wpsslwp_option('wpsswp_google_settings');
		$clientid = isset($wpsslwp_google_settings_value[0]) ? $wpsslwp_google_settings_value[0] : '';
		$clientsecert = isset($wpsslwp_google_settings_value[1]) ? $wpsslwp_google_settings_value[1] : '';
		$auth_token = isset($wpsslwp_google_settings_value[2]) ? $wpsslwp_google_settings_value[2] : '';
		if (empty($clientid) || empty($clientsecert) || empty($auth_token)) {
			return false;
		}
		else {
			try {
				if (self::getClient()) {
					return true;
				}
				else {
					return false;
				}
			}
			catch (Exception $e) {
				return false;
			}
		}
	}
	/**
	 * Get meta vlaue.
	 *
	 * @param object $key plugin meta key.
	 * @param string $type boolean value.
	 * @param int    $form_id .
	 */
	public static function wpsslwp_option($key = '', $type = '', $form_id = '')
	{
		$value = '';
		$wpsslwp_old_keys = self::wpsslwp_old_option_keys();
		$wpsslwp_old_post_keys = self::wpsslwp_old_post_option_keys();
		$postmetas = get_post_meta($form_id);
		$wpsslwp_oldmeta_keys = array_keys(self::wpsslwp_old_option_keys());
		if (in_array($key, $wpsslwp_oldmeta_keys, true)) {
			self::wpsslwp_database_update();
		}
		if (array_key_exists($key, $wpsslwp_old_keys)) {
			$value = parent::wpsslwp_option($key, $type);
		}
		if (!empty($form_id) && array_key_exists($key, $wpsslwp_old_post_keys) && isset($postmetas[$key])) {
			$value = get_post_meta($form_id, $key);
		}
		elseif (!empty($form_id) && isset($postmetas[$wpsslwp_old_post_keys[$key]])) {
			$value = get_post_meta($form_id, $wpsslwp_old_post_keys[$key]);
		}
		return $value;
	}
	/**
	 * Update meta value.
	 *
	 * @param object $key plugin meta key.
	 * @param string $value plugin meta value.
	 */
	public static function wpsslwp_update_option($key = '', $value = '')
	{
		$wpsslwp_old_keys = self::wpsslwp_old_option_keys();
		$wpsslwp_oldmeta_keys = array_keys(self::wpsslwp_old_option_keys());
		if (in_array($key, $wpsslwp_oldmeta_keys, true)) {
			self::wpsslwp_database_update();
		}
		$value = parent::wpsslwp_update_option($key, $value);
		return $value;
	}
	/**
	 * Update database.
	 */
	public static function wpsslwp_database_update()
	{
		$wpsslwp_is_updated = self::wpsslwp_option('wpsswp_database_updated');
		$wpsslwp_old_keys = self::wpsslwp_old_option_keys();
		global $wpdb;
		if (!$wpsslwp_is_updated) {
			$table_name = $wpdb->prefix;
			$table_name = $table_name . 'options';
			foreach ($wpsslwp_old_keys as $newkey => $oldkey) {
				// @codingStandardsIgnoreStart
				$sql = $wpdb->prepare("UPDATE `$table_name` SET `option_name`=%s WHERE `option_name`=%s", $newkey, $oldkey); // db call ok.
				$result = $wpdb->get_results($sql);
			// @codingStandardsIgnoreEnd
			}
			self::wpsslwp_update_option('wpsswp_database_updated', 1);
		}
	}
	/**
	 * Return old option keys.
	 *
	 * @return array
	 */
	public static function wpsslwp_old_option_keys()
	{
		return array(
			'wpsswp_google_settings' => 'wpformssheets_google_settings',
			'wpsswp_google_accessToken' => 'wpformssheets_google_accessToken',
			'wpsswp_envato_apikey' => 'wpformssheets_envato_apikey',
		);
	}
	/**
	 * Return old post meta option keys.
	 *
	 * @return array
	 */
	public static function wpsslwp_old_post_option_keys()
	{
		return array(
			'wpsswp_form_settings' => 'form_settings',
			'wpsswp_active_headers' => 'wpformssheets_active_headers',
			'wpsswp_form_version' => 'wpsswp_form_version',
		);
	}
	/**
	 * Generate token for the user and refresh the token if it's expired.
	 *
	 * @param int $flag for getting error code.
	 * @return array
	 */
	public function getClient($flag = 0)
	{
		$this->wpsslwp_load_library();
		$wpsslwp_google_settings_value = self::wpsslwp_option('wpsswp_google_settings');
		$clientid = isset($wpsslwp_google_settings_value[0]) ? $wpsslwp_google_settings_value[0] : '';
		$clientsecert = isset($wpsslwp_google_settings_value[1]) ? $wpsslwp_google_settings_value[1] : '';
		$auth_token = isset($wpsslwp_google_settings_value[2]) ? $wpsslwp_google_settings_value[2] : '';
		$client = new \Google_Client();
		$client->setApplicationName('WPSyncSheets For WPForms');
		$client->setScopes(\Google_Service_Sheets::SPREADSHEETS_READONLY);
		$client->setScopes(\Google_Service_Drive::DRIVE_METADATA_READONLY);
		$client->addScope(\Google_Service_Sheets::SPREADSHEETS);
		$client->setClientId($clientid);
		$client->setClientSecret($clientsecert);
		$client->setRedirectUri(esc_url(admin_url('admin.php?page=wpsyncsheets-for-wpforms')));
		$client->setAccessType('offline');
		$client->setPrompt('consent');

		// Load previously authorized credentials from a database.
		try {
			if (empty($auth_token)) {
				$auth_url = $client->createAuthUrl();
				return $auth_url;
			}
			$wpsslwp_accesstoken = self::wpsslwp_option('wpsswp_google_accessToken');

			if (!empty($wpsslwp_accesstoken)) {
				$accesstoken = json_decode($wpsslwp_accesstoken, true);
			}
			else {
				if (empty($auth_token)) {
					$auth_url = $client->createAuthUrl();
					return $auth_url;
				}
				else {
					$authcode = trim($auth_token);
					// Exchange authorization code for an access token.
					$accesstoken = $client->fetchAccessTokenWithAuthCode($authcode);
					if (!isset($accesstoken['refresh_token']) || empty($accesstoken['refresh_token'])) {
						$accesstoken['refresh_token'] = $client->getRefreshToken();
					}
					// Store the credentials to disk.
					parent::wpsslwp_update_option('wpsswp_google_accessToken', wp_json_encode($accesstoken));
				}
			}
			// Check for invalid token.
			if (is_array($accesstoken) && isset($accesstoken['error']) && !empty($accesstoken['error'])) {
				if ($flag) {
					return $accesstoken['error'];
				}
				return false;
			}
			$client->setAccessToken($accesstoken);

			// Refresh the token if it's expired.
			if ($client->isAccessTokenExpired()) {
				// save refresh token to some variable.				
				$refreshtokensaved = (isset($accesstoken['refresh_token']) && !empty($accesstoken['refresh_token'])) ? $accesstoken['refresh_token'] : $client->getRefreshToken();
				if (Null === $refreshtokensaved || empty($refreshtokensaved)) {
					if ($flag) {
						$m = 'Please revoke the token and generate it again.';
						return $m;
					}
					else {
						return false;
					}
				}
				$newaccesstoken = $client->fetchAccessTokenWithRefreshToken($refreshtokensaved);

				if (is_array($newaccesstoken) && isset($newaccesstoken['error']) && !empty($newaccesstoken['error'])) {
					if ($flag) {
						return $newaccesstoken['error'];
					}
					return false;
				}

				// pass access token to some variable.
				$accesstokenupdated = $client->getAccessToken();
				if (!isset($accesstokenupdated['refresh_token'])) {
					// append refresh token.
					$accesstokenupdated['refresh_token'] = $refreshtokensaved;
				}
				// Set the new access token.
				parent::wpsslwp_update_option('wpsswp_google_accessToken', wp_json_encode($accesstokenupdated));
				$accesstoken = json_decode(wp_json_encode($accesstokenupdated), true);
				$client->setAccessToken($accesstoken);
			}
		}
		catch (Exception $e) {
			if ($flag) {
				return $e->getMessage();
			}
			else {
				return false;
			}
		}
		return $client;
	}
	/**
	 * Fetch Spreadsheet list from Google Drive.
	 *
	 * @param array $sheetarray Spreadsheet array.
	 * @since 1.0.0
	 *
	 * @return array.
	 */
	public function get_spreadsheet_listing($sheetarray = array())
	{
		if (self::checkcredenatials()) {
			self::get_object_drive_object();
			self::loadobject();
		}
		else {
			return $sheetarray;
		}

		$opt_params = array(
			'fields' => 'nextPageToken, files(id, name, mimeType)',
			'q' => "mimeType='application/vnd.google-apps.spreadsheet' and trashed = false",
		);
		$results = self::$instance_drive->files->listFiles($opt_params);
		if (count($results->getFiles()) === 0) {
			$sheetarray['new'] = __('Create New', 'wpsyncsheets-wpforms');
		}
		else {
			foreach ($results->getFiles() as $file) {
				$sheetarray[$file->getId()] = $file->getName();
			}
			$sheetarray['new'] = __('Create New Spreadsheet', 'wpsyncsheets-wpforms');
		}
		return $sheetarray;
	}
	/**
	 * Retrieve the list of sheets from the Google Spreadsheet.
	 *
	 * @param string $spreadsheetid Spreadsheet id.
	 * @since 1.0.0
	 *
	 * @return object.
	 */
	public function get_sheet_listing($spreadsheetid = '')
	{
		self::refreshobject();
		return parent::get_sheets(self::$instance_service, $spreadsheetid);
	}
	/**
	 * Fetch row from Google Sheet.
	 *
	 * @param array $spreadsheetid Spreadsheet ID.
	 * @param array $sheetname Sheet Name.
	 * @since 1.0.0
	 *
	 * @return object.
	 */
	public function get_row_list($spreadsheetid, $sheetname)
	{
		self::refreshobject();
		$param = array();
		$param['spreadsheetid'] = trim($spreadsheetid);
		$param['sheetname'] = trim($sheetname);

		return parent::get_values(self::$instance_service, $param);
	}
	/**
	 * Create sheet array.
	 *
	 * @param object $response_object google sheet object.
	 * @since 1.0.0
	 *
	 * @return array.
	 */
	public function get_sheet_list($response_object)
	{
		$sheets = array();
		foreach ($response_object->getSheets() as $key => $value) {
			$sheets[$value['properties']['title']] = $value['properties']['sheetId'];
		}
		return $sheets;
	}
	/**
	 * Create insertDimension Object.
	 *
	 * @param array $param contains sheetid,startindex,endindex.
	 * @since 1.0.0
	 *
	 * @return object.
	 */
	public function insertdimensionobject($param = array())
	{
		$requests = new \Google_Service_Sheets_Request(
			array(
			'insertDimension' => array(
				'range' => array(
					'sheetId' => $param['sheetid'],
					'dimension' => 'ROWS',
					'startIndex' => $param['startindex'],
					'endIndex' => $param['endindex'],
				),
			),
		)
			);
		$batchupdaterequest = new \Google_Service_Sheets_BatchUpdateSpreadsheetRequest(
			array(
			'requests' => $requests,
		)
			);
		return $batchupdaterequest;
	}
	/**
	 * Create moveDimension Object.
	 *
	 * @param array $param contains sheetid,startindex,endindex,destinationIndex.
	 * @since 1.0.0
	 *
	 * @return object.
	 */
	public function moveDimensionrequests($param = array())
	{
		$requests = new \Google_Service_Sheets_Request(
			array(
			'moveDimension' => array(
				'source' => array(
					'dimension' => 'COLUMNS',
					'sheetId' => $param['sheetid'],
					'startIndex' => $param['startindex'],
					'endIndex' => $param['endindex'],
				),
				'destinationIndex' => $param['destindex'],
			),
		)
			);
		return $requests;
	}
	/**
	 * Create deleteDimension Object.
	 *
	 * @param array $param contains sheetid,startindex,endindex.
	 * @since 1.0.0
	 *
	 * @return object.
	 */
	public function deleteDimensionrequests($param = array())
	{
		$requests = new \Google_Service_Sheets_Request(
			array(
			'deleteDimension' => array(
				'range' => array(
					'sheetId' => $param['sheetid'],
					'dimension' => 'COLUMNS',
					'startIndex' => $param['startindex'],
					'endIndex' => $param['endindex'],
				),
			),
		)
			);
		return $requests;
	}
	/**
	 * Create insertDimension Object.
	 *
	 * @param array $param contains sheetid,startindex,endindex.
	 * @since 1.0.0
	 *
	 * @return object.
	 */
	public function insertdimensionrequests($param = array())
	{
		$requests = new \Google_Service_Sheets_Request(
			array(
			'insertDimension' => array(
				'range' => array(
					'sheetId' => $param['sheetid'],
					'dimension' => 'COLUMNS',
					'startIndex' => $param['startindex'],
					'endIndex' => $param['endindex'],
				),
			),
		)
			);
		return $requests;
	}
	/**
	 * Update batch requests.
	 *
	 * @param array $param contains requests.
	 * @since 1.0.0
	 *
	 * @return object.
	 */
	public function updatebachrequests($param = array())
	{
		$batchupdaterequest = new \Google_Service_Sheets_BatchUpdateSpreadsheetRequest(
			array(
			'requests' => $param['requestarray'],
		)
			);
		$requestobject['spreadsheetid'] = $param['spreadsheetid'];
		$requestobject['requestbody'] = $batchupdaterequest;
		return parent::batchupdate(self::$instance_service, $requestobject);
	}
	/**
	 * Freeze Row Object
	 *
	 * @param int $sheetid Sheet ID.
	 * @param int $wpsslwp_freeze 0 - Unfreeze Row, 1 - Freeze Row.
	 * @since 1.0.0
	 *
	 * @return object.
	 */
	public function freezeobject($sheetid = 0, $wpsslwp_freeze = 0)
	{
		$requestbody = new \Google_Service_Sheets_BatchUpdateSpreadsheetRequest(
			array(
			'requests' => array(
				'updateSheetProperties' => array(
					'properties' => array(
						'sheetId' => $sheetid,
						'gridProperties' => array(
							'frozenRowCount' => $wpsslwp_freeze,
						),
					),
					'fields' => 'gridProperties.frozenRowCount',
				),
			),
		)
			);
		return $requestbody;
	}
	/**
	 * Google_Service_Sheets_Spreadsheet Object
	 *
	 * @param string $spreadsheetname Spreadsheet Name.
	 * @param string $sheetname Sheet Name.
	 * @since 1.0.0
	 *
	 * @return object.
	 */
	public function newspreadsheetobject($spreadsheetname = '', $sheetname = '')
	{
		$requestbody = new \Google_Service_Sheets_Spreadsheet(
			array(
			'properties' => array(
				'title' => $spreadsheetname,
			),
		)
			);
		return $requestbody;
	}
	/**
	 * Create new sheet
	 *
	 * @param string $param .
	 * @since 1.0.0
	 *
	 * @return object.
	 */
	public function newsheetobject($param = array())
	{
		$batchupdaterequest = new \Google_Service_Sheets_BatchUpdateSpreadsheetRequest(
			array(
			'requests' => array(
				'addSheet' => array(
					'properties' => array(
						'title' => $param['sheetname'],
					),
				),
			),
		)
			);
		$param['requestbody'] = $batchupdaterequest;
		return parent::batchupdate(self::$instance_service, $param);
	}
	/**
	 * Delete default sheet
	 *
	 * @param string $param .
	 * @since 1.0.0
	 *
	 * @return object.
	 */
	public function deletesheetobject($param = array())
	{
		$batchupdaterequest = new \Google_Service_Sheets_BatchUpdateSpreadsheetRequest(
			array(
			'requests' => array(
				'deleteSheet' => array(
					'sheetId' => 0,
				),
			),
		)
			);
		$param['requestbody'] = $batchupdaterequest;
		return parent::batchupdate(self::$instance_service, $param);
	}
	/**
	 * Prepare parameter array.
	 *
	 * @param string $spreadsheetid Spreadsheet Name.
	 * @param string $range Sheet Name.
	 * @param array  $requestbody requestbody param.
	 * @param array  $params array.
	 * @since 1.0.0
	 *
	 * @return array.
	 */
	public function setparamater($spreadsheetid = '', $range = '', $requestbody = array(), $params = array())
	{
		$param = array();
		$param['spreadsheetid'] = $spreadsheetid;
		$param['range'] = $range;
		$param['requestbody'] = $requestbody;
		$param['params'] = $params;
		return $param;
	}
	/**
	 * Create Google_Service_Sheets_ValueRange Object.
	 *
	 * @param array $values_data Values Array.
	 * @since 1.0.0
	 *
	 * @return object.
	 */
	public function valuerangeobject($values_data = array())
	{
		$requestbody = new \Google_Service_Sheets_ValueRange(array('values' => $values_data));
		return $requestbody;
	}
	/**
	 * Create Google_Service_Sheets_ClearValuesRequest Object.
	 *
	 * @since 1.0.0
	 *
	 * @return object.
	 */
	public function clearobject()
	{
		$requestbody = new \Google_Service_Sheets_ClearValuesRequest();
		return $requestbody;
	}
	/**
	 * Insert new column, Freeze first row to google spreadsheet.
	 *
	 * @param array $param contains spreadsheetid,requestbody.
	 * @since 1.0.0
	 *
	 * @return object.
	 */
	public function formatsheet($param = array())
	{
		return parent::batchupdate(self::$instance_service, $param);
	}
	/**
	 * Update entry to google sheet.
	 *
	 * @param array $param contains spreadsheetid, range, requestbody, params.
	 * @since 1.0.0
	 *
	 * @return object.
	 */
	public function updateentry($param = array())
	{
		return parent::update_entry(self::$instance_service, $param);
	}
	/**
	 * Append entry to google sheet.
	 *
	 * @param array $param contains spreadsheetid, range, requestbody, params.
	 * @since 1.0.0
	 *
	 * @return object.
	 */
	public function appendentry($param = array())
	{
		return parent::append_entry(self::$instance_service, $param);
	}
	/**
	 * Create new spreadsheet in Google Drive.
	 *
	 * @param array $requestbody requestbody object.
	 * @since 1.0.0
	 *
	 * @return object.
	 */
	public function createspreadsheet($requestbody = array())
	{
		return parent::create_spreadsheet(self::$instance_service, $requestbody);
	}
	/**
	 * Clear Sheet Value.
	 *
	 * @param array $param spreadsheetid,sheetname,requestbody.
	 * @since 1.0.0
	 *
	 * @return object.
	 */
	public function clear($param = array())
	{
		return parent::clearsheet(self::$instance_service, $param);
	}
	/**
	 * Prepare parameter array.
	 *
	 * @param int $sheetid Sheet ID.
	 * @param int $startindex Start Index.
	 * @param int $endindex End Index.
	 * @since 1.0.0
	 *
	 * @return array.
	 */
	public function prepare_param($sheetid, $startindex, $endindex)
	{
		$param = array();
		$param['sheetid'] = $sheetid;
		$param['startindex'] = $startindex;
		$param['endindex'] = $endindex;
		return $param;
	}
}
