<?php
/**
 * OpenSQLManager
 *
 * Free Database manager for Open Source Databases
 *
 * @package		OpenSQLManager
 * @author 		Timothy J. Warren
 * @copyright	Copyright (c) 2012
 * @link 		https://github.com/aviat4ion/OpenSQLManager
 * @license 	https://timshomepage.net/dbaj.txt
 */

// --------------------------------------------------------------------------

namespace OpenSQLManager;

/**
 * Widget for adding / Editing Connections
 *
 * @package OpenSQLManager
 * @subpackage Widgets
 */
class Connection_Manager extends \wxFrame {

	const TXT_CONN_NAME = 1;
	const COMBO_DB_TYPE = 2;
	const FILE_DB_FILE = 3;
	const TXT_DB_NAME = 4;
	const TXT_DB_HOST = 5;
	const TXT_DB_PORT = 6;
	const TXT_DB_USER = 7;
	const TXT_DB_PASS = 8;
	const BTN_TEST = 9;
	const BTN_ADD = 10;

	/**
	 * Array of fields for Connection Information manipulation
	 *
	 * @var array
	 */
	protected $fields = array();

	/**
	 * Array of labels for Connection Information manipulation
	 *
	 * @var array
	 */
	protected $labels = array();
	
	/**
	 * Reference to the parent Control
	 *
	 * @var object
	 */
	protected $parent;

	/**
	 * Create the window
	 *
	 * @param wxWindow
	 * @param mixed
	 */
	public function __construct($parent, $params = array())
	{
		$this->parent =& $parent;
		parent::__construct($parent, 32, "Connection Manager", wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX | wxSTAY_ON_TOP | wxRESIZE_BORDER);

		// Save a reference to the settings class
		$this->settings =& Settings::get_instance();

		// Layout the window
		$this->_layout($params);
	}

	// --------------------------------------------------------------------------

	/**
	 * Layout fields on the form
	 *
	 * @param array
	 */
	protected function _layout($params)
	{
		$container_sizer = new \wxBoxSizer(wxVERTICAL);

		// Use a table-like sizer
		$sizer = new \wxFlexGridSizer(2, 5, 5);
		$sizer->SetHGap(5);
		$sizer->SetVGap(5);
		$sizer->SetFlexibleDirection(wxBOTH);
		$sizer->AddGrowableCol(0, 1);
		$sizer->AddGrowableCol(1, 1);

		$db_types = $this->get_available_dbs();

		if ($db_types === FALSE)
		{
			error("No valid databases set up in PHP");
			return;
		}

		// Create the controls
		// label => control
		$this->fields = array(
			'Connection Name' => new \wxTextCtrl($this, self::TXT_CONN_NAME),
			'Database Type' => $choice = new \wxChoice(),
			'Database File' => new \wxFilePickerCtrl($this, self::FILE_DB_FILE, wxEmptyString, "Select the database file", '*.*'),
			'Database Name' => new \wxTextCtrl($this, self::TXT_DB_NAME),
			'Host' => new \wxTextCtrl($this, self::TXT_DB_HOST),
			'Port' => new \wxTextCtrl($this, self::TXT_DB_PORT),
			'User' => new \wxTextCtrl($this, self::TXT_DB_USER),
			'Password' => new \wxTextCtrl($this, self::TXT_DB_PASS)
		);

		$choice->Create($this, self::COMBO_DB_TYPE, wxDefaultPosition, wxDefaultSize, $db_types);

		// Enable hiding/showing of controls based on choice
		$choice->Connect(wxEVT_COMMAND_CHOICE_SELECTED, array($this, 'change_db'));

		// Add the controls to the sizer
		$i = 1;
		foreach ($this->fields as $lbl => $ctrl)
		{
			// Add the label to the labels array for later manipulation
			$this->labels[$lbl] = new \wxStaticText($this, $i, $lbl);

			$sizer->Add($this->labels[$lbl], 0, wxALIGN_LEFT);
			$sizer->Add($ctrl, 1, wxALIGN_RIGHT|wxEXPAND);

			$i++;
		}

		// Test Connection Button
		$test_button = new \wxButton($this, self::BTN_TEST, 'Test Connection');
		$test_button->Connect(wxEVT_COMMAND_BUTTON_CLICKED, array($this, 'test_conn'));

		// Add Connection Button
		$add_button = new \wxButton($this, self::BTN_ADD, 'Add Connection');
		$add_button->Connect(wxEVT_COMMAND_BUTTON_CLICKED, array($this, 'add_conn'));

		// Add the buttons to the sizer
		$sizer->Add($test_button, 1, wxEXPAND);
		$sizer->Add($add_button, 1, wxEXPAND);

		// Add the sizer to the window
		// Add it inside of another sizer for padding.
		$container_sizer->Add($sizer, 1, wxALL|wxEXPAND, 10);
		$this->SetSizer($container_sizer);
		$this->Layout();

		// Autosize the window to fit the controls
		$this->Fit();
		$this->CenterOnScreen(wxBOTH);
	}

	// --------------------------------------------------------------------------

	/**
	 * Get the list of available database types
	 *
	 * return array
	 */
	protected function get_available_dbs()
	{
		$drivers = array("");

		$pdo_drivers = \pdo_drivers();

		// Add PDO drivers
		foreach ($pdo_drivers as $d)
		{
			// Skip sqlite2 as opposed to sqlite3
			if ($d === 'sqlite2' && (in_array('sqlite', $pdo_drivers) || in_array('sqlite3', $pdo_drivers)))
			{
				continue;
			}

			// Use the ibase_functions over PDO::Firebird
			if ($d === 'firebird')
			{
				continue;
			}

			// Replace default capitalization with something that looks better.
			$d = str_replace("sql", "SQL", $d);
			$d = str_ireplace("pg", "Postgre", $d);
			$d = str_ireplace("odbc", "ODBC", $d);
			$d = ucfirst($d);

			$drivers[] = $d;
		}

		// Add firebird support, if exists
		if (function_exists('fbird_connect'))
		{
			$drivers[] = "Firebird";
		}

		sort($drivers);

		return $drivers;
	}

	// --------------------------------------------------------------------------

	/**
	 * Adds a connection to the connection manager
	 *
	 * @param wxCommandEvent
	 * @return void
	 */
	public function add_conn($event)
	{
		$params = $this->_get_vals();

		if (empty($params->name))
		{
			error("You need a name for the connection");
			return;
		}

		$this->settings->add_db($params->name, $params);
		
		$this->parent->Update();
		
		$this->Destroy();
	}

	// --------------------------------------------------------------------------

	/**
	 * Set defaults for new database type
	 *
	 * @param wxCommandEvent
	 * @return void
	 */
	public function change_db($event)
	{
		$db = strtolower($event->GetString());
		$sizer = $this->GetSizer();

		$fields =& $this->fields;

		// Set defaults
		$this->_show(array(
			'Host',
			'Database Name',
			'Port',
			'User',
			'Password'
		));
		$this->_hide(array('Database File'));

		$fields['User']->SetValue('');
		$fields['Port']->SetValue('');
		$fields['Password']->SetValue('');
		$fields['Database Name']->SetValue('');
		$fields['Host']->SetValue('127.0.0.1');

		// Set db-specific defaults
		switch($db)
		{
			case "mysql":
				$fields['User']->SetValue('root');
				$fields['Port']->SetValue('3306');
			break;

			case "postgresql":
				$fields['User']->SetValue('postgres');
				$fields['Port']->SetValue('5432');
			break;

			case "firebird":
				$fields['User']->SetValue('sysdba');
				$fields['Password']->SetValue('masterkey');
				$fields['Port']->SetValue('');
				$this->_show(array('Database File'));
				$this->_hide(array(
					'Database Name',
					'Port'
				));
			break;

			case "sqlite":
				$this->_show(array('Database File'));

				$this->_hide(array(
					'Database Name',
					'Port',
					'Host',
					'User',
					'Password'
				));
			break;
		}

		// Resize the window to fit the controls
		$sizer->Fit($this);
	}

	// --------------------------------------------------------------------------

	/**
	 * Test a db connection, and display a popup with the result
	 *
	 * @return void
	 */
	public function test_conn()
	{
		// Get the connection parameters
		$params = $this->_get_vals();

		// Smart aleck error for smart aleck behavior
		if (empty($params->type))
		{
			error("You need to select the correct database type");
			return;
		}

		// Catch connection exceptions, and
		// display the error message to the
		// user so they can edit the db
		// parameters
		try
		{
			\Query($params);
		}
		catch (\Exception $e)
		{
			error("Error connecting to database: \n\n" . $e->getMessage());
			return;
		}

		// Successful Connection?
		// Tell the user!
		alert("Successfully Connected.");
	}

	// --------------------------------------------------------------------------

	/**
	 * Get the values of the widgets in the window
	 *
	 * @return object
	 */
	private function _get_vals()
	{
		$params = new \stdClass();
		$fields =& $this->fields;

		$types = $this->get_available_dbs();
		$type_id = $fields['Database Type']->GetSelection();
		$type = (isset($types[$type_id]))
                    ? $types[$type_id]
                    : "";

		$params->name = $fields['Connection Name']->GetValue();
		$params->type = $type;
		$params->file = $fields['Database File']->GetPath();
		$params->conn_db = $fields['Database Name']->GetValue();
		$params->host = $fields['Host']->GetValue();
		$params->port = $fields['Port']->GetValue();
		$params->user = $fields['User']->GetValue();
		$params->pass = $fields['Password']->GetValue();

		return $params;
	}

	// --------------------------------------------------------------------------

	/**
	 * Hides a list of elements
	 *
	 * @param array
	 */
	private function _hide($ctrls)
	{
		$f =& $this->fields;
		$l =& $this->labels;

		foreach($ctrls as $c)
		{
			$f[$c]->Hide();
			$l[$c]->Hide();
		}
	}

	// --------------------------------------------------------------------------

	/**
	 * Shows a list of elements
	 *
	 * @param array
	 */
	private function _show($ctrls)
	{
		$f =& $this->fields;
		$l =& $this->labels;

		foreach($ctrls as $c)
		{
			$f[$c]->Show();
			$l[$c]->Show();
		}
	}
}

// End of connection_manager.php