<?php
/**
 * @package dsn
 */ 

require_once 'common/collection/TokenMap.php';

/**
 * Dsn class.
 * 
 * This class is a holder and transformer for Dsn objects. It can transform 
 * Dsn objects to and from strings. 
 * Full string representation is as follows:
 * <code>scheme://user:password@host:port/folder/file?query#fragment</code>
 * The Dsn's internal structure is composed by: <ul>
 * <li>scheme: protocol or type of source to use</li>
 * <li>user: user for connection and access</li>
 * <li>password: for specified user</li>
 * <li>host: host specification as IP or name</li>
 * <li>port: port to connect to, if differs from default</li>
 * <li>folder: folder where should look for</li>
 * <li>file: the searched item</li>
 * <li>query: key value pairs to pass</li>
 * <li>fragment: subpart to look inside</li>
 * </ul>
 * And, internally, some other parts will be created:<ul>
 * <li>path: / <em>folder</em> / <em>file</em></li>
 * <li>queryVars: map of key-value <em>query</em> vars</li>
 * <li>folders: list of <em>folder</em></li>
 * </ul>
 * Some examples of possible schemas are: http(s), ftp(s), file, mail, pop, 
 * imap, exec, mysql, oci8, odbc, ...
 * Note that you will need the proper handlers for the schemes (protocols) that 
 * you choose to use.
 * 
 * @todo analyze support for "envelopes", as: ssl://user:passowrd(http://...)
 * 
 * @author  $Author: pruna $
 * @package dsn
 * @version $Revision: 1.3 $
 * @created 26-Apr-2006
 * @modified $Date: 2005/12/06 02:56:45 $
 */
class Dsn extends TokenMap {
    
    /**
     * This const is the string generated from an empty DSN
     * You should treat it as an error.
     */
    const EMPTY_STR = ':///';
    
	/**
	 * Joins $obj elements and returns it as an string.
	 * 
	 * @access	protected
	 * @param   HashMap    $obj     Object to recompose to string
	 * @return	string
	 */
	protected function arr2str($obj) {
	    // scheme
	    $str = $obj->getScheme().'://';
	    // user and pass
	    if ($obj->getUser()) {
	        $str .= $obj->getUser();
    	    if ($obj->getPass()) {
    	        $str .= ':' . $obj->getPass();
    	    }
    	    $str .= '@';
	    }
	    // host
	    $str .= $obj->getHost();
	    // port
	    if ($obj->getPort()) {
	        $str .= ':' . $obj->getPort();
	    }
	    $str .= '/';
	    // folder
	    if ($obj->getFolder()) {
	        $str .= $obj->getFolder() . '/';
	    }
	    // file
	    $str .= $obj->getFile();
	    // query
	    if ($obj->getQuery()) {
	        $str .= '?' . $obj->getQuery();
	    }
	    // fragment
	    if ($obj->getFragment()) {
	        $str .= '#' . $obj->getFragment();
	    }
	    return $str;
	}
	
    /**
     * Returns a Collection with required keys and default values.
     * 
     * @access	protected
     * @return	Collection
     */
    protected function getDefaultValues() {
        return array(
            'scheme'    => '',
            'user'      => '',
            'pass'      => '',
            'host'      => '',
            'port'      => 0,
            'folder'    => '',
            'file'      => '',
            'query'     => '',
            'fragment'  => '',
            // extra parts:
            'path'      => '',
            'queryVars' => array(),
            'folders' => array(),
        );
    }
    
	/**
	 * Splits $str elements and returns it in $obj.
	 * 
	 * @access	protected
	 * @param   string     $str     String to decompose to HashMap
	 * @param   HashMap    $obj     HashMap to modify
	 * @return	string
	 */
	protected function str2arr($str, $obj) {
	    $arr = parse_url($str);
	    $separatorPos = strrpos($arr['path'], '/');
	    if ($separatorPos === FALSE) {
	        $arr['file'] = $arr['path'];
	        $arr['folder'] = '';
	    } elseif ($separatorPos === 0) {
	        $arr['file'] = substr($arr['path'], 1);
	        $arr['folder'] = '';
	    } else {
	        $arr['file'] = substr($arr['path'], $separatorPos + 1);
    	    $arr['folder'] = substr($arr['path'], 1, $separatorPos - 1);
	    }
        if ($arr['folder'] === '') {
            // change default, from array with 1 empty element, to empty array
            $arr['folders'] = array();
        } else {
            $arr['folders'] = explode('/', $arr['folder']);
        }
	    @parse_str($arr['query'], $arr['queryVars']);
        if ($arr['file'] === FALSE) {
            // change default, from boolean FALSE, to empty string
            $arr['file'] ='';
        }
	    $obj->putAll($arr);
	    return $obj;
	}
	
}

?>
