from __future__ import print_function

import sys
from sys import stderr, argv
from os import makedirs
from os.path import abspath, isfile, isdir, split
import sqlite3
from datetime import datetime as dt
from dateutil import parser as dt_parser

def _insert(val, sensor):
    """Returns INSERT query"""
    query = "INSERT INTO samples (id, value, sensor, timestamp) VALUES (NULL, %f, '%s', '%s');"
    return query % (val, sensor, dt.utcnow())

class FriskbyDao(object):

    def __init__(self, sql_path):
        """The sqlite db has a table called 'samples' with schema
        id, value, sensor, timestamp, uploaded
        """
        self._sql_path = abspath(sql_path)
        self.__init_sql()

    def get_path(self):
        return self._sql_path

    def __init_sql(self):
        if isfile(self._sql_path):
            return # nothing to do

        _path, _ = split(self._sql_path)
        if not isdir(_path):
            makedirs(_path) # equivalent to `mkdir -p _path`
        if not isfile(self._sql_path):
            print('No database, constructing new: %s.' % self._sql_path)
            _id = '`id` INTEGER PRIMARY KEY'
            _val = '`value` FLOAT NOT NULL'
            _sen = '`sensor` TEXT NOT NULL'
            _date = '`timestamp` TEXT NOT NULL'
            _upl = '`uploaded` BOOL DEFAULT 0'
            _create = 'CREATE TABLE samples (%s, %s, %s, %s, %s);'
            schema = _create % (_id, _val, _sen, _date, _upl)
            conn = sqlite3.connect(self._sql_path)
            conn.execute(schema)
            conn.close()

    def get_num_rows(self, uploaded_status=None):
        """Gets num rows in sql storage.  If uploaded_status is set to True, we
        fetch number of rows that are marked uploaded, if uploaded_status is set
        to False, we fetch number of rows that are marked as not uploaded.
        """
        query = 'SELECT COUNT(uploaded) FROM samples'
        if uploaded_status is not None:
            if uploaded_status:
                query += ' WHERE uploaded'
            else:
                query += ' WHERE NOT uploaded'
        query += ';'
        conn = sqlite3.connect(self._sql_path)
        result = conn.execute(query)
        num = result.fetchone()[0]
        conn.close()
        return num


    def get_non_uploaded(self, limit=100):
        sub_q = "id, value, sensor, datetime(timestamp, 'localtime'), uploaded"
        query = 'SELECT %s FROM samples WHERE NOT `uploaded` LIMIT %d;'
        try:
            conn = sqlite3.connect(self._sql_path)
            result = conn.execute(query % (sub_q, limit))
            data = result.fetchall()
            conn.close()
            print('dao fetched %d rows of non-uploaded data' % len(data))
            sys.stdout.flush()
            for i in range(len(data)):
                id_, val_, sens_, dt_, upl_ = data[i]
                data[i] = id_, val_, sens_, dt_parser.parse(dt_), upl_
            return data
        except Exception as err:
            stderr.write('Error on reading data: %s.\n' % err)

    def persist_ts(self, data):
        ts_pm10, ts_pm25 = data
        q10 = _insert(ts_pm10.median(), 'PM10')
        q25 = _insert(ts_pm25.median(), 'PM25')
        try:
            conn = sqlite3.connect(self._sql_path)
            conn.execute(q10)
            conn.execute(q25)
            conn.commit()
            conn.close()
        except Exception as err:
            stderr.write('Error on persisting data: %s.\n' % err)
        print('Persisted data.')
        sys.stdout.flush()

    def mark_uploaded(self, data):
        print('dao marking ...')
        sys.stdout.flush()
        query = 'UPDATE samples SET uploaded=1 WHERE id=%s'
        try:
            conn = sqlite3.connect(self._sql_path)
            conn.execute('begin')
            for row in data:
                # id, value, sensor, timestamp, uploaded
                id_ = row[0]
                conn.execute(query % id_)
            conn.commit()
            conn.close()
        except Exception as err:
            stderr.write('Error on setting UPLOADED data! %s.\n' % err)


    def __repr__(self):
        try:
            num, num_up = self.get_num_rows(), self.get_num_rows(uploaded_status=True)
            fmt = 'FriskbyDao(num_rows=%s, non_uploaded=%s, path=%s)'
            return fmt % (num, num_up, self._sql_path)
        except:
            return 'FriskbyDao(path=%s)' % (self._sql_path)

if __name__ == '__main__':
    if len(argv) > 1:
        FriskbyDao(argv[1])
    else:
        sys.exit('Need a path to an sqlite database.')
