import math
import time
import datetime
from direct.directnotify import DirectNotifyGlobal
from direct.interval.LerpInterval import LerpFunc
from pandac.PandaModules import Vec3
from toontown.toonbase import TTLocalizer
from toontown.toonbase.ToontownTimer import ToontownTimer
from toontown.parties import PartyGlobals
notify = DirectNotifyGlobal.directNotify.newCategory('PartyUtils')

def getNewToontownTimer():
    timer = ToontownTimer()
    timer.hide()
    timer.posInTopRightCorner()
    timer.setColor(1, 1, 1, 0.75)
    return timer


def getPartyActivityIcon(activityIconsModel, activityName):
    activityIconsDict = {'PartyValentineDance': 'tt_t_ara_pty_iconDanceFloorValentine',
     'PartyValentineDance20': 'tt_t_ara_pty_iconDanceFloorValentine',
     'PartyValentineJukebox': 'tt_t_ara_pty_iconJukeboxValentine',
     'PartyValentineJukebox40': 'tt_t_ara_pty_iconJukeboxValentine',
     'PartyValentineTrampoline': 'tt_t_ara_pty_iconTrampolineValentine'}
    iconName = activityIconsDict.get(activityName)
    if iconName:
        icon = activityIconsModel.find('**/%s' % iconName)
    else:
        icon = activityIconsModel.find('**/%sIcon' % activityName)
    if icon.isEmpty():
        icon = activityIconsModel.find('**/PartyClockIcon')
        notify.warning("Couldn't find %sIcon in %s, using PartyClockIcon" % (activityName, activityIconsModel.getName()))
    return icon


def arcPosInterval(duration, object, pos, arcHeight, other):
    startPos = object.getPos()
    endPos = object.getParent().getRelativePoint(other, pos)
    startX = startPos.getX()
    startY = startPos.getY()
    startZ = startPos.getZ()
    dx = endPos.getX() - startPos.getX()
    dy = endPos.getY() - startPos.getY()
    dz = endPos.getZ() - startPos.getZ()

    def setArcPos(t):
        newX = startX + dx * t
        newY = startY + dy * t
        newZ = startZ + dz * t + arcHeight * (-(2.0 * t - 1.0) ** 2 + 1.0)
        object.setPos(newX, newY, newZ)

    return LerpFunc(setArcPos, duration=duration)


def formatDate(year, month, day):
    monthString = TTLocalizer.DateOfBirthEntryMonths[month - 1]
    return TTLocalizer.PartyDateFormat % {'mm': monthString,
     'dd': day,
     'yyyy': year}


def truncateTextOfLabelBasedOnWidth(directGuiObject, textToTruncate, maxWidth):
    text0 = directGuiObject.component('text0')
    tempNode = text0.textNode
    currentText = textToTruncate[:]
    scale = text0.getScale()[0]
    width = tempNode.calcWidth(currentText) * scale
    while width > maxWidth:
        currentText = currentText[:-1]
        width = tempNode.calcWidth(currentText) * scale

    directGuiObject['text'] = currentText
    if directGuiObject['text'] != textToTruncate:
        directGuiObject['text'] = '%s...' % directGuiObject['text']


def truncateTextOfLabelBasedOnMaxLetters(directGuiObject, textToTruncate, maxLetters):
    curStr = directGuiObject['text']
    if maxLetters < len(curStr):
        curStr = curStr[:maxLetters]
        curStr += '...'
        directGuiObject['text'] = curStr


def scaleTextOfGuiObjectBasedOnWidth(directGuiObject, textToScale, maxWidth):
    width = directGuiObject.getWidth()
    scale = 0.01
    while width > maxWidth:
        directGuiObject['text_scale'] = scale
        directGuiObject.resetFrameSize()
        width = directGuiObject.getWidth()
        scale += 0.005


def formatTime(hour, minute):
    meridiemString = TTLocalizer.PartyTimeFormatMeridiemAM
    if hour == 0:
        hour = 12
    elif hour > 11:
        meridiemString = TTLocalizer.PartyTimeFormatMeridiemPM
    if hour > 12:
        hour -= 12
    return TTLocalizer.PartyTimeFormat % (hour, minute, meridiemString)


SecondsInOneDay = 60 * 60 * 24

def getTimeDeltaInSeconds(td):
    result = td.days * SecondsInOneDay + td.seconds + td.microseconds / 1000000.0
    return result


def formatDateTime(dateTimeToShow, inLocalTime = False):
    if inLocalTime:
        curServerTime = base.cr.toontownTimeManager.getCurServerDateTime()
        ltime = time.localtime()
        localTime = datetime.datetime(year=ltime.tm_year, month=ltime.tm_mon, day=ltime.tm_mday, hour=ltime.tm_hour, minute=ltime.tm_min, second=ltime.tm_sec)
        naiveServerTime = curServerTime.replace(tzinfo=None)
        newTimeDelta = localTime - naiveServerTime
        localDifference = getTimeDeltaInSeconds(newTimeDelta)
        dateTimeToShow = dateTimeToShow + datetime.timedelta(seconds=localDifference)
        return '%s %s' % (formatDate(dateTimeToShow.year, dateTimeToShow.month, dateTimeToShow.day), formatTime(dateTimeToShow.hour, dateTimeToShow.minute))
    else:
        return '%s %s' % (formatDate(dateTimeToShow.year, dateTimeToShow.month, dateTimeToShow.day), formatTime(dateTimeToShow.hour, dateTimeToShow.minute))
    return


def convertDistanceToPartyGrid(d, index):
    return int((d - PartyGlobals.PartyGridToPandaOffset[index]) / PartyGlobals.PartyGridUnitLength[index])


def convertDistanceFromPartyGrid(d, index):
    return d * PartyGlobals.PartyGridUnitLength[index] + PartyGlobals.PartyGridToPandaOffset[index] + PartyGlobals.PartyGridUnitLength[index] / 2.0


def convertDegreesToPartyGrid(h):
    while h < 0.0:
        h = h + 360.0

    h = h % 360.0
    return int(h / PartyGlobals.PartyGridHeadingConverter)


def convertDegreesFromPartyGrid(h):
    return h * PartyGlobals.PartyGridHeadingConverter


def getCenterPosFromGridSize(x, y, gridsize):
    if gridsize[0] % 2 == 0:
        xMod = PartyGlobals.PartyGridUnitLength[0] / 2.0
    else:
        xMod = 0
    if gridsize[1] % 2 == 0:
        yMod = PartyGlobals.PartyGridUnitLength[1] / 2.0
    else:
        yMod = 0
    return (x + xMod, y + yMod)


def toRadians(angle):
    return angle * math.pi / 180.0


def toDegrees(angle):
    return angle * 180.0 / math.pi


def calcVelocity(rotation, angle, initialVelocity = 1.0):
    horizVel = initialVelocity * math.cos(angle)
    xVel = horizVel * -math.sin(rotation)
    yVel = horizVel * math.cos(rotation)
    zVel = initialVelocity * math.sin(angle)
    return Vec3(xVel, yVel, zVel)


class LineSegment:

    def __init__(self, pt1, pt2):
        self.pt1 = pt1
        self.pt2 = pt2

    def isIntersecting(self, line, compare = None):
        x1 = self.pt1.getX()
        x2 = self.pt2.getX()
        x3 = line.pt1.getX()
        x4 = line.pt2.getX()
        y1 = self.pt1.getY()
        y2 = self.pt2.getY()
        y3 = line.pt1.getY()
        y4 = line.pt2.getY()
        top1 = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)
        top2 = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)
        bot = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1)
        if bot == 0.0:
            return False
        u1 = top1 / bot
        u2 = top2 / bot
        if compare is None:
            return 0 <= u1 and u1 <= 1 and 0 <= u2 and u2 <= 1
        elif compare == 'segment-ray':
            return 0 <= u1 and u1 <= 1 and 0 <= u2
        elif compare == 'ray-ray':
            return 0 <= u1 and 0 <= u2
        elif compare == 'ray-segment':
            return 0 <= u1 and 0 <= u2 and u2 <= 1
        return