'''
Created on 12-Jul-2021

@author: bthakur
'''
import random
import inspect
import traceback
import re
import operator
import datetime
import calendar
from time import time, ctime

from sympy import (symbols, latex, simplify, Eq,
                   pi,
                   sin, cos, tan,
                   csc, sec, cot
                   )
from sympy.abc import theta
import sympy

from xv.km.util import latex_fraction, latex_exponent, wrap_bracket
from xv.km.ui import SvgHelper

class CustomTime:
    def __init__(self, h = 0, m = 0, s = 0, **kwargs):
        self.verbose = kwargs.get('verbose', False)
        self.h = h
        self.m = m
        self.s = s
        self.twelve_hr_format = self._init_twelve_hr_format()
        pass
    
    def _init_twelve_hr_format(self):
        h = self.h
        if h < 12:
            ampm = "AM"
        else:
            if h !=  12:
                h = h - 12
            ampm = "PM"
            
        s = f"{h:02d}:{self.m:02d}:{self.s:02d} {ampm}"
        return s
    
    def get_12_hr_explanation(self):
        stmts = []
        h = self.h
        if h < 12:
            stmts.append(f"As hour = {h} is less than 12, we write time as AM.")
        else:
            if h ==  12:
                stmts.append(f"As hour is 12, we write time as PM.")
            else:
                stmts.append(f"As hour = {h} is more than 12, we write time as PM and deduct 12 from hours.")
                pass
            pass
        stmts = "\n".join(stmts)
        return stmts
        pass
    
    def get_24_hr_explanation(self):
        stmts = []
        h = self.h
        if h < 12:
            stmts.append(f"As time is AM, both formats have same values.")
        else:
            if h ==  12:
                stmts.append(f"As hour is 12, both formats have same values.")
            else:
                stmts.append(f"As time is PM and hour not 12, we add 12 in hours.")
                pass
            pass
        
        stmts = "\n".join(stmts)
        return stmts
        pass


    def get_delta(self, other):
        t0 = other
        t1 = self
        h = t1.h - t0.h
        m = t1.m - t0.m
        s = t1.s - t0.s
        return (h, m, s)

    def get_delta_str(self, other):
        delta = self.get_delta(other)
        return self.to_delta_str(delta)
    
    def to_delta_str(self, delta):
        s = []
        if delta[0] != 0:
            s.append(f"{delta[0]:02d} hours")
            
        if delta[1] != 0:
            s.append(f"{delta[1]:02d} minutes")
            
        if delta[2] != 0:
            s.append(f"{delta[2]:02d} seconds")
            
        s = " ".join(s)
        return s.strip()
    
    def add_delta(self, h = 0, m = 0, s = 0):
        return self.h + h, self.m + m, self.s + s


    def to_valid_format(self, with_statement = False):
        t, stmts = self._to_valid_format()
        if with_statement:
            return t, stmts
        return t

    def _to_valid_format(self):
        stmts = []
        s = self.s
        m = self.m
        h = self.h

        if s < 0:
            stmt = f"{h} hours <b>{m} minutes {s} seconds</b>"
            m_int = abs(s) // 60
            m = m - m_int - 1
            s = 60 - abs(s) % 60
            stmts.append(f"{stmt} = {h} hours <b>{m} minutes {s} seconds</b>")
            pass

        if s >= 60:
            stmt = f"{h} hours <b>{m} minutes {s} seconds</b>"
            m = m + s // 60
            s = s % 60
            stmts.append(f"{stmt} = {h} hours <b>{m} minutes {s} seconds</b>")
            pass
        
        
        if m < 0:
            stmt = f"<b>{h} hours {m} minutes</b> {s} seconds"
            h_int = abs(m) // 60
            h = h - h_int - 1
            m = 60 - abs(m) % 60
            stmts.append(f"{stmt} = <b>{h} hours {m} minutes</b> {s} seconds")
            pass
        
        
        if m >= 60:
            stmt = f"<b>{h} hours {m} minutes</b> {s} seconds"
            h = h + m // 60
            m = m % 60
            stmts.append(f"{stmt} = <b>{h} hours {m} minutes</b> {s} seconds")
            pass

        stmts = "\n".join(stmts)
        return CustomTime(h = h, m = m, s = s), stmts
        pass

    def __add__(self, other):
        s = self.s + other.s
        m = self.m + other.m
        h = self.h + other.h
        t = CustomTime(h = h, m = m, s = s)
        return t.to_valid_format()
        
    
    def __sub__(self, other):
        if self >= other:
            t1 = self
            t0 = other
        else:
            t0 = self
            t1 = other
            pass

        h = t1.h - t0.h
        m = t1.m - t0.m
        s = t1.s - t0.s

        t = CustomTime(h = h, m = m, s = s)
        return t.to_valid_format()
        
    def __le__(self, other):
        if self > other:
            return False
        return True
        
    def __lt__(self, other):
        if self >= other:
            return False
        return True
        
    def __ge__(self, other):
        if self == other:
            return True
        
        if self > other:
            return True
        return False
        
    def __gt__(self, other):
        if self.h > other.h:
            return True
        
        if self.h < other.h:
            return False
        
        if self.m > other.m:
            return True
         
        if self.m < other.m:
            return False
         
        if self.s > other.s:
            return True
        
        return False
    
    def __eq__(self, other):
        if self.h != other.h:
            return False
        
        if self.m != other.m:
            return False
         
        if self.s != other.s:
            return False
        return True
    
    def __str__(self):
        s = f"{self.h:02d}:{self.m:02d}:{self.s:02d} hours"
        return s
        pass
       
    pass

class TimeHelper:
    def __init__(self, **kwargs):
        self.verbose = kwargs.get('verbose', False)
        pass

    def get_random_hms(self):
        while True:
            h = random.choice([0, random.randint(0, 24 - 1)])
            m = random.choice([0, random.randint(0, 60 - 1)])
            s = random.choice([0, random.randint(0, 60 - 1)])
            if h + m + s > 0:
                break
        return h, m, s
        pass

    def to_hms_str(self, delta):
        s = []
        if delta[0] != 0:
            s.append(f"{delta[0]:02d} hours")
            
        if delta[1] != 0:
            s.append(f"{delta[1]:02d} minutes")
            
        if delta[2] != 0:
            s.append(f"{delta[2]:02d} seconds")
            
        s = " ".join(s)
        return s.strip()
    
        
    def get_random_custom_time(self):
        t = CustomTime(
            h = random.randint(0, 23),
            m = random.randint(0, 23),
            s = random.randint(0, 23),
            )
        return t
        pass
        
        
        
        
    def get_custom_time(self, h = 0, m = 0, s = 0):
        t = CustomTime(h = h, m = m, s = s)
        return t
        pass
        
    def delta_to_valid_time_format(self, h = 0, m = 0, s = 0):
        t = CustomTime(h = h, m = m, s = s)
        t, stmts = t.to_valid_format(with_statement = True)
        return t, stmts
        pass
        
    def draw_12_hr_analogue_clock(self, hours, minutes = 0, seconds = 0, **kwargs):
        '''
        Optional parameters:
        show_needles = ['h', 'm', 's']
        '''

        show_needles = kwargs.get('show_needles', None)
        if show_needles is None:
            show_needles = ['h', 'm', 's']
        
        
        import matplotlib.pyplot as plt
        import numpy as np
    
        zero_angle = np.pi / 2
        angles = - np.linspace(0, 2 * np.pi, 100)  + zero_angle
    
        r = 1
        ax = plt.gca()
    
        ax.plot(r * 1.2 * np.cos(angles), r * 1.2 * np.sin(angles), color = 'lightblue')
        ax.plot(r * np.cos(angles), r * np.sin(angles), color = 'lightblue')


        #60 divisions
        angles_60 = np.linspace(0, 2 * np.pi, 61) + zero_angle
        dial_r = 0.95
        for angle_idx, angle in enumerate(angles_60):
            ax.plot((dial_r * np.cos(angle), r * np.cos(angle)), 
                    (dial_r * np.sin(angle), r * np.sin(angle)),
                     color = 'grey'
                    )
    
        #12 divisions    
        angles_12 = np.linspace(0, 2 * np.pi, 13) + zero_angle
        dial_r = 0.9
        for angle_idx, angle in enumerate(angles_12):
            if angle_idx != 12:
                text_x = r * 1.1 * np.cos(angle) - abs(0.05 *  np.cos(angle) )
                text_y = r * 1.1 * np.sin(angle) - abs(0.05 *  np.sin(angle) )
    
                if 'h' in show_needles:
                    dial_label = 12 - angle_idx
                else:
                    dial_label = (12 - angle_idx) * 5
                    
                if dial_label == 60:
                    dial_label = 0
                    
                dial_label = f"{dial_label}"
                ax.text(text_x, text_y, dial_label, color = 'blue')
                pass
    
            ax.plot((dial_r * np.cos(angle), r * np.cos(angle)), 
                    (dial_r * np.sin(angle), r * np.sin(angle)),
                    color = 'lightblue'
                   )
    

    
    
        seconds_angle = - (2 * np.pi / 60) * seconds + zero_angle
        seconds_r = 0.85
        
        minutes_angle = - (2 * np.pi / 60) * (minutes + seconds / 60) + zero_angle
        minutes_r = 0.7
        
        hours_angle = - (2 * np.pi / 12) * (hours + minutes / 60) + zero_angle
        hours_r = 0.6
        
    
        if 'h' in show_needles:
            ax.plot((-0.2 * np.cos(hours_angle), hours_r * np.cos(hours_angle)), 
                    (-0.2 * np.sin(hours_angle), hours_r * np.sin(hours_angle)),
                    color = 'blue', 
                    linewidth = "6"
                   )

        if 'm' in show_needles:
            ax.plot((-0.2 * np.cos(minutes_angle), minutes_r * np.cos(minutes_angle)), 
                    (-0.2 * np.sin(minutes_angle), minutes_r * np.sin(minutes_angle)),
                    color = 'green', 
                    linewidth = "4"
                   )
    
        if 's' in show_needles:
            ax.plot((-0.2 * np.cos(seconds_angle), seconds_r * np.cos(seconds_angle)), 
                    (-0.2 * np.sin(seconds_angle), seconds_r * np.sin(seconds_angle)),
                    color = 'red', 
                    linewidth = "1"
                   )
    
        ax.plot(0, 0, marker='o', color = 'grey', markersize = 10)
    
        ax.set_aspect('equal', adjustable='box')
        ax.set_axis_off()
        
        svg_str = SvgHelper.GET_SVG_STR(close_plot = True)

        return svg_str
        pass
    
    pass
#class TimeHelper:
