'''
Created on 01-Jun-2021

@author: bthakur
'''
from sympy import symbols, Rational, latex, oo
from xv.util import toIntOrFloat
from xv.km.util import (
                     latex_fraction,
                     )


class ExpExpression():
    '''
    a ** b
    '''
    def __init__(self, n1, n2):
        if n1 == 0 and n2 <= 0:
            raise Exception("ExpExpression: Zero cannot be raised to zero or a negative power")

        if n1 == oo and n2 == oo:
            raise Exception("ExpExpression: Infinity raised to an infinite power is indeterminate.")

        if n1 == oo and n2 == 0:
            raise Exception("ExpExpression: Infinity raised to zero power is indeterminate.")

        self.n1 = n1
        self.n2 = n2
        pass


    def value(self):
        return self.n1 ** self.n2
        pass

    def simplified_value(self):
        if self.n2 < 0:
            return Rational(1, self.n1 ** (0-self.n2))
        return self.n1 ** self.n2
        pass


    def getRelationExpression(self, other):
        if self.value() == other.value():
            op = "="
        elif self.value() > other.value():
            op = ">"
        else:
            op = "<"
        return op
        pass

    def get_latex_expr(self,
                       inverse_format = False,
                       net_sign_format = False,
                       _net_sign_format_with_inverse = False):

        if _net_sign_format_with_inverse:
            return self._net_sign_latex_expr_with_inverse()

        if inverse_format and self.has_inverse_format():
            return self._inverse_latex_expr()
            pass

        if net_sign_format and self.has_net_sign_format():
            return self._net_sign_latex_expr()
            pass

        return self._get_plane_latex()
        pass


    def _get_plane_latex(self):
        if self.n1 < 1:
            return f"{{\\left({latex(self.n1)}\\right)}}^{{{latex(self.n2)}}}"


        return f"{{{latex(self.n1)}}}^{{{latex(self.n2)}}}"


    def _inverse_latex_expr(self):
        if self.has_inverse_format():
            if self.n1 < 0:
                expr = f""" {{\\left({self.n1}\\right)}}^{{{0-self.n2}}} """
            else:
                expr = f""" {{{self.n1}}}^{{{0-self.n2}}} """

            return latex_fraction(1, expr)
        return None
        pass

    def _net_sign_latex_expr(self):
        if not self.has_net_sign_format():
            return None

        expr = f"{{{abs(self.n1)}}}^{{{self.n2}}}"
        if self.value() < 0:
            return f"- ({expr})"
        else:
            return expr
        pass

    def _net_sign_latex_expr_with_inverse(self):

        if not (self.has_inverse_format() or
                self.has_net_sign_format()):
            return self._get_plane_latex()
            pass

        if not self.has_inverse_format():
            return self._net_sign_latex_expr()
            pass

        expr = f""" {{{abs(self.n1)}}}^{{{0-self.n2}}} """
        expr =  latex_fraction(1, expr)

        if self.value() < 0:
            return f"- ({expr})"
        else:
            return expr

        pass


    def get_net_sign_comment(self):
        implies = symbols(u'\U000021D2')
        if not self.has_net_sign_format():
            return ""

        if self.n2 % 2 == 0:
            expr = f"""
            Even power of a negative number gives a positive number
            ${implies}{{(-)}}^{{{self.n2}}} = 1$
            """
        else:
            expr = f"""
            Odd power of a negative number gives a negative number
            ${implies}{{(-)}}^{{{self.n2}}} = -1$
            """

        return expr.strip()
        pass


    def toIntOrFloat(self, roundoff = 4):
        return toIntOrFloat(self.n1 ** self.n2, roundoff = roundoff)
        pass

    def has_inverse_format(self):
        if self.n2 < 0:
            return True
        return False

    def has_net_sign_format(self):
        if self.n1 < 0:
            return True
        return False

    def getInequalityStatement(self, other, self_expr, other_expr,
                               equal_rule = True,
                               positive_negative_rule = True,
                               one_rule = True,
                               simplified_values = True
                               ):
        implies = symbols(u'\U000021D2')

        if equal_rule and self.value() == other.value():
            expr = f"""
            ${implies} {self_expr}  \\quad = \\quad  {other_expr}$
            """
            return expr.strip()

        if positive_negative_rule and (
            not self.hasSameSign(other)):
            if self.value() > other.value():
                expr = f"""
                ${implies} {self_expr}  \\quad > \\quad  {other_expr}$ \t Positive number > Negative number
                """
            if self.value() < other.value():
                expr = f"""
                ${implies} {self_expr}  \\quad < \\quad  {other_expr}$ \t Negative number < Positive number
                """
            return expr.strip()

        if one_rule:
            if self.value() < 1 and other.value() == 1:
                expr = f"""
                ${implies}$ less than 1  \t ? \t  1

                ${implies}$ less than 1  \t < \t  1
                """
                return expr.strip()

            if self.value() < 1 and other.value() > 1:
                expr = f"""
                ${implies}$ less than 1  \t ? \t  greater than 1

                ${implies}$ less than 1  \t < \t  greater than 1
                """
                return expr.strip()

            if self.value() == 1 and other.value() < 1:
                expr = f"""
                ${implies}$ 1 \t ? \t  less than 1

                ${implies}$ 1 \t > \t  less than 1
                """
                return expr.strip()

            if self.value() > 1 and other.value() < 1:
                expr = f"""
                ${implies}$ greater than 1  \t ? \t  less than 1

                ${implies}$ greater than 1  \t > \t  less than 1
                """
                return expr.strip()

        if simplified_values:
            v1 = self.simplified_value()
            v2 = other.simplified_value()
            expr = f"""
            ${implies} {v1} \\quad \\text{{ ? }} \\quad {v2}$

            ${implies} {v1}$  \t {self.getRelationExpression(other)} \t  ${v2}$
            """
            return expr.strip()


        return None
        pass

    def hasSameSign(self, other):
        if self.value() > 0 and other.value() > 0:
            return True

        if self.value() < 0 and other.value() < 0:
            return True

        return False
        pass


    pass

