import json
from sqlite3.dbapi2 import Cursor

class MCConfig(object):
    """ Memory Controller Configuration Class

        The format used in memory specification XML files differs from the
        format used in memory controller configuration XML files. Each class
        uses the proper format when searching for elements.
    """
    def getValue(self, id):
        return self.jsonMCConfig['mcconfig'][id]

    def getIntValue(self, id):
        return int(self.getValue(id))

    def __init__(self, dbconnection):
        cursor = dbconnection.cursor()
        cursor.execute("SELECT MCconfig FROM GeneralInfo")
        result = cursor.fetchone()
        self.jsonMCConfig = json.loads(result[0])


class MemSpec(object):
    """ Memory Specification Class

        The format used in memory specification XML files differs from the
        format used in memory configuration XML files. Each class uses the
        proper format when searching for elements.
    """
    def getValue(self, id):
        val = self.jsonMemSpec['memspec'][id]
        return val

    def getIntValue(self, group, id):
        val = self.jsonMemSpec['memspec'][group][id]
        return int(val)

    def __init__(self, dbconnection):
        cursor = dbconnection.cursor()
        cursor.execute("SELECT Memspec FROM GeneralInfo")
        result = cursor.fetchone()
        self.jsonMemSpec = json.loads(result[0])


def getClock(dbconnection):
    cursor = dbconnection.cursor()
    cursor.execute("SELECT clk, UnitOfTime FROM GeneralInfo")
    clock, unit = cursor.fetchone()
    return (clock, unit)

def getNumberOfTransactions(dbconnection):
    cursor = dbconnection.cursor()
    cursor.execute("SELECT NumberOfTransactions FROM GeneralInfo")
    result = cursor.fetchone()
    return result[0]

def getTraceEndTime(dbconnection):
    cursor = dbconnection.cursor()
    cursor.execute("SELECT TraceEnd FROM GeneralInfo")
    result = cursor.fetchone()
    return result[0]

def getNumberOfBanks(dbconnection):
    cursor = dbconnection.cursor()
    cursor.execute("SELECT NumberOfBanks FROM GeneralInfo")
    result = cursor.fetchone()
    return result[0]

def getNumberOfRanks(dbconnection):
    cursor = dbconnection.cursor()
    cursor.execute("SELECT NumberOfRanks FROM GeneralInfo")
    result = cursor.fetchone()
    return result[0]

def getNumberOfBankGroups(dbconnection):
    cursor = dbconnection.cursor()
    cursor.execute("SELECT NumberOfBankGroups FROM GeneralInfo")
    result = cursor.fetchone()
    return result[0]

def getPer2BankOffset(dbconnection):
    cursor = dbconnection.cursor()
    cursor.execute("SELECT Per2BankOffset FROM GeneralInfo")
    result = cursor.fetchone()
    return result[0]

def getWindowSize(connection):
    cursor = connection.cursor()
    cursor.execute("SELECT WindowSize FROM GeneralInfo")
    windowSize = float(cursor.fetchone()[0])
    return windowSize

def getRowColumnCommandBus(connection):
    cursor = connection.cursor()
    cursor.execute("SELECT RowColumnCommandBus FROM GeneralInfo")
    return bool(cursor.fetchone()[0])

def getPseudoChannelMode(connection):
    cursor = connection.cursor()
    cursor.execute("SELECT PseudoChannelMode FROM GeneralInfo")
    return bool(cursor.fetchone()[0])


def maximum_data_rate(connection):
    memspec = MemSpec(connection)    
    try:
        width = memspec.getIntValue("memarchitecturespec", "nbrOfDevices") * memspec.getIntValue("memarchitecturespec", "width")
    except:
        width = memspec.getIntValue("memarchitecturespec", "width")
    clk = memspec.getIntValue("memtimingspec", "clkMhz")
    rate = memspec.getIntValue("memarchitecturespec", "dataRate")
    if getPseudoChannelMode(connection):
        maxDataRate = float(clk) * float(width) * float(rate) * 2
    else:
        maxDataRate = float(clk) * float(width) * float(rate)
    return maxDataRate


def getFlexibleRef(connection):
    cursor = connection.cursor()
    cursor.execute(" SELECT  FlexibleRefresh FROM GeneralInfo ")
    result = cursor.fetchone()
    return result[0]


def getMaxRefBurst(connection):
    cursor = connection.cursor()
    cursor.execute(" SELECT  MaxRefBurst FROM GeneralInfo ")
    result = cursor.fetchone()
    return result[0]


def getControllerThread(connection):
    cursor = connection.cursor()
    cursor.execute("SELECT ControllerThread FROM GeneralInfo")
    result = cursor.fetchone()
    return result[0]


def get_phase_occurrences(connection, phase):
    cursor = connection.cursor()
    query = "SELECT count(*) FROM Phases WHERE PhaseName = :phase"
    cursor.execute(query, {"phase": phase})
    r = cursor.fetchone()
    cnt = r[0]
    if cnt is None:
        cnt = 0
    return cnt


def get_total_time_in_phase(connection, phase):
    cursor = connection.cursor()
    query = "SELECT SUM(PhaseEnd - PhaseBegin) / 1000 FROM Phases WHERE PhaseName = :phase"
    cursor.execute(query, {"phase": phase})
    time = cursor.fetchone()
    totalTime = time[0]
    if totalTime is None:
        totalTime = 0.0
    return totalTime


def getCommandLengthForPhase(connection, phase):
    cursor = connection.cursor()
    cursor.execute("SELECT " + phase + " FROM CommandLengths")
    length = cursor.fetchone()
    return length[0]
