<?php
class WatchDogController extends AppBackendController {

	public $components = array('Api');

# ~ Handles the api	 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
	public function endpoint($id = null) {

		# Get the request
		$method = strtoupper($this->request->method());

		switch($method) {
			case GET:
				return $this->getList();
		}

		$this->reply(array('error' => 'Not found'), 404);
	}


# ~ Show the list of available tests - - - - - - - - - - - - - - - - - - - - - #
	public function index() {

		# Get the environments
		$environment = ClassRegistry::init('WatchDog.Environment')->get();
		$this->set('environment', $environment);

		# Add actions
		$this->addAction('flash primary',	__('WatchDog home'),	'#Home', array('ng-click' => 'showDetails(null)', 'class' => 'btn btn-default'));
		$this->addAction('align-left',		__('Edit HTTP header'),	'#EditHeader', array('class' => 'btn btn-default nxdialog-trigger'));
		$this->addAction('code',			__('Edit environment'),	'#EditEnvironment', array('class' => 'btn btn-default nxdialog-trigger'));

		# Get enum options
		$httpMethods = ClassRegistry::init('WatchDog.APIFunction')->getEnumOptions('http_method');
		$encTypes = ClassRegistry::init('WatchDog.APIFunction')->getEnumOptions('enc_type');
		$this->set(compact('httpMethods', 'encTypes'));

		# Set crumbs
		$this->crumbs = array(
			array(
				__('Tools'),
				array(
					C => 'tools',
					A => 'phpinfo')),
			__('API')
		);

		$this->render('../index');
	}

# ~ Edit the API specification - - - - - - - - - - - - - - - - - - - - - - - - #
	public function modify() {
		$this->prepareTheData();
		$this->render('../modify');
	}

# ~ Executes the function and return the results - - - - - - - - - - - - - - - #
	public function execute() {
		$this->layout = null;
		$headers = array();

		# Extract the URL and salt
		$url = $this->request->data['TestApiFunction']['url'];

		//$salt = $this->request->data['salt'];
		$salt = substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 15);

		//unset($this->request->data['TestApiFunction']['url'], $salt);
		$post = $this->request->data;

		# Get the IP
		$ip = '127.0.0.1';

		# Calculate token
		$token = '';
		foreach($this->request->data['TestApiFunction'] as $key => $value) {
			$token .= $value;
		}
		$post['token'] = md5($token . $salt . $ip);

		# Prepare data for read
		foreach($post as $postKey => $postValue) {
			if(is_array($postValue)) {
				foreach($postValue as $postKeyItem => $postValueItem) {
					if(!is_array($postValueItem)) {
						$readPost[$postKeyItem] = $postValueItem;
					} else {

						# Build headers for read
						foreach($postValueItem as $key => $value) {
							if($key != 'enctype' && !empty($value['name'])) {
								$headers[] = array(
									'name' => $value['name'],
									'value' => $value['value']
								);
							}
						}
					}
				}
			} else if($postKey !== 'fields') {
				$readPost[$postKey] = $postValue;
			}
		}

		# Execute
		//$response = $this->read(FULL_BASE_URL . $url, $readPost, $headers);
		$response = $this->read(FULL_BASE_URL . $url, $readPost);

		$this->set(compact('url', 'salt', 'ip', 'post', 'response'));
	}

# ~ Read the data from remote using CURL - - - - - - - - - - - - - - - - - - - #
	protected function read($url = null, $post = null, $header = array()) {

		# Choose cookie name
		$request = $_SERVER;
		unset($request['REQUEST_TIME']);

		# Initialize curl
		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)");

		# Debug
		if(false) {
			curl_setopt($ch, CURLOPT_VERBOSE, true);
			$verbose = fopen('php://temp', 'rw+');
			curl_setopt($ch, CURLOPT_STDERR, $verbose);
		}

		# Post
		if($post) {

			# Post from array
			if(is_array($post)) {
				//$post = urldecode(http_build_query($post));
				$post = $post['body'];
			}

			curl_setopt($ch, CURLOPT_POST, true);
			curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
		}

		# HTTP header
		if($header) {

			# Referer
			if(!empty($header['Referer'])) {
				curl_setopt($ch, CURLOPT_REFERER, $header['Referer']);
				unset($header['Referer']);
			}

			# Headers from array
			$head = array();
			foreach($header as $key => $value) {
				//$head[] = "{$key}: {$value}";
				$head[] = "{$value['name']}: {$value['value']}";
			}

			curl_setopt($ch, CURLOPT_HEADER, true);
			curl_setopt($ch, CURLOPT_HTTPHEADER, $head);
		}

		# Execute
		$data = curl_exec($ch);
		if($data === false) {
			curl_close($ch);
			exit(1);
		}
		$info = curl_getinfo($ch);
		curl_close($ch);

		return $data;
	}

# ~ Save headers  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
	public function save_headers() {

		# If there is data to save
		if(!empty($this->request->data)) {
			$data = $this->request->data['headers'];

			ClassRegistry::init('TestApiHeader')->deleteAll(array('1 = 1'));

			foreach($data as $header) {
				$headerData = explode('-', $header);

				$save = array(
					'name' => $headerData[0],
					'value' => !empty($headerData[1]) ? $headerData[1] : null
				);
				ClassRegistry::init('TestApiHeader')->save($save);
				ClassRegistry::init('TestApiHeader')->clear();
			}

			echo json_encode(true);
		}

		die;
	}

# ~ Get headers - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
	public function get_headers() {
		$data = ClassRegistry::init('TestApiHeader')->find('all', array());

		$headers = array();
		if(!empty($data)) {
			foreach($data as $header) {
				$headers[] = array(
					'name' => $header['TestApiHeader']['name'],
					'value' => $header['TestApiHeader']['value']
				);
			}
		}
		echo json_encode(array('objects' => $headers));

		die;
	}

# ~ Save environment  - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
	public function save_env($id = null) {
		$this->TestApiEnvironment = ClassRegistry::init('TestApiEnvironment');

		# If there is data to save
		if(!empty($this->request->data)) {
			$data = $this->request->data['envdata'];
			$envsData = array();

			# Pack data for environment table
			if($id > 0) {
				$env_data = array(
					'id' => $id,
					'name' => $data[0]
				);
			} else {
				$env_data = array(
					'name' => $data[0]
				);
			}

			# Save Environment title
			$this->TestApiEnvironment->save($env_data);
			$this->TestApiEnvironment->clear();

			# Get id of saved environment
			$envId = $id > 0 ? $id : $this->TestApiEnvironment->getLastInsertId();

			if($id > 0) {
				ClassRegistry::init('TestApiEnvironmentDatas')->deleteAll(array(
					'TestApiEnvironmentDatas.test_api_environment_id' => $id
				), true);
			}

			# Save environment data
			foreach($data[1] as $env) {
				$envData = explode('-', $env);

				$save = array(
					'test_api_environment_id' => $envId,
					'name' => $envData[0],
					'value' => !empty($envData[1]) ? $envData[1] : null
				);
				ClassRegistry::init('TestApiEnvironmentDatas')->save($save);
				ClassRegistry::init('TestApiEnvironmentDatas')->clear();
			}

			echo json_encode(array(
				'response' => true,
				'envId' => $envId
			));
		}

		die;
	}

# ~ Get environments  - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
	public function get_envs($id = null) {
		$envItems = array();
		$envs = array();

		ClassRegistry::init('TestApiEnvironmentData')->clearCache();

		if(!empty($id)) {
			$data = ClassRegistry::init('TestApiEnvironmentData')->find('all', array(
				'conditions' => array(
					'TestApiEnvironmentData.test_api_environment_id' => $id)
			));

			if(!empty($data)) {
				foreach($data as $envData) {
					$envItems[] = array(
						'id' => $envData['TestApiEnvironmentData']['id'],
						'env_id' => $envData['TestApiEnvironmentData']['test_api_environment_id'],
						'name' => $envData['TestApiEnvironmentData']['name'],
						'value' => $envData['TestApiEnvironmentData']['value']
					);
				}
			}

			$envs = array(
				'id' => $data[0]['TestApiEnvironment']['id'],
				'name' => $data[0]['TestApiEnvironment']['name'],
				'items' => $envItems
			);

		} else {
			$data = ClassRegistry::init('TestApiEnvironment')->find('all', array());

			if(!empty($data)) {
				foreach($data as $env) {
					$envs[] = array(
						'id' => $env['TestApiEnvironment']['id'],
						'name' => $env['TestApiEnvironment']['name'],
						'items' => $envItems
					);
				}
			}
		}

		echo json_encode(array('objects' => $envs));

		die;
	}


# ~ Get environments  - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
	public function delete_env() {

		# If there is data to delete
		if(!empty($this->request->data)) {
			$envId = $this->request->data['envId'];

			$deleted = (bool)ClassRegistry::init('TestApiEnvironment')->delete($envId);

			if($deleted) {
				ClassRegistry::init('TestApiEnvironmentDatas')->deleteAll(array(
					'TestApiEnvironmentDatas.test_api_environment_id' => $envId
				), true);
			}

			echo json_encode($deleted);
		}

		die;
	}

# ~ Save groups - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
	public function save_group($id = null) {
		$this->TestApiFunctionGroup = ClassRegistry::init('TestApiFunctionGroup');

		# If there is data to save
		if(!empty($this->request->data)) {
			$data = $this->request->data['groupdata'];
			$groupsIds = array();

			# Save group data
			foreach($data as $group) {
				$groupData = explode('-', $group);

				# Check is it add or edit
				if($groupData[0] > 0) {
					$save = array(
						'id' => $groupData[0],
						'name' => $groupData[1],
						//'ordering' => !empty($groupData[2]) ? $groupData[2] : null
					);
				} else {
					$save = array(
						'name' => $groupData[1],
						//'ordering' => !empty($groupData[2]) ? $groupData[2] : null
					);
				}

				$this->TestApiFunctionGroup->save($save);
				$this->TestApiFunctionGroup->clear();

				# Get id of saved environment
				$groupsData[] = array(
					'id' => $groupData[0] > 0 ? $groupData[0] : $this->TestApiFunctionGroup->getLastInsertId(),
					'name' => $groupData[1]
				);
			}

			echo json_encode(array(
				'response' => true,
				'groupsData' => $groupsData
			));
		}

		die;
	}

# ~ Get groups	- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
	public function get_groups($id = null) {
		$groups = array();
		$this->TestApiFunctionGroup = ClassRegistry::init('TestApiFunctionGroup');

		$this->TestApiFunctionGroup->clearCache();

		if(!empty($id)) {
			$data = $this->TestApiFunctionGroup->find('first', array(
				'conditions' => array(
					'TestApiFunctionGroup.id' => $id),
				'order' => 'TestApiFunctionGroup.ordering ASC'
			));

			if(!empty($data)) {
				$groupData[] = array(
					'id' => $data['TestApiFunctionGroup']['id'],
					'name' => $data['TestApiFunctionGroup']['name'],
					'ordering' => $data['TestApiFunctionGroup']['ordering']
				);
			}

		} else {
			$data = $this->TestApiFunctionGroup->find('all', array());

			if(!empty($data)) {
				foreach($data as $group) {
					$groupData[] = array(
						'id' => $group['TestApiFunctionGroup']['id'],
						'name' => $group['TestApiFunctionGroup']['name'],
						'ordering' => $group['TestApiFunctionGroup']['ordering']
					);
				}
			}
		}

		echo json_encode(array('groups' => $groupData));

		die;
	}

# ~ Delete group  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
	public function delete_group() {

		# If there is data to delete
		if(!empty($this->request->data)) {
			$groupId = $this->request->data['groupId'];

			$deleted = (bool)ClassRegistry::init('TestApiFunctionGroup')->delete($groupId);

			echo json_encode($deleted);
		}

		die;
	}

# ~ Save api function - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
	public function save_api_function() {
		$this->TestApiFunction = ClassRegistry::init('TestApiFunction');

		if(!empty($this->request->data)) {
			$data = $this->request->data['fnData'];

			$url = '';
			$body = array();
			$encTypeData = explode('&', $data[end(array_keys($data))]['encTypeData']);
			foreach($encTypeData as $encTypeData) {
				$encT = explode('=', $encTypeData);
				$body = array_merge($body, array($encT[0] => $encT[1]));
			}

			# Prepare data
			if(!empty($data[0]['id'])) {
				$save = array(
					'id' => $data[0]['id'],
					'test_api_function_group_id' => $data[1]['groupId'],
					'name' => $data[2]['name'],
					'url' => $data[3]['url'],
					'http_type' => $data[4]['httpType'],
					'enc_type' => $data[5]['encType'],
					'body' => null,
				);
			} else {
				$save = array(
					'test_api_function_group_id' => $data[1]['groupId'],
					'name' => $data[2]['name'],
					'url' => $data[3]['url'],
					'http_type' => $data[4]['httpType'],
					'enc_type' => $data[5]['encType'],
					'body' => null,
				);
			}

			$save['body'] = !empty($url) ? $url : http_build_query($body);

			# Save data
			$response = (bool)$this->TestApiFunction->save($save);

			echo json_encode(array(
				'response' => $response,
				'fnId' => !empty($data[0]['id']) ? $data[0]['id'] : $this->TestApiFunction->getLastInsertId()
			));

		}

		die;
	}

# ~ Get api function  - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
	public function get_api_function() {
		$this->TestApiFunction = ClassRegistry::init('TestApiFunction');
		$encTypeField = $this->TestApiFunction->schema('enc_type');

		$encTypeField['form-data'] = 0;
		$encTypeField['x-www-form-urlencoded'] = 0;
		$encTypeField['raw'] = 1;

		if(!empty($this->request->data)) {
			$fnId = $this->request->data['fnId'];

			$this->TestApiFunction->clearCache();
			$data = $this->TestApiFunction->find('first', array(
				'conditions' => array(
					'TestApiFunction.id' => $fnId)
			));

			$bodyArray = array();

			# Parse raw data for first two enc types
			parse_str($data['TestApiFunction']['body'], $bodyArray);

			//debug($bodyArray); die;

			$fnData = array(
				'id' => $data['TestApiFunction']['id'],
				'group_id' => $data['TestApiFunction']['test_api_function_group_id'],
				'name' => $data['TestApiFunction']['name'],
				'url' => $data['TestApiFunction']['url'],
				'http_type' => $data['TestApiFunction']['http_type'],
				'enc_type' => $data['TestApiFunction']['enc_type'],
				'enc_type_id' => $encTypeField[$data['TestApiFunction']['enc_type']],
				'body' => !empty($bodyArray) ?	array_reverse($bodyArray) : $data['TestApiFunction']['body'],
				'raw_body' => $data['TestApiFunction']['body']
			);


			echo json_encode(array($fnData));
		}

		die;
	}

# ~ Reorder function at sidebar - - - - - - - - - - - - - - - - - - - - - - - #
	public function function_reorder() {

		# Validate input
		if(!empty($this->request->data['id']) && !empty($this->request->data['ordering'])) {
			$this->Model = ClassRegistry::init($this->request->data['model']);

			# Prepare data
			if($this->request->data['model'] == 'TestApiFunctionGroup') {
				$save = array(
					'id' => $this->request->data['id'],
					'test_api_function_group_id' => $this->request->data['group_id'],
					'ordering' => $this->request->data['ordering']
				);
			} else {
				$save = array(
					'id' => $this->request->data['id'],
					'ordering' => $this->request->data['ordering']
				);
			}

			# Update the database
			$this->Model->save($save);

			# Get the new ordering
			$list = $this->Model->find('list', array(
				'fields' => array(
					'id', 'ordering')
			));
			//debug($list); die;

			echo json_encode($list);
		}

		die;
	}


# ~ Define the custom environment custom action for header - - - - - - - - - - #
	private function getEnvironmentCustomAction($config, $environments) {

		# Get the active enviroment
		$name = !empty($config['Environment']['name']) ? __('Enviroment') . ': ' . $config['Environment']['name'] : __('No enviroment');

		# Get the list
		$envs = array();
		if($environments) {
			foreach($environments as $enviroment) {
				$envs[] = '<li><a href="javascript:setEnviroment(' . $enviroment['id'] . ')">' . $enviroment['name'] . '</a></li>';
			}
		} else {
			$envs[] = '<li><a href="#" class="btnNewEnvironment">' . __('There are no defined enviroments') . '</a></li>';
		}

		# Define the button
		return '
			<div class="btn-group">
				<button class="btn btn-default btnEnvironments">
					<i class="fa fa-fw fa-code button"></i>
					{{selectedEnvironment.name}}
				</button>

				<button class="btn btn-default dropdown-toggle" data-toggle="dropdown">
					<span class="caret"></span>
				</button>

				<ul role="menu" class="dropdown-menu">
					<li ng-repeat="environment in data.environments">
						<a ng-click="setEnvironment(environment)" href="#">{{environment.name}}</a>
					</li>

					<li class="divider"></li>

					<li>
						<a ng-click="addEnvironment()" href="#"><i class="fa fa-fw fa-plus"></i>' . __('Add new environment') . '</a>
					</li>
				</ul>
			</div>';
	}

	private function getList() {

		# Get the list form the database
		$list = ClassRegistry::init('WatchDog.Function')->find('all');
		foreach($list as $i => $item) {
			$list[$i] = reset($item);
		}

		# Send the response
		$this->reply($list);
	}

	private function reply($data, $code = null) {
		$this->Api->build($code, $data, false);
	}

}
