#!/usr/bin/python3

from evdev import ecodes, InputDevice
from time import time
from select import select
import os
import sys
import evdev
import subprocess


is_56rc_installed = None


# 5.X
def kernel_version():
    with open("/proc/version") as f:
        proc_version = f.read()
        if 'version 5.3.' in proc_version:
            return 3
        elif 'version 5.6.' in proc_version:
            return 6
        else:
            return None


def check_screen():
    with open("/sys/class/leds/lm36922:white:backlight_cluster/brightness") as ledf:
        state = ledf.read()

    if state[0] == '0':
        print("Screen blank")
        return False
    else:
        print("Screen lit")
        return True


def find_noc_devfreq():
    for node in ['devfreq1', '32700000.noc', '32700000.interconnect']:
        noc = "/sys/class/devfreq/{}".format(node)
        if os.path.isdir(noc):
            break
    return noc


def find_dram_devfreq():
    for node in ['devfreq0', '3d400000.memory-controller']:
        dram = "/sys/class/devfreq/{}".format(node)
        if os.path.isdir(dram):
            break
    return dram


def set_dram_freq(freq):
    with open(os.path.join(find_dram_devfreq(), 'userspace/set_freq'), "w+") as f:
        f.write(freq + "\n")


def get_low_freq_dram():
    if kernel_version() == 3:
        return "100000000"
    else:
        with open(os.path.join(find_dram_devfreq(), 'min_freq')) as f:
            freq = f.read()
            return freq


def is_56_rc_installed():
    global is_56rc_installed
    if is_56rc_installed is not None:
        return is_56rc_installed

    kernel_apt = subprocess.check_output(["uname", "-r"])
    if (b"5.6.0-1" in kernel_apt):
        # 5.6-rc kernel without devfreq interconnect functionality
        is_56rc_installed = True
    else:
        is_56rc_installed = False

    return is_56rc_installed


def maybe_set_dram_freq(freq):
    if supports_powersave_gov():
        return False

    set_dram_freq(freq)
    return True


def supports_powersave_gov():
    if kernel_version() >= 6 and not is_56_rc_installed():
        return True
    else:
        return False


def set_governor(gov):
    with open(os.path.join(find_dram_devfreq(), 'governor'), "w+") as f:
        f.write("%s\n" % gov)

    try:
        with open(os.path.join(find_noc_devfreq(), 'governor'), "w+") as f:
            f.write("%s\n" % gov)
    except IOError:
        # not writable in case the passive governor is (wrongly) in use
        pass


def main(args):
    print("for kernel version 5.%d" % (kernel_version()))

    powerkeyname = '30370000.snvs:snvs-powerkey'
    hi_speed = "800000000"

    path = [path for path in evdev.list_devices() if evdev.InputDevice(path).name == powerkeyname]
    foundpath = ''.join(path)
    dev = InputDevice(foundpath)

    if supports_powersave_gov():
        set_governor("powersave")
    else:
        set_governor("userspace")

    maybe_set_dram_freq(hi_speed)

    power_wait_time = 1.5

    if check_screen():
        blank = False
    else:
        blank = True
        maybe_set_dram_freq(get_low_freq_dram())

    # wait for the key release event so that we can differentiate
    # between long and short press
    state = {}

    while True:
        # Block for a 500ms or until there are events to be read.
        r, _, _ = select([dev], [], [], 0.5)

        if r:
            for event in dev.read():
                if event.type == ecodes.EV_KEY:
                    # When the key is pressed, record its timestamp.
                    if event.value == 1:
                        if event.code == ecodes.KEY_POWER and blank:
                            print("screen wakeup")
                            blank = False
                            maybe_set_dram_freq(hi_speed)
                        else:
                            state[event.code] = event.timestamp(), event
                            print("Key: %s %d %d pressed" % (ecodes.KEY[event.code], event.code, ecodes.KEY_POWER))

                    # When it's released check which key is is
                    if event.value == 0 and event.code in state:
                        delta = time() - event.timestamp()
                        print("Key: %s released %3.2f" % (ecodes.KEY[event.code], delta))
                        if event.code == ecodes.KEY_POWER and delta < power_wait_time:
                            # short power key press blanks the screen so change the DDR freq
                            blank = True
                            maybe_set_dram_freq(get_low_freq_dram())
                            # os.system("systemctl suspend -q")

                        del state[event.code]

        now = time()
        for code, ts_event in list(state.items()):
            ts, event = ts_event
            delta = now - ts
            if code == ecodes.KEY_POWER and delta >= power_wait_time and not blank:
                # power key held for more than power_wait_time shut down the system
                os.system('shutdown -h now')


if __name__ == "__main__":
    sys.exit(main(sys.argv))
