<?php

function __pwneopriv_callbackPushRow($row, &$array)
{
    array_push($array, $row);
}
function __pwneopriv_callbackEchoJsonRow($row, &$dummy)
{
    echo ',';
    echo json_encode($row);
}
function __pwneopriv_callbackEchoCsvRow($row, &$stdout)
{
    fputcsv($stdout, $row, ';');
}

class __PwneoprivDbConn
{
    private $filename;
    private $db;
    private $stmts = array();
    private $transactionStarted;
    private $timeoutMs;

    static public function retrieveColumnNames(SQLite3Result $rs)
    {
        $res = array();
        for ($i=0; $i<$rs->numColumns(); $i++) {
            $res[$i] = $rs->columnName($i);
        }
        return $res;
    }

    /**
     * @return array whose first element is an array column names and remaining
     * elements are arrays of column values.
     * @throws Exception on error; contains the error message an error code.
     */
    static public function createSelectResult(SQLite3Result $rs)
    {
        $res = array(__PwneoprivDbConn::retrieveColumnNames($rs));
        while (1) {
            $row = $rs->fetchArray(SQLITE3_NUM);
            if (!$row) {
                break;
            }
            array_push($res, $row);
        }
        //Reference required to avoid creating new arrays
        return $res;
    }

    /**
     * @return FALSE on error.
     */
    private function initDb()
    {
        $queries = array('PRAGMA foreign_keys=ON','PRAGMA read_uncommitted=OFF');
        return $this->execAllQueries($queries);
    }

    /**
     * @param $mode SQLITE3_OPEN_READWRITE or SQLITE3_OPEN_READONLY.
     * @throws Exception on error; contains the error message an error code.
     */
    public function __construct($filename,$mode,$timeout_ms)
    {
        $this->filename = $filename;
        $this->db = new SQLite3($filename, $mode);
        $this->db->busyTimeout($timeout_ms);
        $this->timeoutMs = $timeout_ms;
        $this->transactionStarted = FALSE;
        //
        if (!$this->initDb()) {
            $errmsg = $this->db->lastErrorMsg();
            $errcode = $this->db->lastErrorCode();
            $this->db->close();
            throw new Exception($errmsg, $errcode);
        }
        /* Prepared statments not used as it's not likely the queries be reused
         $this->stmtSelectMonitorings = $this->prepareStmt('SELECT ...');
        */
    }

    public function __destruct()
    {
        foreach ($this->stmts as $s) {
            $s->close();
        }
        $this->db->close();
    }

    public function getFilename()
    {
        return $this->filename;
    }

    public function getTimeoutMs()
    {
        return $this->timeoutMs;
    }

    /**
     * Statements closed in the destructor.
     * @throws Exception on error; contains the error message an error code.
     */
    public function prepareStmt($query)
    {
        $res = $this->db->prepare($query);
        if (!$res) {
            throw new Exception($this->db->lastErrorMsg().'. Query='.$query,
                $this->db->lastErrorCode());
        }
        array_push($this->stmts, $res);
        return $res;
    }

    /**
     * @return FALSE error on any query.
     */
    public function execAllQueries(array $queries)
    {
        foreach ($queries as $q) {
            if (!$this->db->exec($q)) {
                return FALSE;
            }
        }
        return TRUE;
    }

    public function lastInsertRowID()
    {
        return $this->db->lastInsertRowID();
    }

    /**
     * @see closeTransaction
     * @throws Exception on error; contains the error message an error code.
     */
    public function startTransaction()
    {
        $query = 'BEGIN EXCLUSIVE TRANSACTION';
        if (!$this->db->exec($query)) {
            throw new Exception($this->db->lastErrorMsg(),
                $this->db->lastErrorCode());
        }
        $this->transactionStarted = TRUE;
    }

    /**
     * @throws Exception on error; contains the error message an error code.
     */
    public function closeTransaction($commit)
    {
        if ($commit) {
            $query = 'COMMIT';
        } else {
            $query = 'ROLLBACK';
        }
        if (!$this->db->exec($query)) {
            throw new Exception($this->db->lastErrorMsg(),
                $this->db->lastErrorCode());
        }
        $this->transactionStarted = FALSE;
    }

    public function isTransactionStarted()
    {
        return $this->transactionStarted;
    }

    /**
     * @return an SQLite3Result
     * @throws Exception on error; contains the error message an error code.
     */
    public function query($query)
    {
        $rs = $this->db->query($query);
        if (!$rs) {
            throw new Exception($this->db->lastErrorMsg(),
                $this->db->lastErrorCode());
        }
        return $rs;
    }

    public function lastErrorCode()
    {
        return $this->db->lastErrorCode();
    }

    public function lastErrorMsg()
    {
        return $this->db->lastErrorMsg();
    }
};


class PwneoDb
{
    private $conn; //@see __PwneoprivDbConn
    private $dbTimeoutMs;

    const EVENT_SOURCE_SYSTEM = 'S';
    const EVENT_SOURCE_MONITOR = 'M';
    static $POLARIZATION = array(
        'NONE' => '--',
        'VERTICAL_HIGH' => 'VH',
        'VERTICAL_LOW' => 'VL',
        'HORIZONTAL_HIGH' => 'HH',
        'HORIZONTAL_LOW' => 'HL'
    );
    static $SIGNAL_TYPE_MAGNITUDES = array(
        'DVBT' => array('POWER','C/N','MER','LM','CBER','VBER','LOCKED','F_OFF'),
        'DVBT2' => array('POWER','C/N','MER','LM','CBER','LBER','LOCKED','F_OFF'),
        'DVBC2' => array('POWER','C/N','MER','LM','CBER','LBER','LOCKED','F_OFF'),
        'ISDBT' => array('POWER','C/N','MER','LM','CBER','VBER','LOCKED','F_OFF'),
        'ATSC' => array('POWER','C/N','MER','LM','VBER','SER','LOCKED','F_OFF'),
        'ANALOGTV' => array('LEVEL','C/N','V/A','LOCKED'),
        'DVBC' => array('POWER','C/N','MER','LM','CBER','LOCKED','F_OFF'),
        'DVBS' => array('POWER','C/N','MER','LM','CBER','VBER','LOCKED','F_OFF'),
        'DVBS2' => array('POWER','C/N','MER','LM','CBER','LBER','LOCKED','F_OFF'),
        'DSS' => array('POWER','C/N','MER','LM','CBER','VBER','LOCKED','F_OFF'),
        'FM' => array('LEVEL','LOCKED'),
        'FMA' => array('LEVEL','MPX','MPX Dev','L+R Dev','L-R Dev','L Dev','R Dev','Pilot Dev','RDS Dev','LOCKED','F_OFF','L ALvl','R ALvl','L+R ALvl','L-R ALvl'),
        'OTHER' => array('POWER','LOCKED'),
        'J83ANNEXB' => array('POWER','C/N','MER','LM','CBER','LOCKED','F_OFF'),
        'DAB' => array('POWER','C/N','MER','CBER','LOCKED','F_OFF'),
        'DABA' => array('POWER','C/N','MER','CBER','FIB Ratio','MSC CBER','FIC CBER','LOCKED','F_OFF'),
        'UNKNOWN' => array('POWER','LOCKED'),
        'DABPLUS' => array('POWER','C/N','MER','CBER','LOCKED','F_OFF'),
        'DTMB' => array('POWER','LOCKED','F_OFF'),
        'DVBH' => array('POWER','C/N','MER','LM','CBER','VBER','LOCKED','F_OFF')
    );
    static $NOTIFICATION_TYPES = array(
        'EMAIL'=> 'EMAIL',
        'SMS' => 'SMS');
    public $select_limit = 1000;

    static private function echoJsonHeader(SQLite3Result $rs)
    {
        echo '[[';
        for ($i=0; $i<$rs->numColumns()-1; $i++) {
            echo '"'.$rs->columnName($i).'",';
        }
        echo '"'.$rs->columnName($i).'"]';
    }
    static private function echoJsonTail()
    {
        echo ']';
    }
    /**
     * @param $fmts map of column names to value format functions.
     */
    static private function echoJsonSelectResult(SQLite3Result $rs, $fmts=null)
    {
        PwneoDb::echoJsonHeader($rs);
        $row = $rs->fetchArray(SQLITE3_NUM);
        $fmtsInd = array();
        if ($fmts) {
            for ($i=0; $i<$rs->numColumns(); $i++) {
                $k = $rs->columnName($i);
                if (array_key_exists($k,$fmts)) {
                    $fmtsInd[$i] = $fmts[$k];
                }
            }
        }
        if ($row) {
            while (1) {
                echo ',';
                foreach ($fmtsInd as $k=>$v) {
                    $row[$k] = $v($row[$k]);
                }
                echo json_encode($row);
                $row = $rs->fetchArray(SQLITE3_NUM);
                if (!$row) {
                    break;
                }
            }
        }
        PwneoDb::echoJsonTail($rs);
    }

    static private function echoCsvHeader($stdout, SQLite3Result $rs)
    {
        for ($i=0; $i<$rs->numColumns()-1; $i++) {
            echo '"'.$rs->columnName($i) . '";';
        }
        echo '"' . $rs->columnName($i) . "\"\n";
    }

    static private function echoCsvSelectResult(SQLite3Result $rs)
    {
        $stdout = fopen('php://output', 'w');
        PwneoDb::echoCsvHeader($stdout, $rs);
        //
        $row = $rs->fetchArray(SQLITE3_NUM);
        if ($row) {
            while (1) {
                fputcsv($stdout, $row, ';');
                $row = $rs->fetchArray(SQLITE3_NUM);
                if (!$row) {
                    break;
                }
            }
        }
        //No echoCsvTail
    }

    static private function forEachSelectResult(SQLite3Result $rs, &$callback)
    {
        $r = array();
        for ($i=0; $i<$rs->numColumns(); $i++) {
            $r[$rs->columnName($i)] = null;
        }
        //
        while (1) {
            $row = $rs->fetchArray(SQLITE3_NUM);
            if (!$row) {
                break;
            }
            for ($i=0; $i<$rs->numColumns(); $i++) {
                $r[$rs->columnName($i)] = $row[$i];
            }
            $callback($r);
        }
    }

    /**
     * Does nothing if $this->select_limit has no value or $offset is null.
     */
    private function concatSelectLimit(&$query, $offset)
    {
        if ($this->select_limit && (null!==$offset)) {
            $query .= ' LIMIT ' . $this->select_limit . ' OFFSET ' . $offset;
        }
    }

    /**
     * @param $mode SQLITE3_OPEN_READWRITE or SQLITE3_OPEN_READONLY.
     * @throws Exception on error; contains the error message an error code.
     */
    public function __construct($filename,$mode,$timeout_ms)
    {
        $this->conn = new __PwneoprivDbConn($filename, $mode, $timeout_ms);
    }

    public function __destruct()
    {
    }

    /**
     * @see closeTransaction
     * @throws Exception on error; contains the error message an error code.
     */
    public function startTransaction()
    {
        $this->conn->startTransaction();
    }

    /**
     * @throws Exception on error; contains the error message an error code.
     */
    public function closeTransaction($commit)
    {
        $this->conn->closeTransaction($commit);
    }

    private function queryMonitorings($offset)
    {
        $query = 'SELECT * FROM MONITORINGS';
        $this->concatSelectLimit($query,$offset);
        return $this->conn->query($query);
    }

    /**
     * @param $offset ignored if $this->select_limit is not set.
     * @throws Exception on error; contains the error message an error code.
     * @see __PwneoprivDbConn::createSelectResult
     * @return $res
     */
    public function selectMonitorings($offset)
    {
        $rs = $this->queryMonitorings($offset);
        $res = __PwneoprivDbConn::createSelectResult($rs);
        $rs->finalize();
        return $res;
    }

    /**
     * @param $offset ignored if $this->select_limit is not set.
     * @throws Exception on error; contains the error message an error code.
     */
    public function echoJsonMonitorings($offset)
    {
        $rs = $this->queryMonitorings($offset);
        PwneoDb::echoJsonSelectResult($rs);
        $rs->finalize();
    }

    /**
     * Ignores $this->select_limit.
     * @throws Exception on error; contains the error message an error code.
     */
    public function echoCsvMonitorings()
    {
        $rs = $this->queryMonitorings(null);
        PwneoDb::echoCsvSelectResult($rs);
        $rs->finalize();
    }

    /**
     * For each register in the table executes $callback($row) where $row is a
     * map whose keys are column names and values are column values for the
     * current row.
     * Ignores $this->select_limit.
     * @throws Exception on error; contains the error message an error code.
     */
    public function forEachMonitoring($callback)
    {
        $rs = $this->queryMonitorings(null);
        PwneoDb::forEachSelectResult($rs, $callback);
        $rs->finalize();
    }

    private function queryMonitoringChannels($offset, $monid)
    {
        $query = 'SELECT * FROM CHANNELS WHERE MONID='.$monid;
        $this->concatSelectLimit($query,$offset);
        return $this->conn->query($query);
    }

    /**
     * @param $offset ignored if $this->select_limit is not set.
     * @return select result sorted by frequency.
     * @throws Exception on error; contains the error message an error code.
     * @see __PwneoprivDbConn::createSelectResult
     */
    public function selectMonitoringChannels($offset, $monid)
    {
        $rs = $this->queryMonitoringChannels($offset, $monid);
        $res = __PwneoprivDbConn::createSelectResult($rs);
        $rs->finalize();
        return $res;
    }

    /**
     * Sorts channels by frequency.
     * @param $offset ignored if $this->select_limit is not set.
     * @throws Exception on error; contains the error message an error code.
     */
    public function echoJsonMonitoringChannels($offset, $monid)
    {
        $rs = $this->queryMonitoringChannels($offset, $monid);
        PwneoDb::echoJsonSelectResult($rs);
        $rs->finalize();
    }

    /**
     * Ignores $this->select_limit.
     * @throws Exception on error; contains the error message an error code.
     */
    public function echoCsvMonitoringChannels($monid)
    {
        $rs = $this->queryMonitoringChannels(null, $monid);
        PwneoDb::echoCsvSelectResult($rs);
        $rs->finalize();
    }

    /**
     * For each register in the table executes $callback($row) where $row is a
     * map whose keys are column names and values are column values for the
     * current row.
     * Ignores $this->select_limit.
     * @throws Exception on error; contains the error message an error code.
     */
    public function forEachMonitoringChannel($callback, $monid)
    {
        $rs = $this->queryMonitoringChannels(null, $monid);
        PwneoDb::forEachSelectResult($rs, $callback);
        $rs->finalize();
    }

    private function queryMagnitudeSettings($offset, $monid)
    {
        $query = 'SELECT MAGNITUDE,UNITS FROM MAGNITUDESETTINGS'
            .' WHERE MONID='.$monid;
        $this->concatSelectLimit($query,$offset);
        return $this->conn->query($query);
    }
    /**
     * @param callback prototype is function callback($row, $callbackparam);
     */
    private static function forEachMagnitudeForSignalType($rs, $signaltype, $callback, $callbackparam) {

        if (!array_key_exists($signaltype, PwneoDb::$SIGNAL_TYPE_MAGNITUDES)) {
            return;
        }

        $magnitudes = PwneoDb::$SIGNAL_TYPE_MAGNITUDES[$signaltype];

        while (1) {
            $row = $rs->fetchArray(SQLITE3_NUM);
            if (!$row) {
                break;
            }
            $k = array_search($row[0], $magnitudes);
            if (false !== $k) {
                $callback($row, $callbackparam);
                array_splice($magnitudes, $k, 1);
            }
        }

        foreach ($magnitudes as $m) {
            $row = array($m, NULL);
            $callback($row, $callbackparam);
        }
    }

    /**
     * @param $offset ignored if $this->select_limit is not set.
     * @throws Exception on error; contains the error message an error code.
     * @see __PwneoprivDbConn::createSelectResult
     * @see PwneoDb::$SIGNAL_TYPE_MAGNITUDES
     */
    public function selectMagnitudeSettings($offset, $monid, $signaltype)
    {
        $rs = $this->queryMagnitudeSettings($offset, $monid);
        $res = array(__PwneoprivDbConn::retrieveColumnNames($rs));
        PwneoDb::forEachMagnitudeForSignalType($rs, $signaltype,
            @__pwneopriv_callbackPushRow, $res);
        $rs->finalize();
        //
        return $res;
    }

    /**
     * @param $offset ignored if $this->select_limit is not set.
     * @throws Exception on error; contains the error message an error code.
     * @see PwneoDb::$SIGNAL_TYPE_MAGNITUDES
     */
    public function echoJsonMagnitudeSettings($offset, $monid, $signaltype)
    {
        $dummy=null;
        $rs = $this->queryMagnitudeSettings($offset, $monid);
        PwneoDb::echoJsonHeader($rs);
        PwneoDb::forEachMagnitudeForSignalType($rs, $signaltype,
            @__pwneopriv_callbackEchoJsonRow, $dummy);
        PwneoDb::echoJsonTail();
        $rs->finalize();
    }

    /**
     * Ignores $this->select_limit.
     * @throws Exception on error; contains the error message an error code.
     * @see PwneoDb::$SIGNAL_TYPE_MAGNITUDES
     */
    public function echoCsvMagnitudeSettings($monid, $signaltype)
    {
        $rs = $this->queryMagnitudeSettings(null,$monid);
        $stdout = fopen('php://output', 'w');
        PwneoDb::echoCsvHeader($stdout, $rs);
        PwneoDb::forEachMagnitudeForSignalType($rs, $signaltype,
            @__pwneopriv_callbackEchoCsvRow, $stdout);
        //No echoCsvTail
        $rs->finalize();
    }

    /**
     * For each register in the table executes $callback($row) where $row is a
     * map whose keys are column names and values are column values for the
     * current row.
     * Ignores $this->select_limit.
     * @throws Exception on error; contains the error message an error code.
     * @see PwneoDb::$SIGNAL_TYPE_MAGNITUDES
     */
    public function forEachMagnitudeSetting($callback, $monid, $signaltype)
    {
        $rs = $this->queryMagnitudeSettings(null,$monid);
        PwneoDb::forEachMagnitudeForSignalType($rs, $signaltype,
            $callback, null);
        $rs->finalize();
    }

    static private function queryMeasuresFilter($tstart, $tend, $monid,
                                                $chfreqkhz=NULL, $polarization=NULL, array $magnitudes=NULL)
    {
        $filter = 'TIME BETWEEN '.$tstart.' AND '.$tend
            .' AND MONID='.$monid;
        if (NULL !== $chfreqkhz) {
            $filter .= ' AND CHFREQKHZ='.$chfreqkhz;
        }
        if (NULL !== $polarization) {
            $filter .= ' AND POLARIZATION="'.$polarization.'"';
        }
        if (NULL !== $magnitudes) {
            $filter .= ' AND MAGNITUDE IN("'.implode($magnitudes,'","').'")';
        }
        return $filter;
    }

    /**
     * @param $colNames desired database column names. If UNITS appears in the
     * array, then the MAGNITUDESETTINGS table is joined in query.
     * @see PwneoDb::$POLARIZATION
     * @see PwneoDb::$SIGNAL_TYPE_MAGNITUDES
     */
    private function queryMeasures($colNames, $offset, $tstart, $tend, $monid,
                                   $chfreqkhz=NULL, $polarization=NULL, array $magnitudes=NULL)
    {
        $query = 'SELECT '.implode($colNames,',').' FROM MEASURES';
        if (in_array('UNITS', $colNames)) {
            $query .= ' LEFT JOIN MAGNITUDESETTINGS USING (MONID,MAGNITUDE)';
        }
        $query .= ' WHERE ' . PwneoDb::queryMeasuresFilter($tstart, $tend, $monid,
                $chfreqkhz, $polarization, $magnitudes) . ' ORDER BY TIME';
        $this->concatSelectLimit($query,$offset);
//        echo $query;
        return $this->conn->query($query);
    }

    public function countMeasures($tstart, $tend, $monid,
                                  $chfreqkhz=NULL, $polarization=NULL, array $magnitudes=NULL)
    {
        $query = 'SELECT COUNT(1) FROM MEASURES'
            .' WHERE ' . PwneoDb::queryMeasuresFilter($tstart, $tend, $monid,
                $chfreqkhz, $polarization, $magnitudes);
        $rs = $this->conn->query($query);
        $row = $rs->fetchArray(SQLITE3_NUM);
        if (!$row) {
            $res = 0;
        } else {
            $res = $row[0];
        }
        $rs->finalize();
        return $res;
    }

    /**
     * @param $offset ignored if $this->select_limit is not set.
     * @return select result sorted by time (ascending order).
     * @throws Exception on error; contains the error message an error code.
     * @see __PwneoprivDbConn::createSelectResult
     * @see PwneoDb::$POLARIZATION
     * @see PwneoDb::$SIGNAL_TYPE_MAGNITUDES
     */
    public function selectMeasures($offset, $tstart, $tend, $monid,
                                   $chfreqkhz=NULL, $polarization=NULL, array $magnitudes=NULL)
    {
        $rs = $this->queryMeasures(array('*'), $offset, $tstart, $tend, $monid,
            $chfreqkhz, $polarization, $magnitudes);
        $res = __PwneoprivDbConn::createSelectResult($rs);
        $rs->finalize();
        return $res;
    }

    /**
     * Sorts measures by time (ascending order).
     * @param $offset ignored if $this->select_limit is not set.
     * @throws Exception on error; contains the error message an error code.
     * @see PwneoDb::$POLARIZATION
     * @see PwneoDb::$SIGNAL_TYPE_MAGNITUDES
     */
    public function echoJsonMeasures($offset, $tstart, $tend, $monid,
                                     $chfreqkhz=NULL, $polarization=NULL, array $magnitudes=NULL)
    {
        $rs = $this->queryMeasures(array('*'), $offset, $tstart, $tend, $monid,
            $chfreqkhz, $polarization, $magnitudes);
        PwneoDb::echoJsonSelectResult($rs);
        $rs->finalize();
    }

    /**
     * Sorts measures by time (ascending order).
     * Ignores $this->select_limit.
     * @throws Exception on error; contains the error message an error code.
     * @see PwneoDb::$POLARIZATION
     * @see PwneoDb::$SIGNAL_TYPE_MAGNITUDES
     */
    public function echoCsvMeasures($tstart, $tend, $monid,
                                    $chfreqkhz=NULL, $polarization=NULL, array $magnitudes=NULL)
    {
        $rs = $this->queryMeasures(array('*'), null, $tstart, $tend, $monid,
            $chfreqkhz, $polarization, $magnitudes);
        PwneoDb::echoCsvSelectResult($rs);
        $rs->finalize();
    }

    /**
     * Sorts measures by time (ascending order).
     * Ignores $this->select_limit.
     * Executes $echoFunc for each row passing an array of column values in the
     * same order of $colNames.
     * @param $colNames desired database column names. If UNITS appears in the
     * array, then the MAGNITUDESETTINGS table is joined in query.
     * @param $echoFunc function that echoes a row.
     * @throws Exception on error; contains the error message an error code.
     * @see PwneoDb::$POLARIZATION
     * @see PwneoDb::$SIGNAL_TYPE_MAGNITUDES
     */
    public function echoFormattedMeasures($echoFunc, array $colNames, $tstart,
                                          $tend, $monid, $chfreqkhz=NULL, $polarization=NULL,
                                          array $magnitudes=NULL,$tz="Europe/Madrid")
    {
        $rs = $this->queryMeasures($colNames, null, $tstart, $tend, $monid,
            $chfreqkhz, $polarization, $magnitudes);
        $row = $rs->fetchArray(SQLITE3_NUM);
        if ($row) {
            while (1) {
                $echoFunc($row,$tz);
                $row = $rs->fetchArray(SQLITE3_NUM);
                if (!$row) {
                    break;
                }
            }
        }
        $rs->finalize();
    }

    /**
     * Sorts measures by time (ascending order).
     * For each register in the table executes $callback($row) where $row is a
     * map whose keys are column names and values are column values for the
     * current row.
     * Ignores $this->select_limit.
     * @throws Exception on error; contains the error message an error code.
     * @see PwneoDb::$SIGNAL_TYPE_MAGNITUDES
     * @see PwneoDb::$POLARIZATION
     */
    public function forEachMeasure($callback, $tstart, $tend, $monid,
                                   $chfreqkhz=NULL, $polarization=NULL, array $magnitudes=NULL)
    {
        $rs = $this->queryMeasures(array('*'), null, $tstart, $tend, $monid,
            $chfreqkhz, $polarization, $magnitudes);
        PwneoDb::forEachSelectResult($rs, $callback);
        $rs->finalize();
    }

    private function querySystemEvents($offset, $tstart, $tend,
                                       array $eventtypes=NULL, $intinfo=NULL, $strinfo=NULL)
    {
        $query = 'SELECT * FROM SYSTEMEVENTS'
            .' WHERE TIME BETWEEN '.$tstart.' AND '.$tend;
        if (NULL !== $eventtypes) {
            $query .= ' AND TYPE  IN("'.implode($eventtypes,'","').'")';
        }
        if (NULL !== $intinfo) {
            $query .= ' AND INTINFO='.$intinfo.'';
        }
        if (NULL !== $strinfo) {
            $query .= ' AND STRINFO="'.$strinfo.'"';
        }
        $query .= ' ORDER BY TIME';
        $this->concatSelectLimit($query,$offset);
        return $this->conn->query($query);
    }

    /**
     * @param $offset ignored if $this->select_limit is not set.
     * @return select result sorted by time (ascending order).
     * @throws Exception on error; contains the error message an error code.
     * @see __PwneoprivDbConn::createSelectResult
     */
    public function selectSystemEvents($offset, $tstart, $tend,
                                       array $eventtypes=NULL, $intinfo=NULL, $strinfo=NULL)
    {
        $rs = $this->querySystemEvents($offset, $tstart, $tend, $eventtypes,
            $intinfo, $strinfo);
        $res = __PwneoprivDbConn::createSelectResult($rs);
        $rs->finalize();
        return $res;
    }

    /**
     * Sorts events by time (ascending order).
     * @param $offset ignored if $this->select_limit is not set.
     * @throws Exception on error; contains the error message an error code.
     */
    public function echoJsonSystemEvents($offset, $tstart, $tend,
                                         array $eventtypes=NULL, $intinfo=NULL, $strinfo=NULL)
    {
        $rs = $this->querySystemEvents($offset, $tstart, $tend, $eventtypes,
            $intinfo, $strinfo);
        PwneoDb::echoJsonSelectResult($rs);
        $rs->finalize();
    }

    /**
     * Sorts events by time (ascending order).
     * Ignores $this->select_limit.
     * @throws Exception on error; contains the error message an error code.
     */
    public function echoCsvSystemEvents($tstart, $tend,
                                        array $eventtypes=NULL, $intinfo=NULL, $strinfo=NULL)
    {
        $rs = $this->querySystemEvents(null, $tstart, $tend, $eventtypes,
            $intinfo, $strinfo);
        PwneoDb::echoCsvSelectResult($rs);
        $rs->finalize();
    }

    /**
     * Sorts events by time (ascending order).
     * For each register in the table executes $callback($row) where $row is a
     * map whose keys are column names and values are column values for the
     * current row.
     * Ignores $this->select_limit.
     * @throws Exception on error; contains the error message an error code.
     */
    public function forEachSystemEvent($callback, $tstart, $tend,
                                       array $eventtypes=NULL, $intinfo=NULL, $strinfo=NULL)
    {
        $rs = $this->querySystemEvents(null, $tstart, $tend, $eventtypes,
            $intinfo, $strinfo);
        PwneoDb::forEachSelectResult($rs, $callback);
        $rs->finalize();
    }

    private function queryMonitorEvents($offset, $tstart, $tend, $monid,
                                        $chfreqkhz=NULL, $polarization=NULL, array $magnitudes=NULL,
                                        array $eventtypes=NULL)
    {
        $query = 'SELECT * FROM MONITOREVENTS'
            .' WHERE TIME BETWEEN '.$tstart.' AND '.$tend
            .' AND MONID='.$monid;
        if (NULL !== $chfreqkhz) {
            $query .= ' AND CHFREQKHZ='.$chfreqkhz;
        }
        if (NULL !== $polarization) {
            $query .= ' AND POLARIZATION="'.$polarization.'"';
        }
        if (NULL !== $magnitudes) {
            $query .= ' AND MAGNITUDE IN("'.implode($magnitudes,'","').'")';
        }
        if (NULL !== $eventtypes) {
            $query .= ' AND TYPE IN ("'.implode($eventtypes,'","').'")';
        }
        $query .=' ORDER BY TIME';
        $this->concatSelectLimit($query,$offset);


        return $this->conn->query($query);
    }

    /**
     * @param $offset ignored if $this->select_limit is not set.
     * @return select result sorted by time (ascending order).
     * @throws Exception on error; contains the error message an error code.
     * @see __PwneoprivDbConn::createSelectResult
     * @see PwneoDb::$POLARIZATION
     * @see PwneoDb::$SIGNAL_TYPE_MAGNITUDES
     */
    public function selectMonitorEvents($offset, $tstart, $tend, $monid,
                                        $chfreqkhz=NULL, $polarization=NULL, array $magnitudes=NULL,
                                        array $eventtypes=NULL)
    {
        $rs = $this->queryMonitorEvents($offset, $tstart, $tend, $monid, $chfreqkhz,
            $polarization, $magnitudes, $eventtypes);
        $res = __PwneoprivDbConn::createSelectResult($rs);
        $rs->finalize();
        return $res;
    }

    /**
     * Sorts events by time (ascending order).
     * @param $offset ignored if $this->select_limit is not set.
     * @throws Exception on error; contains the error message an error code.
     * @see PwneoDb::$POLARIZATION
     * @see PwneoDb::$SIGNAL_TYPE_MAGNITUDES
     */
    public function echoJsonMonitorEvents($offset, $tstart, $tend, $monid,
                                          $chfreqkhz=NULL, $polarization=NULL, array $magnitudes=NULL,
                                          array $eventtypes=NULL)
    {
        $rs = $this->queryMonitorEvents($offset, $tstart, $tend, $monid, $chfreqkhz,
            $polarization, $magnitudes, $eventtypes);
        PwneoDb::echoJsonSelectResult($rs);
        $rs->finalize();
    }

    /**
     * Ignores $this->select_limit.
     * Sorts events by time (ascending order).
     * @throws Exception on error; contains the error message an error code.
     * @see PwneoDb::$POLARIZATION
     * @see PwneoDb::$SIGNAL_TYPE_MAGNITUDES
     */
    public function echoCsvMonitorEvents($tstart, $tend, $monid,
                                         $chfreqkhz=NULL, $polarization=NULL, array $magnitudes=NULL,
                                         array $eventtypes=NULL)
    {
        $rs = $this->queryMonitorEvents(null, $tstart, $tend, $monid, $chfreqkhz,
            $polarization, $magnitudes, $eventtypes);
        PwneoDb::echoCsvSelectResult($rs);
        $rs->finalize();
    }

    /**
     * Sorts events by time (ascending order).
     * For each register in the table executes $callback($row) where $row is a
     * map whose keys are column names and values are column values for the
     * current row.
     * Ignores $this->select_limit.
     * @throws Exception on error; contains the error message an error code.
     * @see PwneoDb::$POLARIZATION
     * @see PwneoDb::$SIGNAL_TYPE_MAGNITUDES
     */
    public function forEachMonitorEvent($callback, $tstart, $tend, $monid,
                                        $chfreqkhz=NULL, $polarization=NULL, array $magnitudes=NULL,
                                        array $eventtypes=NULL)
    {
        $rs = $this->queryMonitorEvents(null, $tstart, $tend, $monid, $chfreqkhz,
            $polarization, $magnitudes, $eventtypes);
        PwneoDb::forEachSelectResult($rs, $callback);
        $rs->finalize();
    }

    /**
     * Transaction required.
     * @see __PwneoprivDbConn::createSelectResult
     * @see PwneoDb::$NOTIFICATION_TYPES
     */
    public function insertNotificationDestination($type, $destination, $name)
    {
        $t = SQLite3::escapeString($type);
        $d = SQLite3::escapeString($destination);
        $n = SQLite3::escapeString($name);
        $queries = array(
            'INSERT INTO NOTIFICATIONDESTINATIONS'
            .' (DESTINATIONID,TYPE,DESTINATION,NAME) VALUES'
            .' (-1,"'.$t.'","'.$d.'","'.$n.'")',
            //
            'UPDATE NOTIFICATIONDESTINATIONS SET DESTINATIONID=ROWID'
            .' WHERE DESTINATIONID=-1'
        );
        if (!$this->conn->isTransactionStarted()) {
            throw new Exception('Transaction required', 1);
        }
        if (!$this->conn->execAllQueries($queries)) {
            throw new Exception($this->conn->lastErrorMsg(),
                $this->conn->lastErrorCode());
        }
        $o->destinationid = $this->conn->lastInsertRowID();
    }

    /**
     * @param $ids array of destination identifiers.
     */
    public function deleteNotificationDestination(array $ids)
    {
        $query = 'DELETE FROM NOTIFICATIONDESTINATIONS WHERE DESTINATIONID IN("'
            .implode($ids,'","').'")';
        if (!$this->conn->query($query)) {
            throw new Exception($this->conn->lastErrorMsg(),
                $this->conn->lastErrorCode());
        }
    }

    private function queryNotificationDestinations($offset, $type=NULL)
    {
        //Cannot use a simple SELECT as the SQLite3Result::fetchArray does not
        //mix columns with same name from different tables
        $query = 'SELECT * FROM NOTIFICATIONDESTINATIONS';
        if (NULL !== $type) {
            $query .= ' WHERE TYPE="'.$type.'"';
        }
        $this->concatSelectLimit($query,$offset);
        return $this->conn->query($query);
    }

    /**
     * @param $offset ignored if $this->select_limit is not set.
     * @param $type NULL selects all rows.
     * @see __PwneoprivDbConn::createSelectResult
     * @see PwneoDb::$NOTIFICATION_TYPES
     */
    public function selectNotificationDestinations($offset, $type=NULL)
    {
        $rs = $this->queryNotificationDestinations($offset, $type);
        $res = __PwneoprivDbConn::createSelectResult($rs);
        $rs->finalize();
        return $res;
    }

    /**
     * @param $offset ignored if $this->select_limit is not set.
     * @param $type NULL selects all rows.
     * @see PwneoDb::$NOTIFICATION_TYPES
     */
    public function echoJsonNotificationDestinations($offset, $type=NULL)
    {
        $rs = $this->queryNotificationDestinations($offset, $type);
        PwneoDb::echoJsonSelectResult($rs);
        $rs->finalize();
    }

    /**
     * Ignores $this->select_limit.
     * @param $type NULL selects all rows.
     * @see PwneoDb::$NOTIFICATION_TYPES
     */
    public function echoCsvNotificationDestinations($type=NULL)
    {
        $rs = $this->queryNotificationDestinations(null, $type);
        PwneoDb::echoCsvSelectResult($rs);
        $rs->finalize();
    }

    /**
     * For each register in the table executes $callback($row) where $row is a
     * map whose keys are column names and values are column values for the
     * current row.
     * Ignores $this->select_limit.
     * @param $type NULL selects all rows.
     * @see PwneoDb::$NOTIFICATION_TYPES
     */
    public function forEachNotificationDestination($callback, $type=NULL)
    {
        $rs = $this->queryNotificationDestinations(null, $type);
        PwneoDb::forEachSelectResult($rs, $callback);
        $rs->finalize();
    }

    private function querySpectrumMonitoringGroups($offset)
    {
        $query = 'SELECT * FROM SPECTRUMMONITORINGGROUPS';
        $this->concatSelectLimit($query,$offset);
        return $this->conn->query($query);
    }

    /**
     * @param $offset ignored if $this->select_limit is not set.
     * @see __PwneoprivDbConn::createSelectResult
     */
    public function selectSpectrumMonitoringGroups($offset)
    {
        $rs = $this->querySpectrumMonitoringGroups($offset);
        $res = __PwneoprivDbConn::createSelectResult($rs);
        $rs->finalize();
        return $res;
    }

    /**
     * @param $offset ignored if $this->select_limit is not set.
     */
    public function echoJsonSpectrumMonitoringGroups($offset)
    {
        $rs = $this->querySpectrumMonitoringGroups($offset);
        PwneoDb::echoJsonSelectResult($rs);
        $rs->finalize();
    }

    /**
     * For each register in the table executes $callback($row) where $row is a
     * map whose keys are column names and values are column values for the
     * current row.
     * Ignores $this->select_limit.
     * @throws Exception on error; contains the error message an error code.
     */
    public function forEachSpectrumMonitoringGroups($callback)
    {
        $rs = $this->querySpectrumMonitoringGroups(null);
        PwneoDb::forEachSelectResult($rs, $callback);
        $rs->finalize();
    }

    /**
     * Ignores $this->select_limit.
     */
    public function echoCsvSpectrumMonitoringGroups()
    {
        $rs = $this->querySpectrumMonitoringGroups(null);
        PwneoDb::echoCsvSelectResult($rs);
        $rs->finalize();
    }

    private function querySpectrumMonitorings($dbconn,$offset)
    {
        $query = 'SELECT * FROM SPECTRUMMONITORINGS';
        $this->concatSelectLimit($query,$offset);
        return  $dbconn->query($query);
    }

    /**
     * @param $offset ignored if $this->select_limit is not set.
     * @see PwneoDb::createSelectResult
     */
    public function selectSpectrumMonitorings($offset,$groupdb)
    {
        $dbconn = new __PwneoprivDbConn($groupdb, SQLITE3_OPEN_READONLY,
            $this->conn->getTimeoutMs());
        $rs = $this->querySpectrumMonitorings($dbconn, $offset);
        $res = PwneoDb::createSelectResult($rs);
        $rs->finalize();
        return $res;
    }

    /**
     * @param $offset ignored if $this->select_limit is not set.
     */
    public function echoJsonSpectrumMonitorings($offset,$groupdb)
    {
        $dbconn = new __PwneoprivDbConn($groupdb, SQLITE3_OPEN_READONLY,
            $this->conn->getTimeoutMs());
        $rs = $this->querySpectrumMonitorings($dbconn, $offset);
        PwneoDb::echoJsonSelectResult($rs, array('SPECTRUMFREQS'=>@base64_encode,
            'REFSPECTRUMPOINTS'=>@base64_encode));
        $rs->finalize();
    }

    /**
     * Ignores $this->select_limit.
     */
    public function echoCsvSpectrumMonitorings($groupdb)
    {
        $dbconn = new __PwneoprivDbConn($groupdb, SQLITE3_OPEN_READONLY,
            $this->conn->getTimeoutMs());
        $rs = $this->querySpectrumMonitorings($dbconn, null);
        PwneoDb::echoCsvSelectResult($rs);
        $rs->finalize();
    }


    /**
     * For each register in the table executes $callback($row) where $row is a
     * map whose keys are column names and values are column values for the
     * current row.
     * Ignores $this->select_limit.
     * @throws Exception on error; contains the error message an error code.
     */
    public function forEachSpectrumMonitoring($callback,$groupdb)
    {
        $dbconn = new __PwneoprivDbConn($groupdb, SQLITE3_OPEN_READONLY,
            $this->conn->getTimeoutMs());
        $rs = $this->querySpectrumMonitorings($dbconn, null);
        PwneoDb::forEachSelectResult($rs, $callback);
        $rs->finalize();
    }

    private function querySpectrumPoints($dbconn,$offset,$spmonid,$tstart,$tend)
    {
//        $query = 'SELECT TIME,POINTS FROM SPECTRUMPOINTS JOIN SPECTRUMCUMULIDS '
//            .' USING(SPMONID,CUMULID) WHERE SPMONID='.$spmonid.' AND'
//            .' T0<='.$tend.' AND TEND>='.$tstart
//            .' AND TIME BETWEEN '.$tstart.' AND '.$tend;
        $query = 'SELECT TIME,POINTS FROM SPECTRUMPOINTS JOIN SPECTRUMCUMULIDS '
            .' USING(SPMONID,CUMULID) WHERE SPMONID='.$spmonid
            .' AND TIME BETWEEN '.$tstart.' AND '.$tend;
        $this->concatSelectLimit($query,$offset);
        return $dbconn->query($query);
    }

    /**
     * @param $offset ignored if $this->select_limit is not set.
     * @see PwneoDb::createSelectResult
     */
    public function selectSpectrumPoints($offset,$groupdb,$spmonid,$tstart,$tend)
    {
        $dbconn = new __PwneoprivDbConn($groupdb, SQLITE3_OPEN_READONLY,
            $this->conn->getTimeoutMs());
        $rs = $this->querySpectrumPoints($dbconn, $offset, $spmonid, $tstart,
            $tend);
        $res = PwneoDb::createSelectResult($rs);
        $rs->finalize();
        return $res;
    }

    /**
     * @param $offset ignored if $this->select_limit is not set.
     */
    public function echoJsonSpectrumPoints($offset,$groupdb,$spmonid,$tstart,$tend)
    {
        $dbconn = new __PwneoprivDbConn($groupdb, SQLITE3_OPEN_READONLY,
            $this->conn->getTimeoutMs());
        $rs = $this->querySpectrumPoints($dbconn, $offset, $spmonid, $tstart,
            $tend);
        PwneoDb::echoJsonSelectResult($rs, array('POINTS'=>@base64_encode));
        $rs->finalize();
    }

    /**
     * Ignores $this->select_limit.
     */
    public function echoCsvSpectrumPoints($groupdb,$spmonid,$tstart,$tend)
    {
        $dbconn = new __PwneoprivDbConn($groupdb, SQLITE3_OPEN_READONLY,
            $this->conn->getTimeoutMs());
        $rs = $this->querySpectrumPoints($dbconn, $offset, $spmonid, $tstart,
            $tend);
        PwneoDb::echoCsvSelectResult($rs);
        $rs->finalize();
    }

    private function querySpectrumEvents($dbconn,$offset,$spmonid,$tstart,$tend)
    {
        /*
        * We don't need to receive SPMONID since it's always the same
        */
        $query = 'SELECT EVID, TIME, ACTIVATION, REFID, TYPE, SEVERITY, FREQC, FREQ0, FREQ1,'
            .'VALUE, THRESHOLD FROM SPECTRUMEVENTS WHERE SPMONID='.$spmonid.' AND TIME '
            .'BETWEEN '.$tstart.' AND '.$tend;
        $this->concatSelectLimit($query,$offset);
        return $dbconn->query($query);

    }

    public function countSpectrumEvents($groupdb,$tstart,$tend,$spmonid)
    {
        $dbconn = new __PwneoprivDbConn($groupdb, SQLITE3_OPEN_READONLY, $this->conn->getTimeoutMs());

        $query = 'SELECT COUNT(1) FROM SPECTRUMEVENTS WHERE SPMONID='.$spmonid.' AND TIME '
            .'BETWEEN '.$tstart.' AND '.$tend;
        $rs = $dbconn->query($query);
        $row = $rs->fetchArray(SQLITE3_NUM);
        if (!$row) {
            $res = 0;
        } else {
            $res = $row[0];
        }
        $rs->finalize();
        return $res;
    }

    /**
     * @param $offset ignored if $this->select_limit is not set.
     * @see PwneoDb::createSelectResult
     */
    public function selectSpectrumEvents($offset,$groupdb,$spmonid,$tstart,$tend)
    {
        $dbconn = new __PwneoprivDbConn($groupdb, SQLITE3_OPEN_READONLY,
            $this->conn->getTimeoutMs());
        $rs = $this->querySpectrumEvents($dbconn, $offset, $spmonid, $tstart,$tend);
        $res = PwneoDb::createSelectResult($rs);
        $rs->finalize();
    }

    /**
     * @param $offset ignored if $this->select_limit is not set.
     */
    public function echoJsonSpectrumEvents($offset,$groupdb,$spmonid,$tstart,$tend)
    {
        $dbconn = new __PwneoprivDbConn($groupdb, SQLITE3_OPEN_READONLY,
            $this->conn->getTimeoutMs());
        $rs = $this->querySpectrumEvents($dbconn, $offset, $spmonid, $tstart,$tend);
        PwneoDb::echoJsonSelectResult($rs, array('EVENTS'=>@utf8_encode));
        $rs->finalize();
    }

    /**
     * Ignores $this->select_limit.
     */
    public function echoCsvSpectrumEvents($offset,$groupdb,$spmonid,$tstart,$tend)
    {
        $dbconn = new __PwneoprivDbConn($groupdb, SQLITE3_OPEN_READONLY,
            $this->conn->getTimeoutMs());
        $rs = $this->querySpectrumEvents($dbconn, $offset, $spmonid, $tstart,$tend);
        PwneoDb::echoCsvSelectResult($rs);
        $rs->finalize();
    }

    /**
     * For each register in the table executes $callback($row) where $row is a
     * map whose keys are column names and values are column values for the
     * current row.
     * Ignores $this->select_limit.
     * @throws Exception on error; contains the error message an error code.
     */
    public function forEachSpectrumPoint($callback,$groupdb,$spmonid,
                                         $tstart,$tend)
    {
        $dbconn = new __PwneoprivDbConn($groupdb, SQLITE3_OPEN_READONLY,
            $this->conn->getTimeoutMs());
        $rs = $this->querySpectrumPoints($dbconn, null, $groupdb, $tstart,
            $tend);
        PwneoDb::forEachSelectResult($rs, $callback);
        $rs->finalize();
    }

    private function queryTaskScheduling($offset)
    {
        $query = 'select taskscheduling.TASKID AS TASKID, TASKTYPE, NEXTRUNDATE, EXPIRATIONDATE, PREVIOUSRUNTIME,
                  REPETITIONTYPE, REPETITIONSTARTMOMENT, REPETITIONP1, REPETITIONP2, RUNDURATION, ENABLED, ERRTYPE
                  from taskscheduling LEFT JOIN ( SELECT * from taskexecutions where TIME IN (select max(time)
                  from taskexecutions group by taskid) group by taskid) lastexecutions ON taskscheduling.TASKID = lastexecutions.TASKID;';
        return $this->conn->query($query);
    }

    /**
     * @param $offset ignored if $this->select_limit is not set.
     * @throws Exception on error; contains the error message an error code.
     * @see __PwneoprivDbConn::createSelectResult
     */
    public function selectTaskScheduling($offset)
    {
        $rs = $this->queryTaskScheduling($offset);
        $res = __PwneoprivDbConn::createSelectResult($rs);
        $rs->finalize();
        return $res;
    }

    /**
     * @param $offset ignored if $this->select_limit is not set.
     * @throws Exception on error; contains the error message an error code.
     */
    public function echoJsonTaskScheduling($offset)
    {
        $rs = $this->queryTaskScheduling($offset);
        PwneoDb::echoJsonSelectResult($rs);
        $rs->finalize();
    }

    /**
     * Ignores $this->select_limit.
     * @throws Exception on error; contains the error message an error code.
     */
    public function echoCsvTaskScheduling()
    {
        $rs = $this->queryTaskScheduling(null);
        PwneoDb::echoCsvSelectResult($rs);
        $rs->finalize();
    }

    private function querySpectralMonitoringTasks($offset)
    {
        $query = 'SELECT * FROM SPECTRALMONITORINGTASKS';
        return $this->conn->query($query);
    }

    /**
     * @param $offset ignored if $this->select_limit is not set.
     * @throws Exception on error; contains the error message an error code.
     * @see __PwneoprivDbConn::createSelectResult
     */
    public function selectSpectralMonitoringTasks($offset)
    {
        $rs = $this->querySpectralMonitoringTasks($offset);
        $res = __PwneoprivDbConn::createSelectResult($rs);
        $rs->finalize();
        return $res;
    }

    /**
     * @param $offset ignored if $this->select_limit is not set.
     * @throws Exception on error; contains the error message an error code.
     */
    public function echoJsonSpectralMonitoringTasks($offset)
    {
        $rs = $this->querySpectralMonitoringTasks($offset);
        PwneoDb::echoJsonSelectResult($rs);
        $rs->finalize();
    }

    /**
     * Ignores $this->select_limit.
     * @throws Exception on error; contains the error message an error code.
     */
    public function echoCsvSpectralMonitoringTasks()
    {
        $rs = $this->querySpectralMonitoringTasks(null);
        PwneoDb::echoCsvSelectResult($rs);
        $rs->finalize();
    }

    private function querySpectralMonitoringTaskbyId($taskid)
    {
        $query = 'SELECT * FROM SPECTRALMONITORINGTASKS WHERE TASKID='.$taskid;
        return $this->conn->query($query);
    }

    public function selectSpectralMonitoringTaskbyId($taskid)
    {
        $rs = $this->querySpectralMonitoringTaskbyId($taskid);
        //$res = __PwneoprivDbConn::createSelectResult($rs);
        PwneoDb::echoJsonSelectResult($rs);
        $rs->finalize();
        //return $res;
    }

    private function querySpectraltaskfromGroup($groupID)
    {
        $query = 'SELECT * FROM TASKSCHEDULING WHERE TASKID=(SELECT TASKID FROM SPECTRALMONITORINGTASKS WHERE GRPID='.$groupID.')';
        return $this->conn->query($query);
    }

    public function echoJsonSpectraltaskfromGroup($groupID)
    {
        $rs = $this->querySpectraltaskfromGroup($groupID);
        PwneoDb::echoJsonSelectResult($rs);
        $rs->finalize();
    }

    private function queryMonitoringTasks($offset)
    {
        $query = 'SELECT * FROM MONITORINGTASKS';
        return $this->conn->query($query);
    }

    /**
     * Ignores $this->select_limit.
     * @throws Exception on error; contains the error message an error code.
     */
    public function selectMonitoringTasks($offset)
    {
        $rs = $this->queryMonitoringTasks($offset);
        $res = __PwneoprivDbConn::createSelectResult($rs);
        $rs->finalize();
        return $res;
    }

    /**
     * @param $offset ignored if $this->select_limit is not set.
     * @throws Exception on error; contains the error message an error code.
     */
    public function echoJsonMonitoringTasks($offset)
    {
        $rs = $this->queryMonitoringTasks($offset);
        PwneoDb::echoJsonSelectResult($rs);
        $rs->finalize();
    }
    /**
     * Ignores $this->select_limit.
     * @throws Exception on error; contains the error message an error code.
     */
    public function echoCsvMonitoringTasks()
    {
        $rs = $this->queryMonitoringTasks(null);
        PwneoDb::echoCsvSelectResult($rs);
        $rs->finalize();
    }

    private function queryMonitoringTaskbyId($taskid)
    {
        $query = 'SELECT * FROM MONITORINGTASKS WHERE TASKID='.$taskid;
        return $this->conn->query($query);
    }

    public function selectMonitoringTaskbyId($taskid)
    {
        $rs = $this->queryMonitoringTaskbyId($taskid);
        PwneoDb::echoJsonSelectResult($rs);
        $rs->finalize();
    }

    private function queryMonitoringtaskfromMonid($monID)
    {
        $query = 'SELECT * FROM TASKSCHEDULING WHERE TASKID=(SELECT TASKID FROM MONITORINGTASKS WHERE MONID='.$monID.')';
        return $this->conn->query($query);
    }

    public function echoJsonMonitoringtaskfromMonid($monID)
    {
        $rs = $this->queryMonitoringtaskfromGroup($monID);
        PwneoDb::echoJsonSelectResult($rs);
        $rs->finalize();
    }

    private function queryCaptureTasks($offset)
    {
        $query = 'SELECT * FROM CAPTURETASKS';
        return $this->conn->query($query);
    }

    /**
     * Ignores $this->select_limit.
     * @throws Exception on error; contains the error message an error code.
     */
    public function selectCaptureTasks($offset)
    {
        $rs = $this->queryCaptureTasks($offset);
        $res = __PwneoprivDbConn::createSelectResult($rs);
        $rs->finalize();
        return $res;
    }

    /**
     * @param $offset ignored if $this->select_limit is not set.
     * @throws Exception on error; contains the error message an error code.
     */
    public function echoJsonCaptureTasks($offset)
    {
        $rs = $this->queryCaptureTasks($offset);
        PwneoDb::echoJsonSelectResult($rs);
        $rs->finalize();
    }
    /**
     * Ignores $this->select_limit.
     * @throws Exception on error; contains the error message an error code.
     */
    public function echoCsvCaptureTasks()
    {
        $rs = $this->queryCaptureTasks(null);
        PwneoDb::echoCsvSelectResult($rs);
        $rs->finalize();
    }

    private function queryCaptureTaskbyId($taskid)
    {
        $query = 'SELECT * FROM CAPTURETASKS WHERE TASKID='.$taskid;
        return $this->conn->query($query);
    }

    public function echoJsonCaptureTaskbyId($taskid)
    {
        $rs = $this->queryCaptureTaskbyId($taskid);
        PwneoDb::echoJsonSelectResult($rs);
        $rs->finalize();
    }

    private function queryDataloggerTasks($offset)
    {
        $query = 'SELECT * FROM DATALOGGERTASKS';
        return $this->conn->query($query);
    }

    private function queryDataloggerTaskbyId($taskid)
    {
        $query = 'SELECT * FROM DATALOGGERTASKS WHERE TASKID='.$taskid;
        return $this->conn->query($query);
    }

    public function selectDataloggerTaskbyId($taskid)
    {
        $rs = $this->queryDataloggerTaskbyId($taskid);
        $res = __PwneoprivDbConn::createSelectResult($rs);
        $rs->finalize();
        return $res;
    }

    /**
     * Ignores $this->select_limit.
     * @throws Exception on error; contains the error message an error code.
     */
    public function selectDataloggerTasks($offset)
    {
        $rs = $this->queryDataloggerTasks($offset);
        $res = __PwneoprivDbConn::createSelectResult($rs);
        $rs->finalize();
        return $res;
    }

    /**
     * @param $offset ignored if $this->select_limit is not set.
     * @throws Exception on error; contains the error message an error code.
     */
    public function echoJsonDataloggerTasks($offset)
    {
        $rs = $this->queryDataloggerTasks($offset);
        PwneoDb::echoJsonSelectResult($rs);
        $rs->finalize();
    }
    /**
     * Ignores $this->select_limit.
     * @throws Exception on error; contains the error message an error code.
     */
    public function echoCsvDataloggerTasks()
    {
        $rs = $this->queryDataloggerTasks(null);
        PwneoDb::echoCsvSelectResult($rs);
        $rs->finalize();
    }


    public function echoJsonDataloggerTaskbyId($taskid)
    {
        $rs = $this->queryDataloggerTaskbyId($taskid);
        PwneoDb::echoJsonSelectResult($rs);
        $rs->finalize();
    }

    private function queryTSRecordTasks($offset)
    {
        $query = 'SELECT * FROM TSRECORDTASKS';
        return $this->conn->query($query);
    }

    /**
     * Ignores $this->select_limit.
     * @throws Exception on error; contains the error message an error code.
     */
    public function selectTSRecordTasks($offset)
    {
        $rs = $this->queryTSRecordTasks($offset);
        $res = __PwneoprivDbConn::createSelectResult($rs);
        $rs->finalize();
        return $res;
    }

    /**
     * @param $offset ignored if $this->select_limit is not set.
     * @throws Exception on error; contains the error message an error code.
     */
    public function echoJsonTSRecordTasks($offset)
    {
        $rs = $this->queryTSRecordTasks($offset);
        PwneoDb::echoJsonSelectResult($rs);
        $rs->finalize();
    }

    /**
     * @param $offset ignored if $this->select_limit is not set.
     * @throws Exception on error; contains the error message an error code.
     */
    public function echoJsonTSRecordTaskbyId($taskid)
    {
        $rs = $this->queryTSRecordTaskbyId($taskid);
        PwneoDb::echoJsonSelectResult($rs);
        $rs->finalize();
    }

    /**
     * Ignores $this->select_limit.
     * @throws Exception on error; contains the error message an error code.
     */
    public function echoCsvTSRecordTasks()
    {
        $rs = $this->queryTSRecordTasks(null);
        PwneoDb::echoCsvSelectResult($rs);
        $rs->finalize();
    }

    private function queryTSRecordTaskbyId($taskid)
    {
        $query = 'SELECT * FROM TSRECORDTASKS WHERE TASKID='.$taskid;
        return $this->conn->query($query);
    }

    public function selectTSRecordTaskbyId($taskid)
    {
        $rs = $this->queryTSRecordTaskbyId($taskid);
        $res = __PwneoprivDbConn::createSelectResult($rs);
        $rs->finalize();
        return $res;
    }

    //AudioRecord
    private function queryAudioRecordTasks($offset)
    {
        $query = 'SELECT * FROM AUDIORECORDTASKS';
        return $this->conn->query($query);
    }

    public function selectAudioRecordTasks($offset)
    {
        $rs = $this->queryAudioRecordTasks($offset);
        $res = __PwneoprivDbConn::createSelectResult($rs);
        $rs->finalize();
        return $res;
    }

    /**
     * @param $offset ignored if $this->select_limit is not set.
     * @throws Exception on error; contains the error message an error code.
     */
    public function echoJsonAudioRecordTasks($offset)
    {
        $rs = $this->queryAudioRecordTasks($offset);
        PwneoDb::echoJsonSelectResult($rs);
        $rs->finalize();
    }

    /**
     * Ignores $this->select_limit.
     * @throws Exception on error; contains the error message an error code.
     */
    public function echoCsvAudioRecordTasks()
    {
        $rs = $this->queryAudioRecordTasks(null);
        PwneoDb::echoCsvSelectResult($rs);
        $rs->finalize();
    }


    private function queryAudioRecordTaskbyId($taskid)
    {
        $query = 'SELECT * FROM AUDIORECORDTASKS WHERE TASKID='.$taskid;
        return $this->conn->query($query);
    }

    public function selectAudioRecordTaskbyId($taskid)
    {
        $rs = $this->queryAudioRecordTaskbyId($taskid);
        $res = __PwneopribDbConn::createSelectResult($rs);
        $rs->finalize();
        return $res;
    }
     /**
     * @param $offset ignored if $this->select_limit is not set.
     * @throws Exception on error; contains the error message an error code.
     */
    public function echoJsonAudioRecordTaskbyId($offset)
    {
        $rs = $this->queryAudioRecordTaskbyId($offset);
        PwneoDb::echoJsonSelectResult($rs);
        $rs->finalize();
    }

    /**
     * Ignores $this->select_limit.
     * @throws Exception on error; contains the error message an error code.
     */
    public function echoCsvAudioRecordTaskbyId()
    {
        $rs = $this->queryAudioRecordTaskbyId(null);
        PwneoDb::echoCsvSelectResult($rs);
        $rs->finalize();
    }

    //EtiRecord
    private function queryEtiRecordTasks($offset)
    {
        $query = 'SELECT * FROM ETIRECORDTASKS';
        return $this->conn->query($query);
    }

    public function selectEtiRecordTasks($offset)
    {
        $rs = $this->queryEtiRecordTasks($offset);
        $res = __PwneoprivDbConn::createSelectResult($rs);
        $rs->finalize();
        return $res;
    }

    /**
     * @param $offset ignored if $this->select_limit is not set.
     * @throws Exception on error; contains the error message an error code.
     */
    public function echoJsonEtiRecordTasks($offset)
    {
        $rs = $this->queryEtiRecordTasks($offset);
        PwneoDb::echoJsonSelectResult($rs);
        $rs->finalize();
    }

    /**
     * Ignores $this->select_limit.
     * @throws Exception on error; contains the error message an error code.
     */
    public function echoCsvEtiRecordTasks()
    {
        $rs = $this->queryEtiRecordTasks(null);
        PwneoDb::echoCsvSelectResult($rs);
        $rs->finalize();
    }


    private function queryEtiRecordTaskbyId($taskid)
    {
        $query = 'SELECT * FROM ETIRECORDTASKS WHERE TASKID='.$taskid;
        return $this->conn->query($query);
    }

    public function selectEtiRecordTaskbyId($taskid)
    {
        $rs = $this->queryEtiRecordTaskbyId($taskid);
        $res = __PwneopribDbConn::createSelectResult($rs);
        $rs->finalize();
        return $res;
    }
     /**
     * @param $offset ignored if $this->select_limit is not set.
     * @throws Exception on error; contains the error message an error code.
     */
    public function echoJsonEtiRecordTaskbyId($offset)
    {
        $rs = $this->queryEtiRecordTaskbyId($offset);
        PwneoDb::echoJsonSelectResult($rs);
        $rs->finalize();
    }

    /**
     * Ignores $this->select_limit.
     * @throws Exception on error; contains the error message an error code.
     */
    public function echoCsvEtiRecordTaskbyId()
    {
        $rs = $this->queryEtiRecordTaskbyId(null);
        PwneoDb::echoCsvSelectResult($rs);
        $rs->finalize();
    }


    //Task Executions
    private function queryTaskExecutionsById($taskid)
    {
        $query = 'SELECT * FROM TASKEXECUTIONS WHERE TASKID='.$taskid;
        return $this->conn->query($query);
    }

    public function selectTaskExecutionsById($taskid)
    {
        $rs = $this->queryTaskExecutionsById($taskid);
        $res = __PwneoprivDbConn::createSelectResult($rs);
        $rs->finalize();
        return $res;
    }

    public function echoJsonTaskExecutions($taskid)
    {
        $rs = $this->queryTaskExecutions($taskid);
        PwneoDb::echoJsonSelectResult($rs);
        $rs->finalize();
    }

    public function echoCsvTaskExecutions($taskid)
    {
        $rs = $this->queryTaskExecutions($taskid);
        PwneoDb::echoCsvSelectResult($rs);
        $rs->finalize();
    }


}
