#  =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#   Copyright 2020-2021 <NAME>
#  #
#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#  #
#       http://www.apache.org/licenses/LICENSE-2.0
#  #
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.
#  =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
from __future__ import annotations
from empire.core import *


class Tristate:
    def __init__(self, val: Union[bool, None] = False):
        self._val: Union[bool, None] = val

    def set_true(self):
        self._val = True

    def set_false(self):
        self._val = False

    def set_indeterminate(self):
        self._val = None

    def __bool__(self) -> bool:
        return self._val is True

    def __and__(self, other: Union[bool, None, Tristate]) -> Tristate:
        if isinstance(other, bool):
            return Tristate(self._val & other)
        elif (isinstance(other, Tristate) and other._val is None) or other is None:
            return Tristate()
        elif isinstance(other, Tristate):
            return Tristate(self._val & other._val)
        else:
            raise TypeError('Unsupported type: ' + str(type(other)))
    
    def __eq__(self, other: Union[bool, None, Tristate]) -> bool:
        if isinstance(other, Tristate):
            return self._val == other._val
        else:
            return self._val == other

    def __ne__(self, other) -> bool:
        return not (self == other)

    def __hash__(self):
        return hash((self._val, id(self)))

    def __iand__(self, other: Union[bool, Tristate]) -> Tristate:
        if isinstance(other, bool):
            self._val &= other
        elif (isinstance(other, Tristate) and other._val is None) or other is None:
            self._val = None
        elif isinstance(other, Tristate):
            self._val &= other._val
        else:
            raise TypeError('Unsupported type: ' + str(type(other)))
        return self

    def __int__(self) -> int:
        if self._val is True:
            return 1
        elif self._val is False:
            return 0
        else:
            return -1

    def __invert__(self):
        if self._val is not None:
            self._val = ~self._val

    def __ior__(self, other: Union[bool, Tristate]) -> Tristate:
        if isinstance(other, bool):
            self._val |= other
        elif (isinstance(other, Tristate) and other._val is None) or other is None:
            self._val = None
        elif isinstance(other, Tristate):
            self._val |= other._val
        else:
            raise TypeError('Unsupported type: ' + str(type(other)))
        return self

    def __ixor__(self, other: Union[bool, Tristate]) -> Tristate:
        if isinstance(other, bool):
            self._val ^= other
        elif (isinstance(other, Tristate) and other._val is None) or other is None:
            self._val = None
        elif isinstance(other, Tristate):
            self._val ^= other._val
        else:
            raise TypeError('Unsupported type: ' + str(type(other)))
        return self

    def __or__(self, other: Union[bool, None, Tristate]) -> Tristate:
        if isinstance(other, bool):
            return Tristate(self._val | other)
        elif (isinstance(other, Tristate) and other._val is None) or other is None:
            return Tristate()
        elif isinstance(other, Tristate):
            return Tristate(self._val | other._val)
        else:
            raise TypeError('Unsupported type: ' + str(type(other)))

    def __repr__(self) -> str:
        if self._val is True:
            return 'True'
        elif self._val is False:
            return 'False'
        else:
            return 'None'

    def __str__(self) -> str:
        if self._val is True:
            return 'True'
        elif self._val is False:
            return 'False'
        else:
            return 'Indeterminate'

    def __xor__(self, other: Union[bool, None, Tristate]) -> Tristate:
        if isinstance(other, bool):
            return Tristate(self._val ^ other)
        elif (isinstance(other, Tristate) and other._val is None) or other is None:
            return Tristate()
        elif isinstance(other, Tristate):
            return Tristate(self._val ^ other._val)
        else:
            raise TypeError('Unsupported type: ' + str(type(other)))


if __name__ == '__main__':
    ts = Tristate()
    print(ts & None)

