<?php

class PacketTelemetryRepository extends ModelRepository
{

    private static $_singletonInstance = null;

    public function __construct()
    {
        parent::__construct('PacketTelemetry');
    }

    /**
     * Returnes an initiated PacketTelemetryRepository
     *
     * @return PacketTelemetryRepository
     */
    public static function getInstance()
    {
        if (self::$_singletonInstance === null) {
            self::$_singletonInstance = new PacketTelemetryRepository();
        }

        return self::$_singletonInstance;
    }

    /**
     * Get object by id
     *
     * @param  int $id
     * @param  int $timestamp
     * @return PacketTelemetry
     */
    public function getObjectById($id, $timestamp)
    {
        if (!isInt($id) || !isInt($timestamp)) {
            return new PacketTelemetry(0);
        }
        return $this->getObjectFromSql('select * from packet_telemetry where id = ? and timestamp = ?', [$id, $timestamp]);
    }

    /**
     * Get object by packet id
     *
     * @param  int $id
     * @param  int $timestamp
     * @return PacketTelemetry
     */
    public function getObjectByPacketId($id, $timestamp)
    {
        if (!isInt($id) || !isInt($timestamp)) {
            return new PacketTelemetry(0);
        }
        return $this->getObjectFromSql('select * from packet_telemetry where packet_id = ? and timestamp = ?', [$id, $timestamp]);
    }

    /**
     * Get latest object by station id (for the latest 3 days)
     * Note: Some stations can send BITS data independent of normal telemetry packets. This means that the BITS record
     * stored in the station_telemetry_bits_id may be out of date if the BITS record arrived after the last telemetry packet.
     * To get around this, we will check the station_telemetry_bits table for the latest record for this station.
     *
     * @param  int $stationId
     * @return array
     */
    public function getLatestObjectByStationId($stationId, $latestBITS = false)
    {
        if (!isInt($stationId)) {
            return new PacketTelemetry(0);
        }

        if ($latestBITS === false)
          return $this->getObjectFromSql(
              'select * from packet_telemetry
              where station_id = ?
                  and timestamp > ?
              order by timestamp desc limit 1', [$stationId, (time() - 24*60*60*3)]
          );
        return $this->getObjectFromSql(
            'select t.*, b.id AS station_telemetry_bits_id
             from packet_telemetry t
             LEFT JOIN station_telemetry_bits b ON (b.station_id = t.station_id AND b.valid_to_ts IS NULL)
            where t.station_id = ?
                and t.timestamp > ?
            order by t.timestamp desc limit 1', [$stationId, (time() - 24*60*60*3)]
        );
    }

    /**
     * Get latest data list by station id (useful for creating a chart)
     *
     * @param  int   $stationId
     * @param  int   $startTimestamp
     * @param  int   $endTimestamp
     * @param  array $columns
     * @param  int   $limit
     * @return array
     */
    public function getLatestDataListByStationId($stationId, $startTimestamp, $endTimestamp, $columns=['*'], $limit=500)
    {
        if (!isInt($stationId) || !isInt($startTimestamp)|| !isInt($endTimestamp) || !is_array($columns)) {
            return [];
        }

        $sql = 'select ' . implode(',', $columns) . ' from packet_telemetry
            where station_id = ?
                and timestamp >= ?
                and timestamp <= ?
            order by timestamp desc
            limit ?';
        $arg = [$stationId, $startTimestamp, $endTimestamp, $limit];

        $pdo = PDOConnection::getInstance();
        $stmt = $pdo->prepareAndExec($sql, $arg);
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }


    /**
     * Get latest BITS data list by station id (useful for creating a chart)
     *
     * @param  int   $stationId
     * @param  int   $startTimestamp
     * @param  int   $endTimestamp
     * @param  array $columns
     * @param  int   $limit
     * @return array
     */
    public function getLatestBitsDataListByStationId($stationId, $startTimestamp, $endTimestamp, $columns=['t.*, b.bits'], $limit=500)
    {
        if (!isInt($stationId) || !isInt($startTimestamp)|| !isInt($endTimestamp) || !is_array($columns)) {
            return [];
        }

        if ($columns[0] == 't.*, b.bits' && !in_array('station_telemetry_bits_id', $columns)) {
          return [];
        }

        $sql = 'select ' . implode(',', $columns) . ' from packet_telemetry t
            left join station_telemetry_bits b on b.id = t.station_telemetry_bits_id
            where t.station_id = ?
                and t.timestamp >= ?
                and timestamp <= ?
            order by t. timestamp desc
            limit ?';
        $arg = [$stationId, $startTimestamp, $endTimestamp, $limit];

        $pdo = PDOConnection::getInstance();
        $stmt = $pdo->prepareAndExec($sql, $arg);
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }


    /**
     * Get latest object list by station id
     * We only include telemetry that has the same params, units and eqns as the latest telemetry packet
     *
     * @param  int             $stationId
     * @param  int             $limit
     * @param  int             $offset
     * @param  int             $maxDays
     * @return array
     */
    public function getLatestObjectListByStationId($stationId, $limit, $offset, $maxDays = 7, $sort='desc', $startAt=null, $endAt=null)
    {
        if (!isInt($stationId) || !isInt($limit) || !isInt($offset) || !isInt($maxDays)) {
            return [];
        }
        $latestObject = $this->getLatestObjectByStationId($stationId);

        $sqlParameters = Array();
        $sql = 'select * from packet_telemetry where station_id = ? and timestamp > ? and timestamp < ?';
        $sqlParameters[] = $stationId;
        $sqlParameters[] = $startAt ?? (time() - 24*60*60*$maxDays);
        $sqlParameters[] = $endAt ?? time();

        if ($latestObject->stationTelemetryParamId !== null) {
            $sql .= ' and station_telemetry_param_id = ?';
            $sqlParameters[] = $latestObject->stationTelemetryParamId;
        } else {
            $sql .= ' and station_telemetry_param_id is null';
        }

        if ($latestObject->stationTelemetryUnitId !== null) {
            $sql .= ' and station_telemetry_unit_id = ?';
            $sqlParameters[] = $latestObject->stationTelemetryUnitId;
        } else {
            $sql .= ' and station_telemetry_unit_id is null';
        }

        // if ($latestObject->stationTelemetryEqnsId !== null) {
        // $sql .= ' and station_telemetry_eqns_id = ?';
        // $sqlParameters[] = $latestObject->stationTelemetryEqnsId;
        // } else {
        // $sql .= ' and station_telemetry_eqns_id is null';
        // }

        if ($latestObject->stationTelemetryBitsId !== null) {
            $sql .= ' and station_telemetry_bits_id = ?';
            $sqlParameters[] = $latestObject->stationTelemetryBitsId;
        } else {
            $sql .= ' and station_telemetry_bits_id is null';
        }

        $sql .= ' order by timestamp '.$sort.' limit ? offset ?';
        $sqlParameters[] = $limit;
        $sqlParameters[] = $offset;

        return $this->getObjectListFromSql($sql, $sqlParameters);
    }


    /**
     * Get latest number of packets by station id
     * We only include telemetry that has the same params, units and eqns as the latest telemetry packet
     *
     * @param  int             $stationId
     * @param  int             $maxDays
     * @return int
     */
    public function getLatestNumberOfPacketsByStationId($stationId, $maxDays = 7, $startAt=null, $endAt=null)
    {
        if (!isInt($stationId) || !isInt($maxDays)) {
            return 0;
        }
        $latestObject = $this->getLatestObjectByStationId($stationId);

        $sqlParameters = Array();
        $sql = 'select count(*) c from packet_telemetry where station_id = ? and timestamp > ? and timestamp < ?';
        $sqlParameters[] = $stationId;
        $sqlParameters[] = $startAt ?? (time() - 24*60*60*$maxDays);
        $sqlParameters[] = $endAt ?? time();

        if ($latestObject->stationTelemetryParamId !== null) {
            $sql .= ' and station_telemetry_param_id = ?';
            $sqlParameters[] = $latestObject->stationTelemetryParamId;
        } else {
            $sql .= ' and station_telemetry_param_id is null';
        }

        if ($latestObject->stationTelemetryUnitId !== null) {
            $sql .= ' and station_telemetry_unit_id = ?';
            $sqlParameters[] = $latestObject->stationTelemetryUnitId;
        } else {
            $sql .= ' and station_telemetry_unit_id is null';
        }

        // if ($latestObject->stationTelemetryEqnsId !== null) {
        // $sql .= ' and station_telemetry_eqns_id = ?';
        // $sqlParameters[] = $latestObject->stationTelemetryEqnsId;
        // } else {
        // $sql .= ' and station_telemetry_eqns_id is null';
        // }

        if ($latestObject->stationTelemetryBitsId !== null) {
            $sql .= ' and station_telemetry_bits_id = ?';
            $sqlParameters[] = $latestObject->stationTelemetryBitsId;
        } else {
            $sql .= ' and station_telemetry_bits_id is null';
        }

        $pdo = PDOConnection::getInstance();
        $stmt = $pdo->prepareAndExec($sql, $sqlParameters);
        $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

        $sum = 0;
        foreach($rows as $row) {
            $sum += $row['c'];
        }

        return $sum;
    }
}
