from __future__ import print_function
from time import time
import subprocess
import random
import numpy

# Constants

STEP = 1000 * 100   # the size of the buffer to fill the table, in rows
SCALE = 0.1         # standard deviation of the noise compared with actual
                    # values
NI_NTIMES = 1       # The number of queries for doing a mean (non-idx cols)
# COLDCACHE = 10   # The number of reads where the cache is considered 'cold'
# WARMCACHE = 50   # The number of reads until the cache is considered 'warmed'
# READ_TIMES = WARMCACHE+50    # The number of complete calls to DB.query_db()
# COLDCACHE = 50   # The number of reads where the cache is considered 'cold'
# WARMCACHE = 50   # The number of reads until the cache is considered 'warmed'
# READ_TIMES = WARMCACHE+50    # The number of complete calls to DB.query_db()
MROW = 1000 * 1000.

# Test values
COLDCACHE = 5   # The number of reads where the cache is considered 'cold'
WARMCACHE = 5   # The number of reads until the cache is considered 'warmed'
READ_TIMES = 10    # The number of complete calls to DB.query_db()

# global variables
rdm_cod = ['lin', 'rnd']
prec = 6  # precision for printing floats purposes


def get_nrows(nrows_str):
    if nrows_str.endswith("k"):
        return int(float(nrows_str[:-1]) * 1000)
    elif nrows_str.endswith("m"):
        return int(float(nrows_str[:-1]) * 1000 * 1000)
    elif nrows_str.endswith("g"):
        return int(float(nrows_str[:-1]) * 1000 * 1000 * 1000)
    else:
        raise ValueError(
            "value of nrows must end with either 'k', 'm' or 'g' suffixes.")


class DB(object):

    def __init__(self, nrows, rng, userandom):
        global step, scale
        self.step = STEP
        self.scale = SCALE
        self.rng = rng
        self.userandom = userandom
        self.filename = '-'.join([rdm_cod[userandom], nrows])
        self.nrows = get_nrows(nrows)

    def get_db_size(self):
        sout = subprocess.Popen("sync;du -s %s" % self.filename, shell=True,
                                stdout=subprocess.PIPE).stdout
        line = [l for l in sout][0]
        return int(line.split()[0])

    def print_mtime(self, t1, explain):
        mtime = time() - t1
        print("%s:" % explain, round(mtime, 6))
        print("Krows/s:", round((self.nrows / 1000.) / mtime, 6))

    def print_qtime(self, colname, ltimes):
        qtime1 = ltimes[0]  # First measured time
        qtime2 = ltimes[-1]  # Last measured time
        print("Query time for %s:" % colname, round(qtime1, 6))
        print("Mrows/s:", round((self.nrows / (MROW)) / qtime1, 6))
        print("Query time for %s (cached):" % colname, round(qtime2, 6))
        print("Mrows/s (cached):", round((self.nrows / (MROW)) / qtime2, 6))

    def norm_times(self, ltimes):
        "Get the mean and stddev of ltimes, avoiding the extreme values."
        lmean = ltimes.mean()
        lstd = ltimes.std()
        ntimes = ltimes[ltimes < lmean + lstd]
        nmean = ntimes.mean()
        nstd = ntimes.std()
        return nmean, nstd

    def print_qtime_idx(self, colname, ltimes, repeated, verbose):
        if repeated:
            r = "[REP] "
        else:
            r = "[NOREP] "
        ltimes = numpy.array(ltimes)
        ntimes = len(ltimes)
        qtime1 = ltimes[0]  # First measured time
        ctimes = ltimes[1:COLDCACHE]
        cmean, cstd = self.norm_times(ctimes)
        wtimes = ltimes[WARMCACHE:]
        wmean, wstd = self.norm_times(wtimes)
        if verbose:
            print("Times for cold cache:\n", ctimes)
            # print "Times for warm cache:\n", wtimes
            print("Histogram for warm cache: %s\n%s" %
                  numpy.histogram(wtimes))
        print("%s1st query time for %s:" % (r, colname),
              round(qtime1, prec))
        print("%sQuery time for %s (cold cache):" % (r, colname),
              round(cmean, prec), "+-", round(cstd, prec))
        print("%sQuery time for %s (warm cache):" % (r, colname),
              round(wmean, prec), "+-", round(wstd, prec))