<?php
/**
 * Инструменты для Google Drive.
 *
 * Получает реквизиты доступа к Google SpreadSheets.
 * Получает данные из указанной таблицы Google SpreadSheets.
 * Записывает идентификаторы, ярылики и статус загрузки в таблицу Google.
 *
 *
 *
 * @author veselka.ua
 * @version 0.4
 *
 * @package veselka_ua/themes
 */

class GdriveTools {


	/**
	 * Регистр.
	 * @type array
	 */
	private $registry = [];
	/**
	 * Идентификаторы столбцов.
	 * @type array
	 */
	private $fields;
	/**
	 * Данные таблицы.
	 * @type array
	 */
	private $data;
	/**
	 * Время выполнения.
	 * @type array
	 */
	private $time;
	/**
	 * Массив сообщений.
	 * @type array
	 */
	private $msg;
	/**
	 * Реквизиты подключения.
	 * @type object
	 */
	private $g;


	public function __construct() {
		echo PHP_EOL . ' ^_^ GDrive object start.' . PHP_EOL;
		$this->time = microtime(true);
	}


	public function __destruct() {
		echo PHP_EOL . ' ^_^ GDrive object erase...' . PHP_EOL . PHP_EOL;
		// Вермя выполнения 
		echo ' /\/\｡[ᴼᴼᴼᴼ\^/ᴼᴼᴼᴼ]｡/\/\ Script execution time: '.(microtime(true) - $this->time).' s.' . PHP_EOL;
	}


//////////////////// Публичные методы ////////////////////


	/**
	 * Обертка для загрузки.
	 *
	 * @param string $option
	 * @param string $sheet_title
	 * @return void
	 */
	final public function load_gdrive( $option='', $sheet_title=false ) {
		// Наименование параметра в базе WP
		$this->registry['opion_name'] = $option;
		// Заголовок листа
		$this->registry['sheet_title'] = $sheet_title;
		// Развертывание
		$this->load();
	}


	/**
	 * Обертка для записи заголовков таблицы.
	 *
	 * @param array $headers
	 * @return array
	 */
	final public function set_sheet_headers($headers) {
		$this->write_sheet_headers($headers);
	}


	/**
	 * Возвращает статус текущего листа (новый/не новый).
	 *
	 * @param void
	 * @return bool
	 */
	final public function is_new_sheet() {
		return $this->registry['new_sheet'];
	}


	/**
	 * Обертка для получения ключа.
	 *
	 * @param void
	 * @return array
	 */
	final public function get_file_fields() {
		return $this->fields;
	}


	/**
	 * Обертка для получения строки данных.
	 *
	 * @param void
	 * @return array
	 */
	final public function get_file_data() {
		return each($this->data);
	}


	/**
	 * Обертка для записи определенной строки в массив.
	 *
	 * @param int $row
	 * @param array $data
	 * @return void
	 */
	final public function set_file_data($row, $data) {
		$this->data[$row] = $data;
	}


	/**
	 * Обертка для добавления строки в массив.
	 *
	 * @param int $row
	 * @param array $data
	 * @return void
	 */
	final public function add_row_data($data) {
		$data = array_values($data);
		array_unshift($this->data, $data);
	}


	/**
	 * Обертка для записи файла.
	 *
	 * @param void
	 * @return void
	 */
	final public function write_file_data() {
		$this->write_data();
	}


//////////////////// Приватные методы ////////////////////


	/**
	 * Развертывание.
	 *
	 * @param void
	 * @return void
	 */
	private function load() {

		// Получение массива сообщений
		$this->get_msgs();
		// Идентификатор листа (нужен толькоа для изменения оформления)
		$this->registry['sheet_id'] = false;
		// Флаг экспорта
		$this->registry['export'] = false;
		// Получение параметров доступа
		$this->get_access_params();
		// Создание ключа для подключения
		$this->load_google_client();
		// Данные необходимого листа в таблице
		$this->load_worksheet_title();
		// Получение данных
		$this->get_data();
	}


	/**
	 * Получение массива сообщений.
	 *
	 *
	 * @param string $add
	 * @return void
	 */
	protected function get_msgs() {
		/**
		 * Стандартный путь к параметрам.
		 */
		require TEMPLATEPATH . '/conf/gdrive.php';
		// Запись в свойство
		$this->msg = $msg;
	}


	/**
	 * Получение параметров доступа.
	 *
	 * @param void
	 * @return void
	 */
	private function get_access_params() {
		$this->g = new stdClass();
		// Файл авторизации системного аккаунта Google
		$this->g->credentials_path = get_option('drive_credentials');
		if( !$this->g->credentials_path ) {
			throw new \Exception('No option loaded - credentials file for google api' . PHP_EOL . PHP_EOL);
		}
		// Идентификатор таблицы
		$this->g->file_id = get_option( $this->registry['opion_name'].'_id' );
		if( !$this->g->file_id ) {
			throw new \Exception('No option loaded - spreadsheet id' . PHP_EOL . PHP_EOL);
		}

	}


	/**
	 * Создание ключа для подключения.
	 *
	 * @param void
	 * @return void
	 */
	private function load_google_client() {

		$this->g->client = new Google_Client();
		putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $this->g->credentials_path);
		if (getenv('GOOGLE_APPLICATION_CREDENTIALS')) {
			$this->g->client->useApplicationDefaultCredentials();
		} else {
			echo missingServiceAccountDetailsWarning();
			throw new \Exception('No credentials file for google api' . PHP_EOL . PHP_EOL);
		}

		$this->g->client->setApplicationName('Veselka WP import/export data');
		$this->g->client->setScopes(implode(' ', [Google_Service_Sheets::SPREADSHEETS]));
		$this->g->service = new Google_Service_Sheets($this->g->client);
		// Объект отбработки массивов для записи
		//$this->g->value_range = new Google_Service_Sheets_ValueRange();

	}



	/**
	 * Подключние требуемого листа в таблице.
	 *
	 * @param void
	 * @return void
	 */
	private function load_worksheet_title() {
		// Заголовок требуемого листа передан аргументом
		// Экспорт. Требуется создание листа при его отсутствии
		if( $this->registry['sheet_title'] ) {
			$this->registry['export'] = true;
			// Новый лист если его нет
			$this->create_worksheet_title();
			// Загловок листа
			$this->g->worksheet_title = $this->registry['sheet_title'];
		} else {
			// Имя листа из параметров WP
			$this->g->worksheet_title = get_option( $this->registry['opion_name'].'_title' );
			if( !$this->g->worksheet_title ) {
				throw new \Exception('No option loaded - worksheet title' . PHP_EOL . PHP_EOL);
			}
		}
	}


	/**
	 * Создание нового листа в таблице.
	 *
	 * @param void
	 * @return void
	 */
	private function create_worksheet_title() {

		// Поиск листа
		$this->registry['new_sheet'] = true;
		$sheetInfo = $this->g->service->spreadsheets->get($this->g->file_id);
		$id_сats = array_column($sheetInfo['sheets'], 'properties');
		foreach( $id_сats as $element ) {
			if( $element->title == $this->registry['sheet_title'] ) {
				// Лист существует
				$this->registry['new_sheet'] = false;
				$this->registry['sheet_id'] = $element->sheetId;
			}
		}
		// Новый лист если его нет
		if( $this->registry['new_sheet'] ) {
			$sheet = [
				'requests' => [
					'addSheet' => [
						'properties' => [
							'title' => $this->registry['sheet_title'],
						]
					]
				]
			];
			// Цвет листа "Заказы"
			if( $this->registry['sheet_title'] == __('Orders','shop') ) {
				$sheet['requests']['addSheet']['properties']['tabColor'] = [
					'red' => 1.0,
					'green' => 0.3,
					'blue' => 0.4
				];
			}
			// Цвет листа "Подтверждение заказа"
			elseif( $this->registry['sheet_title'] == __('Order confirmation','shop') ) {
				$sheet['requests']['addSheet']['properties']['tabColor'] = [
					'red' => 0.067,
					'green' => 0.33,
					'blue' => 0.8
				];
			}
			// Цвет листа "Противопожарная дверь"
			elseif( $this->registry['sheet_title'] == __('Fire door','shop') ) {
				$sheet['requests']['addSheet']['properties']['tabColor'] = [
					'red' => 1,
					'green' => 0.55,
					'blue' => 0
				];
			}
			// Заголовок нового листа
			$batchUpdateRequest = new Google_Service_Sheets_BatchUpdateSpreadsheetRequest($sheet);
			// Запрос
			$response = $this->g->service->spreadsheets->batchUpdate($this->g->file_id,$batchUpdateRequest);
			echo PHP_EOL . ' ¸.｡.:*･ᴼ`* New sheet are created!' . PHP_EOL;
		}
	}


	/**
	 * Запись заголовков таблицы.
	 *
	 * @param array $headers
	 * @return void
	 */
	private function write_sheet_headers($headers) {

		// Запись заголовков таблицы
		$range = $this->g->worksheet_title . '!A1';
		$data = [];
 		$data[] = new Google_Service_Sheets_ValueRange([
			'range' => $range,
			'values' => $headers,
			'majorDimension' => 'ROWS',
		]);
		$batchUpdateRequest = new Google_Service_Sheets_BatchUpdateValuesRequest([
			'valueInputOption' => 'USER_ENTERED',
			'data' => $data
		]);
		$response = $this->g->service->spreadsheets_values->batchUpdate($this->g->file_id, $batchUpdateRequest);
		echo ' <~~~~~~~~~ New table sheet headers saved.' . $response->updatedRange . PHP_EOL;


		// Есть идентификатор новой таблицы
		$sheetInfo = $this->g->service->spreadsheets->get($this->g->file_id);
		$id_сats = array_column($sheetInfo['sheets'], 'properties');
		foreach( $id_сats as $element ) {
			if( $element->title == $this->registry['sheet_title'] ) {
				// Лист существует
				$this->registry['sheet_id'] = $element->sheetId;
			}
		}

		// Лист существует?
		if( !(bool)$this->registry['sheet_id'] ) {
			return true;
		}

		// Форматирование заголовков
		$requests = [];
		// Меняем заголовок таблицы
		$requests[] = new Google_Service_Sheets_Request([
			'repeatCell' => [
				'range' => [
					'sheetId' => $this->registry['sheet_id'],
					'startRowIndex' => 0,
					'endRowIndex' => 1
				],
				'cell' => [
					'userEnteredFormat' => [
						'horizontalAlignment'  => 'LEFT',
						'textFormat' => [
							'foregroundColor' => [
								'red' => 0.8,
								'green' => 0.8,
								'blue' => 0.8,
							],
							'fontSize' => 10,
						]
					]
				],
				'fields' => 'userEnteredFormat(textFormat)'
			],
		]);
		// Меняем заголовок таблицы
		$requests[] = new Google_Service_Sheets_Request([
			'repeatCell' => [
				'range' => [
					'sheetId' => $this->registry['sheet_id'],
					'startRowIndex' => 1,
					'endRowIndex' => 2
				],
				'cell' => [
					'userEnteredFormat' => [
						'horizontalAlignment'  => 'LEFT',
						'textFormat' => [
							'foregroundColor' => [
								'blue' => 1.0
							],
							'fontSize' => 11,
						]
					]
				],
				'fields' => 'userEnteredFormat(textFormat)'
			],
		]);

		// Меняем границы ячеек
		$requests[] = new Google_Service_Sheets_Request([
			'updateBorders' => [
				'range' => [
					'sheetId' => $this->registry['sheet_id'],
					'startRowIndex' => 1,
					'endRowIndex' => 2
				],
				'bottom' => [
					'style' => 'SOLID',
					'width' => 2,
					'color' => [
						'blue' => 1.0
					],
				],
				'innerHorizontal' => [
					'style' => 'DASHED',
					'width' => 1,
					'color' => [
						'red' => 1.0
					],
				],
			],
		]);

		// Меняем границы ячеек
		$requests[] = new Google_Service_Sheets_Request([
			'updateSheetProperties' => [
				'properties' => [
					'sheetId' => $this->registry['sheet_id'],
					'gridProperties' => [
						'frozenRowCount' => 2
					]
				],
				'fields' => 'gridProperties.frozenRowCount'
			]
		]);

		// Сборка запросов
		$batchUpdateRequest = new Google_Service_Sheets_BatchUpdateSpreadsheetRequest([
			'requests' => $requests
		]);
		
		$response = $this->g->service->spreadsheets->batchUpdate($this->g->file_id,$batchUpdateRequest);
		echo ' ¸.｡.:*･ᴼ`* New sheet are formatted.' . PHP_EOL . PHP_EOL;
	}


	/**
	 * Получение данных таблицы.
	 *
	 * @param void
	 * @return void
	 */
	private function get_data() {
		$range = $this->g->worksheet_title;
		$response = $this->g->service->spreadsheets_values->get($this->g->file_id, $range);
		$data = $response->getValues();

		// Идентификаторы столбцов
		if( !$this->registry['new_sheet'] ) {
			$this->fields = $data[0];
			if( !$this->registry['export'] && !in_array( 'wp_id', $this->fields ) && !in_array( 'term_id', $this->fields ) ) {
				throw new \Exception('Broken import file (no row with ids)' . PHP_EOL . PHP_EOL);
			}
			echo PHP_EOL . ' ~~~~~~~~~> Table headings are received.' . PHP_EOL;
		}

		// Удние заголвков
		unset($data[0]);
		unset($data[1]);
		// Запись в свойство
		$this->data = $data;
		if( !(bool)$this->data ) {
			$this->data = [];
		}
	}


	/**
	 * Запись информации.
	 *
	 * @param void
	 * @return void
	 */
	private function write_data() {

		$this->data = array_values($this->data);

		//sort($this->data);
		// Change string to numeric
		foreach( $this->data as $r_key => $row ) {
			if( empty($row) ) {
				continue;
			}
			foreach( $row as $c_key => $cell ) {
				// Цифры
				if( is_numeric($cell) ) {
					if( ctype_digit($cell) ) {
						$this->data[$r_key][$c_key] = (int)$cell;
					} else {
						$this->data[$r_key][$c_key] = (float)$cell;
					}
				}
				// Булевые значения
				if( $cell == 'TRUE' ) {
					$this->data[$r_key][$c_key] = true;
				}
				if( $cell == 'FALSE' ) {
					$this->data[$r_key][$c_key] = false;
				}
			}
		}
		$range = $this->g->worksheet_title . '!A3';
		$data = [];
 		$data[] = new Google_Service_Sheets_ValueRange([
			'range' => $range,
			'values' => $this->data,
			'majorDimension' => 'ROWS',
		]);

		$batchUpdateRequest = new Google_Service_Sheets_BatchUpdateValuesRequest([
			'valueInputOption' => 'USER_ENTERED',
			'data' => $data
		]);

		$response = $this->g->service->spreadsheets_values->batchUpdate($this->g->file_id, $batchUpdateRequest);
		echo ' <~~~~~~~~~ The data is written to file.' . $response->updatedRange . PHP_EOL;

		// Вычисление идентификатора таблицы если нет
		if( !(bool)$this->registry['sheet_id'] ) {
			$sheetInfo = $this->g->service->spreadsheets->get($this->g->file_id);
			//$id_сats = array_column($sheetInfo['sheets'], 'properties');
			foreach( $sheetInfo['sheets'] as $obj ) {
				if( $obj->properties->title == $this->g->worksheet_title ) {
					// Лист существует
					$this->registry['sheet_id'] = $obj->properties->sheetId;
				}
			}
		}

		// Нет идентификатора - форматирование невозможно
		if( $this->registry['sheet_id'] !== false ) {
			// Автоматическая ширина ячеек
			$this->row_resize();
			// Покраска статусов
			$this->conditions_painting();
		}
	}


	/**
	 * Автоматическая ширина ячеек.
	 *
	 * @param void
	 * @return void
	 */
	private function row_resize() {

		$requests[] = new Google_Service_Sheets_Request([
			'autoResizeDimensions' => [
				'dimensions' => [
					'sheetId' => $this->registry['sheet_id'],
					'dimension' => 'COLUMNS',
					'startIndex' => 0,
					'endIndex' => count($this->data[0]),
				]
			]
		]);

		// Сборка запросов
		$batchUpdateRequest = new Google_Service_Sheets_BatchUpdateSpreadsheetRequest([
			'requests' => $requests
		]);
		
		$response = $this->g->service->spreadsheets->batchUpdate($this->g->file_id,$batchUpdateRequest);
		echo ' ♫•*¨*•.¸¸♪ Automatic table cell width.' . PHP_EOL;

	}


	/**
	 * Покраска построчных статусов выполнения.
	 *
	 * @param void
	 * @return void
	 */
	private function conditions_painting() {

		// Есть колонка со статусами?
		if( is_array($this->fields) || !in_array( 'import_status', $this->fields ) ) {
			echo ' (･_├┬┴┬┴┬┴ No column with statuses!' . PHP_EOL;
			return true;
		}

		// Ключ массива - порядковый номер столбца
		$key = array_search('import_status', $this->fields);
		foreach( $this->data as $r_key => $row ) {
			// Цвет
			$color = ['red' => 0.5,'green' => 0.5,'blue' => 0.5];
			if( strpos($row[$key], $this->msg['ok']) !== false ) {
				if( strpos($row[$key], $this->msg['status_update']) !== false ) {
					$color = ['red' => 0.22,'green' => 0.8,'blue' => 0.114];
				} elseif( strpos($row[$key], $this->msg['status_actual']) !== false ) {
					$color = ['red' => 0.067,'green' => 0.33,'blue' => 0.8];
				}
			} elseif( strpos($row[$key], $this->msg['fail']) !== false ) {
				$color = ['red' => 0.8,'green' => 0.0,'blue' => 0.0];
			}
			// Форматирование статусов
			$requests[] = new Google_Service_Sheets_Request([
				'repeatCell' => [
					'range' => [
						'sheetId' => $this->registry['sheet_id'],
						'startRowIndex' => $r_key + 2,
						'endRowIndex' => $r_key + 3,
						'startColumnIndex' => (int)$key,
						'endColumnIndex' => ((int)$key+1),
					],
					'cell' => [
						'userEnteredFormat' => [
							'horizontalAlignment'  => 'LEFT',
							'textFormat' => [
								'foregroundColor' => $color,
							]
						]
					],
					'fields' => 'userEnteredFormat(textFormat)'
				],
			]);
		}

		// Сборка запросов
		$batchUpdateRequest = new Google_Service_Sheets_BatchUpdateSpreadsheetRequest([
			'requests' => $requests
		]);
		
		$response = $this->g->service->spreadsheets->batchUpdate($this->g->file_id,$batchUpdateRequest);
		echo ' ¸.｡.:*･ᴼ`* Column statuses are formatted!' . PHP_EOL;
	}


} //end GdriveTools
?>