<?php
/**
 * YANA library
 *
 * @package yana
 * @licence http://creativecommons.org/licenses/by-nc-sa/2.5/
 *
 * @ignore
 */

/**
 * SessionManager
 *
 * @access      public
 * @package     yana
 * @subpackage  core
 *
 * @ignore
 */
class SessionManager extends SerializeableObject
{

    /**#@+
     * @ignore
     * @access  private
     */

    /** @var mixed */  var $database     = null;
    /** @var mixed */  var $default_user = array('TYPE' => 0, 'ACTIVE' => true);

    /**#@-*/

    /**
     * constructor
     *
     */
    function SessionManager()
    {
        global $YANA;
        $this->database = $YANA->connect('user');
     }

    /**
     * checkLogin
     *
     * @access public
     * @param string $user_name
     * @param string $user_pwd
     * @return boolean 
     */ 
    function checkLogin($user_name,$user_pwd)
    {
        settype($user_name, "string");
        settype($user_pwd, "string");
        $user_name = strtoupper($user_name);

        if (!$this->database->exists("USER.$user_name")) {
            return false;
        }

        $current_pwd = sessionManager::_encode($user_name,$user_pwd);
        $saved_pwd   = $this->database->get("USER.$user_name.PASSWORT");

        if ($saved_pwd === "UNINITIALIZED") {
            return true;
        } else if ($current_pwd === $saved_pwd) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * isLoggedIn
     *
     * @access public
     * @return boolean
     */
    function isLoggedIn()
    {
        if (empty($_SESSION['prog_id']) || $_SESSION['prog_id'] != YANA_INSTANCE_ID || !isset($_SESSION['user_pwd']) || !isset($_SESSION['user_name'])) {
            return false;
        } else {
            $haben = sessionManager::_createKey2($_SESSION['user_pwd']);
            $soll  = $this->database->get("USER.".$_SESSION['user_name'].".PASSWORT");
            if ($soll == "UNINITIALIZED") {
                return true;
            } else {
                return $haben == $soll;
            }
        }
    }

    /**
     * login
     *
     * @access public
     * @param string $user_name
     * @param string $user_pwd
     * @return boolean
     */ 
    function login($user_name,$user_pwd)
    {
        settype($user_name, "string");
        settype($user_pwd, "string");
        $user_name = strtoupper($user_name);

        if ($this->checkLogin($user_name,$user_pwd)) {
            $user_pwd              = sessionManager::_createKey1($user_name,$user_pwd);
            $_SESSION["user_name"] = $user_name;
            $_SESSION["user_pwd"]  = $user_pwd;
            $_SESSION["prog_id"]   = YANA_INSTANCE_ID;
            return true;
        } else {
            return false;
        } /* end if */
    }
    
    /**
     * logout
     *
     * @access public
     * @return boolean
     */ 
    function logout()
    {
        /* make session cookie expire ( get's deleted) */
        if (isset($_COOKIE[@session_name()])) {
            setcookie(session_name(), '', time()-42000, '/');
        }  
        /* kill session */
        @session_destroy();
        /* start empty session */
        @session_start();
        return true;
    }

    /**
     * changePwd
     *
     * @access public
     * @param string $user_name
     * @param string $user_pwd
     * @return boolean
     */ 
    function changePwd($user_name,$user_pwd)
    {
        assert('is_string($user_name);');
        settype($user_name, "string");
        settype($user_pwd, "string");
        $user_name = strtoupper($user_name);

        if ($this->isLoggedIn()) {
            $this->database->insert("USER.$user_name.PASSWORT", sessionManager::_encode($user_name,$user_pwd));
            return $this->database->write();
        } else {
            return false;
        } /* end if */
    }

    /**
     * setPwd
     *
     * @access public
     * @param string $user_name
     * @return boolean
     */ 
    function setPwd($user_name)
    {
        assert('is_string($user_name);');
        settype($user_name, "string");
        $user_name = strtoupper($user_name);

        if (!$this->userExists($user_name)) {
            return false;
        }

        $user_pwd = sessionManager::generatePassword();

        /* Password may be set when user is either online or new */
        if ($this->isLoggedIn() || $this->database->get("USER.$user_name.PASSWORT") == "UNINITIALIZED") {
            $this->database->insert("USER.$user_name.PASSWORT", sessionManager::_encode($user_name,$user_pwd));
            if (!$this->database->write()) {
                return false;
            } else {
                return $user_pwd;
            }
        } else {
            return false;
        } /* end if */
    }

    /**
     * insertUser
     *
     * @access public
     * @param string $user_name
     * @param array $user_data
     * @return boolean
     */ 
    function insertUser($user_name,$user_data)
    {
        assert('is_string($user_name);');
        assert('is_array($user_data);');
        settype($user_name, "string");
        settype($user_data, "array");

        if ($this->database->insert("user.$user_name",$user_data) && $this->database->write()) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * removeUser
     *
     * @access public
     * @param string $user_name
     * @return boolean
     */ 
    function removeUser($user_name)
    {
        assert('is_string($user_name);');
        settype($user_name, "string");
        $user_name = strtoupper($user_name);

        if (!empty($user_name)) {
            $this->database->remove("USER.$user_name");
            return $this->database->write();
        } else {
            return false;
        }
    }

    /**
     * getUserPermission
     *
     * @access public
     * @param string $user_name
     * @param string $id (optional)
     * @return int
     */ 
    function getUserPermission($user_name, $id = "")
    {
        assert('is_string($user_name);');
        assert('is_string($id);');
        settype($user_name, "string");
        settype($id, "string");
        $user_name = strtoupper($user_name);
        $id = strtoupper($id);
        
        /* return 0 if no user name provided */
        if (empty($user_name)) {
            return 0;
        }
                                    
        /* get user activity state */
        if ($this->database->exists("USER.$user_name.ACTIVE")) {
            $active = $this->database->get("USER.$user_name.ACTIVE");
        } else if (isset($this->default_user['ACTIVE'])) {
            $active = $this->default_user['ACTIVE'];
        } else {
            $active = 0;
        }

        /* return 0 if user is inactive */
        if (empty($active)) {
            return 0;
        }

        /* get current mode */
        global $YANA;
        if (isset($YANA)) {
            $mode = $YANA->getMode();
            settype($mode, 'integer');
        } else {
            $mode = 0;
        }

        /* get user permission level */
        if ($id != '') {
            $permission = $this->database->get("USER.$user_name.PERMISSION.$id");
        } else {
            $permission = null;
        }

        if ($this->database->exists("USER.$user_name.TYPE")) {
            $type = $this->database->get("USER.$user_name.TYPE");
        } else if (isset($this->default_user["TYPE"])) {
            $type = $this->default_user["TYPE"];
        } else {
            $type = null;
        }

        if ($mode === 0 && $permission != false) {
            $perm = $permission;
        } elseif (!is_null($type)) {
            $perm = $type;
        } elseif (isset($this->default_user["TYPE"])) {
            $perm = $this->value["DEFAULT"]["TYPE"];
        }

        if (!is_int($perm) && !empty($perm)) {
            if ($this->database->exists("GROUP.$perm.VALUE")) {
                $perm = $this->database->get("GROUP.$perm.VALUE");
                settype($perm, "integer");
                return $perm;
            } else {
                trigger_error("Unable to get permission level for user '".$user_name."'. The provided user group '".$perm."' does not exist.");
                return 0;
            }
        } else {
            if (empty($perm)) {
                return 0;
            } else {
                return $perm;
            }
        }
    }

    /**
     * isEmpty
     *
     * @access public
     * @return boolean 
     */ 
    function isEmpty()
    {
        return $this->database->isEmpty('user');
    }

    /**
     * getUserList
     *
     * @access public
     * @return array
     */ 
    function getUserList()
    {
        $i = 0;
        $REF = array();
        $source = $this->getUser();

        foreach ($source as $a => $b)
        {
            $REF[$i]['USER'] = $this->_formatUserData($a, $b, false);
            $i++;
        }  
        return $REF;
    }

    /**
     * getUserGroups
     *
     * @access public
     * @return array
     */ 
    function getUserGroups()
    {
        $i = 0; $REF = array();
        $SOURCE = $this->database->get("GROUP");
        settype($SOURCE, "array");

        foreach ($SOURCE as $a => $b)
        {
            $REF[$i]['GROUP']['ID']    = $a;
            $REF[$i]['GROUP']['NAME']  = $b['NAME'];
            $REF[$i]['GROUP']['VALUE'] = $b['VALUE'];
            $i++;
        }
        return $REF;
    }
    
    /**
     * getUser
     *
     * @access public
     * @param string $user_name (optional)
     * @return array
     */ 
    function getUser($user_name = '*')
    {
        assert('is_string($user_name);');        
        settype($user_name, "string");
        $user_name = strtoupper($user_name);
                                         
        if (empty($user_name) || $user_name == '*' ) {
            return $this->database->get("USER");
        } else {
            $REF = $this->database->get("USER.$user_name");
            return $this->_formatUserData($user_name, $REF, true);
        }
    }

    /**
     * userExists
     *
     * @access public
     * @param string $user_name
     * @return boolean
     */ 
    function userExists($user_name)
    {
        assert('empty($user_name) || is_string($user_name);');
        settype($user_name, "string");
        $user_name = strtoupper($user_name);
        return $this->database->exists("USER.$user_name");
    }

    /**
     * generatePassword
     *
     * creates a random password string of length 10
     *
     * @access public
     * @static
     * @return string
     */ 
    function generatePassword()
    {
        return substr(md5(uniqid(rand(), true)),0,10);
    }

    /**
     * encode
     *
     * @access private
     * @static
     * @param string $a
     * @param string $b
     * @return string
     * @ignore
     */ 
    function _encode($a, $b)
    {
        settype($a, "string");
        settype($b, "string");
        return sessionManager::_createKey2(sessionManager::_createKey1($a,$b));
    }

    /**
     * _createKey1
     *
     * @access private
     * @static
     * @param string $a
     * @param string $b
     * @return string
     * @ignore
     */ 
    function _createKey1($a, $b)
    {
        settype($a, "string");
        settype($b, "string");
        $a = substr(strtoupper($a),0,2);
        return md5($a.$b);
    }
    
    /**
     * _createKey2
     *
     * @access private
     * @static
     * @param string $a
     * @return string
     * @ignore
     */ 
    function _createKey2($a)
    {
        settype($a, "string");
        return md5($a);
    }

    /**
     * _formatUserData
     *
     * @access private
     * @param string $user_name
     * @param array $user_data
     * @param boolean $i
     * @return array
     * @ignore
     */
    function _formatUserData(/* String */ $name, /* Hashtable */ $data, /* boolean */ $i)
    {
        settype($name, "string");
        settype($data, "array");
        $name = strtoupper($name);

        unset($data['PASSWORT']);
        unset($data['PASSWORD']);
        $REF     = $data;
        unset($REF['PERMISSION']);
        unset($REF['TYPE']);

        $REF['ID'] = $name;

        if (!isset($data['TYPE'])) {
            $REF['TYPE']['NAME']  = "";
            $REF['TYPE']['VALUE'] = 0;
        } else if (is_numeric($data['TYPE'])) {
            $REF['TYPE']['NAME']  = $data['TYPE'];
            $REF['TYPE']['VALUE'] = $data['TYPE'];
        } else {
            $REF['TYPE']['NAME']  = $this->database->get("GROUP.".$data['TYPE'].".NAME");
            $REF['TYPE']['VALUE'] = $data['TYPE'];
        }
        settype($data['PERMISSION'], "array");
        foreach ($data['PERMISSION'] as $c => $d)
        {
            $c = strtoupper($c);
            if (is_numeric($d)) {
                if ($i) {
                  $REF['PERMISSION'][$c]['ID']    = $c;
                  $REF['PERMISSION'][$c]['VALUE'] = $d;
                  $REF['PERMISSION'][$c]['NAME']  = $d;
                } else {
                  $REF['PERMISSION']    .= "$c = $d<br>\n";
                }
            } else {
                if ($i) {
                  $REF['PERMISSION'][$c]['ID']    = $c;
                  $REF['PERMISSION'][$c]['VALUE'] = $this->database->get("GROUP.$d.NAME");
                  $REF['PERMISSION'][$c]['NAME']  = $d;
                } else {
                  if (!isset($REF['PERMISSION'])) $REF['PERMISSION'] = "";
                  $REF['PERMISSION']    .= "$c = ".$this->database->get("GROUP.$d.NAME")."<br>\n";
                }
            }
        }
        
        return $REF;
    }

}

?>