<?php
/**
 * version data handler for the deployment tool
 *
 * @author hahn
 */
class versions {
    //put your code here

    public $sProject = false;
    public $sPhase = false;
    public $sPlace = false;
    public $sVariable = false;
    public $sData = false;

    /**
     * filename of sqlite database file
     * @var type 
     */
    private $_dbfile = false;
    
    /**
     * create statement for the database
     * @var type 
     */
    private $_sCreate = '
        CREATE TABLE "versions" (
          `id` INTEGER PRIMARY KEY  AUTOINCREMENT  NOT NULL  UNIQUE ,
          `time` DATETIME,
          `project` TEXT,
          `phase` TEXT,
          `place` TEXT,
          `host` TEXT,
          `variable` TEXT,
          `data` TEXT,
          UNIQUE (project, phase, place, host, variable) ON CONFLICT REPLACE
        );'
    ;
    
    // ----------------------------------------------------------------------
    // CONSTRUCTOR
    // ----------------------------------------------------------------------
    
    /**
     * constructor ... no params
     */
    public function __construct(){
        
        // cache dir is hardcoded to versions directory :-/
        $this->_dbfile = __DIR__ . '/../data/versioncache.db';
        
        if (!file_exists($this->_dbfile)) {
            $this->_createDb();
        }
    }
    
    // ----------------------------------------------------------------------
    // PRIVATE 
    // ----------------------------------------------------------------------

    /**
     * create sqlite database - called in constructor if the file does not exist
     */
    private function _createDb() {
        if (file_exists($this->_dbfile)) {
            echo "removing existing file $this->_dbfile ...<br>\n";
            unlink($this->_dbfile);
        }
        echo "create database as file $this->_dbfile ...<br>\n";
        $this->_makeQuery($this->_sCreate);
        if (!file_exists($this->_dbfile)) {
            die("ERROR: unable to create sqlite database " . $this->_dbfile);
        }
        return true;
    }

    /**
     * execute a sql statement
     * @param string $sSql   sql statement
     * @param array  $aVars  array with values (uses PDO::prepare(); $sSql must contain placeholders :key)
     * @return database object
     */
    private function _makeQuery($sSql, $aVars=false) {
        // $this->_log(__FUNCTION__."($sSql)");
        // echo "DEBUG: executing SQL<pre>$sSql</pre>";
        $oDb = new PDO("sqlite:" . $this->_dbfile);
        if ($aVars && is_array($aVars)){
            $sth = $oDb->prepare($sSql);
            $result = $sth->execute($aVars);
        } else {
            $result = $oDb->query($sSql);
        }
        return $result;
    }
    
    /**
     * execute a sql statement
     * @param string $sSql sql statement
     * @return database object
     */
    private function _makeSelectQuery($sSql, $aKey=false) {
        // $this->_log(__FUNCTION__."($sSql)");
        // echo "DEBUG: executing select SQL<pre>$sSql</pre>";
        $oDb = new PDO("sqlite:" . $this->_dbfile);
        $oStatement = $oDb->prepare($sSql);
        $oStatement->execute();
        $aReturn=array();
        while ($row = $oStatement->fetch(PDO::FETCH_ASSOC)) {
          if ($aKey && array_key_exists($aKey, $row)){
            $aReturn[] = $row[$aKey];
          } else {
            $aReturn[] = $row;
          }
        }        
        return $aReturn;
    }


    // ----------------------------------------------------------------------
    // PUBLIC GETTER
    // ----------------------------------------------------------------------
    
    
    /**
     * get list of current projects
     * @return type
     */
    public function getProjects(){
        $sSql="select distinct(project) from `versions`";
        return $this->_makeSelectQuery($sSql, 'project');
    }
    
    /**
     * get phases of the current project; a project must be set be set before
     * @return type
     */
    public function getPhases(){
        if (!$this->sProject){
            die("ERROR: you need to set a project first. Use the setProject() method to do so.");
        }
        $sSql="select distinct(phase) from `versions`
            WHERE
                project='" . $this->sProject . "'
            "
            ;
        return $this->_makeSelectQuery($sSql,'phase');
    }
    
    /**
     * get places of the current project; a project and must be set be set before
     * @return type
     */
    public function getPlaces(){
        if (!$this->sProject || !$this->sPhase){
            die("ERROR: you need to set a project, and phase first. Use the setProject() method to do so.");
        }
        $sSql="select distinct(place) from `versions`
            WHERE
                project='" . $this->sProject . "'
                AND phase='" . $this->sPhase . "'
                ";
        return $this->_makeSelectQuery($sSql, 'place');
    }
    
    /**
     * get hosts that have installed a project
     * @return type
     */
    public function getHosts(){
        if (!$this->sProject || !$this->sPhase){
            die("ERROR: you need to set a project, and phase first. Use the setProject() method to do so.");
        }
        $sSql="select distinct(host) from `versions`
            WHERE
                project='" . $this->sProject . "'
                AND phase='" . $this->sPhase . "'
                AND place='deployed'
                ";
        return $this->_makeSelectQuery($sSql, 'host');
    }
    
    /**
     * get versions of the current place (project, phase and place must be
     * set before)
     * @see setProject()
     * @return type
     */
    public function getVersion(){
        if (!$this->sProject || !$this->sPhase || !$this->sPlace ){
            die("ERROR: you need to set a project, phase and place first. Use the setProject() method to do so.");
        }
        $sSql="select data from `versions`
            WHERE
                project='" . $this->sProject . "'
                AND phase='" . $this->sPhase . "'
                AND place='" . $this->sPlace . "'
                AND host='" . $this->sHost . "'
                AND variable='version'
                ";
        return $this->_makeSelectQuery($sSql, 'data');
    }
    
    /**
     * return currebntly set project, phase, place and host
     * @return type
     */
    public function whereiam(){
        return array(
            'project'=>$this->sProject,
            'phase'=>$this->sPhase,
            'place'=>$this->sPlace,
            'host'=>$this->sHost,
        );
    }
    /**
     * return currebntly set project, phase, place and host
     * @return type
     */
    public function dumpdb(){
        $sSql="select * from `versions`";
        return $this->_makeSelectQuery($sSql);
    }
    
    
    // ----------------------------------------------------------------------
    // PUBLIC SETTER
    // ----------------------------------------------------------------------
    
    public function setProject($sProject, $sPhase=false, $sPlace=false, $sHost=false){
        $this->sProject=$sProject;
        $this->setPhase($sPhase, $sPlace, $sHost);
        return $this->sProject;
    }
    
    public function setPhase($sPhase, $sPlace=false, $sHost=false){
        if (!$this->sProject){
            die("ERROR: you need to set a project. Use the setProject() method to do so.");
            return false;
        }
        $this->sPhase=$sPhase;
        $this->setPlace($sPlace, $sHost);
        return $this->sPhase;
    }

    public function setPlace($sPlace, $sHost=false){
        if (!$this->sProject || !$this->sPhase){
            die("ERROR: you need to set a project and phase. Use the setProject() method to do so.");
            return false;
        }
        if($sPlace!=='onhold' && $sPlace!=='ready2install' && $sPlace!=='deployed'){
            die("ERROR: you set a wrong place [$sPlace]");
        }
        $this->sPlace=$sPlace;
        $this->setHost($sHost);
        return $this->sPlace;
    }
    
    public function setHost($sHost=false){
        if (!$this->sProject || !$this->sPhase || !$this->sPlace){
            die("ERROR: you need to set a project, phase and place. Use the setProject() method to do so.");
            return false;
        }
        if($sHost && $this->sPlace!=='deployed'){
            die("ERROR: a host can be set on place [deployed] only.");
        }
        if(!$sHost && $this->sPlace==='deployed'){
            die("ERROR: on place [deployed] a host MUST be set.");
        }
        $this->sHost=$sHost;
        return $this->sHost;
    }
    
    /**
     * update a version
     * @return boolean
     */
    public function updateVar($sVarname,$sValue){
        if (!$this->sProject || !$this->sPhase || !$this->sPlace ){
            die("ERROR: you need to set a project, phase and place. use the setProject() method to do so.");
        }
        $sSql="
        INSERT into `versions` 
        (`time`, `project`, `phase`, `place`, `host`, `variable`, `data` )
        VALUES
        (
            '" . date("Y-m-d H:i:s") . "',
            '" . $this->sProject . "',
            '" . $this->sPhase . "',
            '" . $this->sPlace . "',
            '" . $this->sHost . "',
            :variable,
            :value
        );
        ";
        return $this->_makeQuery(
                $sSql,
                array(
                    'variable'=>$sVarname,
                    'value'=>$sValue,
                )
        );
    }
    /**
     * update a version
     * @return boolean
     */
    public function updateVersion($sVersioninfos){
        return $this->updateVar('version', $sVersioninfos);
    }
    
}
