#!/usr/bin/env python3
# -*- python -*-

from enum import IntEnum
from pconst import const

from sony_fpga_driver.dmac_if import PciBar


const.TVSG_ADRS_OFFSET = 0xd000


class TVSGRegAdrs(IntEnum):
    SG_MODE_ADRS = 0x00
    MOVE_ADRS = 0x04
    MATTE_ADRS = 0x10


class RegAccess(IntEnum):
    READ_ONLY = 1
    WRITE = 2
    ABORT = 3


class TVSG:
    def __init__(self, name, gif2=False):
        if gif2:
            self.__io = PciBar("GIF2")
        else:
            self.__io = PciBar("GIF")
        self._name = name
        self._reg_access = RegAccess.ABORT

    def acceptable_ch(self, args):
        if args.c is None:
            print("Not Found: -c")
            return False
        ch_list = args.c

        if len(ch_list) < 1 or 4 < len(ch_list):
            return False
        for ch in ch_list:
            if ch < 1 or 4 < ch:
                return False
        return True

    def acceptable(self, args):
        print("Don't Use")

    def write(self, adrs, val):
        byte_val = val.to_bytes(4, 'little')
        self.__io.write(adrs, byte_val)
        return 0

    def read(self, adrs):
        return self.__io.read(adrs, 4)

    def display(self):
        return self

    def __del__(self):
        return 0


class SG_MODE(TVSG):
    def __init__(self, gif2=False):
        super().__init__('SG_MODE', gif2)
        self.__ADRS = const.TVSG_ADRS_OFFSET \
            + TVSGRegAdrs.SG_MODE_ADRS
        self.__val = 0

    def acceptable(self, args):
        if super().acceptable_ch(args) is not True:
            print(self._name + " illegal value: -c")
            self._reg_access = RegAccess.ABORT
            return self._reg_access
        ch_list = args.c

        if args.t is None:
            self._reg_access = RegAccess.READ_ONLY
            return self._reg_access
        sg = args.t

        if sg < 0x00 or 0x05 < sg:
            print(self._name + " illegal value: -t")
            self._reg_access = RegAccess.ABORT
            return self._reg_access

        val = 0
        mask = 0

        for ch in ch_list:
            mask |= 0b111 << ((ch - 1) * 8)
            val |= (sg & 0b111) << ((ch - 1) * 8)

        mask = int(format(~mask & 0xFFFFFFFF, '08x'), 16)
        self.__val = (self.read() & mask) | val
        self._reg_access = RegAccess.WRITE
        return self._reg_access

    def write(self):
        if self._reg_access == RegAccess.WRITE:
            super().write(self.__ADRS, self.__val)
        return self

    def read(self):
        return super().read(self.__ADRS)

    def display(self):
        print("%s(0x%02X): 0x%08X" % (self._name, self.__ADRS, self.read()))
        return self

    def __del__(self):
        return


class MOVE(TVSG):
    def __init__(self, gif2=False):
        super().__init__('MOVE', gif2)
        self.__ADRS = const.TVSG_ADRS_OFFSET \
            + TVSGRegAdrs.MOVE_ADRS
        self.__val = 0

    def acceptable(self, args):
        if super().acceptable_ch(args) is not True:
            print(self._name + " illegal value: -c")
            self._reg_access = RegAccess.ABORT
            return self._reg_access
        ch_list = args.c

        if args.mv is None and args.mh is None:
            self._reg_access = RegAccess.READ_ONLY
            return self._reg_access

        val = 0
        mask = 0

        if args.mh is not None:
            h = args.mh
            if h < 0x00 or 0x03 < h:
                print(self._name + " illegal value: -mh")
                self._reg_access = RegAccess.ABORT
                return self._reg_access

            for ch in ch_list:
                mask |= 0b11 << ((ch - 1) * 8)
                val |= (h & 0b11) << ((ch - 1) * 8)

        if args.mv is not None:
            v = args.mv
            if v < 0x00 or 0x03 < v:
                print(self._name + " illegal value: -mv")
                self._reg_access = RegAccess.ABORT
                return self._reg_access

            for ch in ch_list:
                mask |= 0b11 << (((ch - 1) * 8) + 4)
                val |= (v & 0b11) << (((ch - 1) * 8) + 4)

        mask = int(format(~mask & 0xFFFFFFFF, '08x'), 16)
        self.__val = (self.read() & mask) | val
        self._reg_access = RegAccess.WRITE
        return self._reg_access

    def write(self):
        if self._reg_access == RegAccess.WRITE:
            super().write(self.__ADRS, self.__val)
        return self

    def read(self):
        return super().read(self.__ADRS)

    def display(self):
        print("%s(0x%02X): 0x%08X" % (self._name, self.__ADRS, self.read()))
        return self

    def __del__(self):
        return 0


class MATTE(TVSG):
    def __init__(self, gif2=False):
        super().__init__('MATTE', gif2)
        self.__ADRS = const.TVSG_ADRS_OFFSET \
            + TVSGRegAdrs.MATTE_ADRS
        self.__val = 0
        self.__ch_list = []

    def acceptable(self, args):
        if super().acceptable_ch(args) is not True:
            print(self._name + " illegal value: -c")
            self._reg_access = RegAccess.ABORT
            return self._reg_access
        ch_list = args.c

        if args.y is None and args.b is None and args.r is None:
            self._reg_access = RegAccess.READ_ONLY
            return self._reg_access

        val = 0
        mask = 0

        if args.y is not None:
            y_sg = args.y
            if y_sg < 0 or 0x3FF < y_sg:
                print(self._name + " illegal value: -y")
                self._reg_access = RegAccess.ABORT
                return self._reg_access
            mask |= 0x3FF
            val |= (y_sg & 0x3FF)

        if args.b is not None:
            b_sg = args.b
            if b_sg < 0 or 0x3FF < b_sg:
                print(self._name + " illegal value: -b")
                self._reg_access = RegAccess.ABORT
                return self._reg_access
            mask |= 0x3FF << 10
            val |= ((b_sg & 0x3FF) << 10)

        if args.r is not None:
            r_sg = args.r
            if r_sg < 0 or 0x3FF < r_sg:
                print(self._name + " illegal value: -r")
                self._reg_access = RegAccess.ABORT
                return self._reg_access
            mask |= 0x3FF << 20
            val |= ((r_sg & 0x3FF) << 20)

        self.__mask = int(format(~mask & 0xFFFFFFFF, '08x'), 16)
        self.__val = val
        self.__ch_list = ch_list
        self._reg_access = RegAccess.WRITE
        return self._reg_access

    def write(self):
        return self
        if self._reg_access == RegAccess.WRITE:
            for ch in self.__ch_list:
                adrs = self.__ADRS + 4 * (ch - 1)
                val = super().read(adrs)
                val = (val & self.__mask) | self.__val
                super().write(adrs, val)
        return self

    def read(self):
        return 0
        val = super().read(self.__ADRS)
        return val

    def display(self):
        return self
        for ch in range(1, 5):
            adrs = self.__ADRS + (ch - 1) * 4
            print("%s(0x%02X): 0x%08X" % (self._name, adrs, super().read(adrs)))
        return self

    def __del__(self):
        return 0
