# Arup Guha
# 5/31/2024
# Token Class to be used as a base class for pyGame objects.

import random
import math
import time
import pygame, sys
from pygame.locals import *

# Useful Constants
SCREEN_W = 1000
SCREEN_H = 600
BALL_D = 30
NUM_BALLS = 10

# Token Class we'll use for drawing objects in pyGame
class token:

    # Default settings.
    x = 0
    y = 0
    dx = 0
    dy = 0
    side = 0
    color = pygame.Color(0,0,255)

    # Constructor.
    def __init__(self,myx,myy,mydx,mydy,myside,mycolor):
        self.x = myx
        self.y = myy
        self.dx = mydx
        self.dy = mydy
        self.side = myside
        self.color = mycolor

    # Call each frame.
    def move(self):
        self.x += self.dx
        self.y += self.dy

    # Executes updating dx as necessary for bouncing off the left wall.
    def bounceLeft(self):
        if self.x + self.dx < 0:
            self.dx = -self.dx

    # Executes updating dx as necessary for bouncing off the right wall.
    def bounceRight(self, SCREEN_W):
        if self.x + self.dx > SCREEN_W-self.side:
            self.dx = -self.dx

    # Executes updating y as necessary for bouncing off the top wall.
    def bounceUp(self):
        if self.y + self.dy < 0:
            self.dy = -self.dy

    # Executes updating y as necessary for bouncing off the bottom wall.
    def bounceDown(self, SCREEN_H):
        if self.y + self.dy > SCREEN_H-self.side:
            self.dy = -self.dy

    # Update for a single frame. Maybe this will typically be overridden.
    def updateFrame(self, DISPLAYSURF):
        self.move()
        self.bounceLeft()
        self.bounceRight(DISPLAYSURF.get_width())
        self.bounceUp()
        self.bounceDown(DISPLAYSURF.get_height())
        self.draw(DISPLAYSURF)

    # Draws this object on the display surface as a circle.
    # Likely to be overridden most of the time.
    def draw(self, DISPLAYSURF):
        pygame.draw.ellipse(DISPLAYSURF, self.color, (self.x, self.y, self.side, self.side), 0)

    # Returns true iff the two circles represented by self and other intersect.
    # Should be overridden for different objects.
    def collide(self, other):

        # I know these aren't the centers, but this difference is the same as the
        # difference of the x and y coordinates of the centers.
        center_dx = self.x - other.x
        center_dy = self.y - other.y
        dist_sq = center_dx*center_dx + center_dy*center_dy
        dist_sq_radii = (self.side//2 + other.side//2)*(self.side//2 + other.side//2)
        return dist_sq <= dist_sq_radii

# This function handles moving each item listed in items.
def move(items):
    for item in items:
        item.move()

# Returns a random integer in between low and high not equal to 0.
def myrand(low,high):
    res = 0
    while res == 0:
        res = random.randint(low, high)
    return res

def main():

    # Basic Set Up
    pygame.init()
    DISPLAYSURF = pygame.display.set_mode((SCREEN_W, SCREEN_H))
    pygame.display.set_caption("Object Oriented Bouncing")
    WHITE = pygame.Color(255,255,255)
    BLUE = pygame.Color(0,0,255)
    clock = pygame.time.Clock()

    curT = time.time()

    # Make NUM_BALLS random tokens.
    mytokens = []
    for i in range(NUM_BALLS):

        # Somewhere on the screen.
        x = random.randint(1, SCREEN_W-BALL_D)
        y = random.randint(1, SCREEN_H-BALL_D)

        # Random non-zero movement in both directions.
        dx = myrand(-2,2)
        dy = myrand(-2,2)
        mytokens.append(token(x,y,dx,dy,BALL_D,BLUE))
        
    # Game loop.
    while True:

        # Look for events - we aren't using this right now.
        for event in pygame.event.get():
            
            if event.type == QUIT:
                pygame.quit()
                sys.exit()

        # White background.
        DISPLAYSURF.fill(WHITE)

        # Essentially update each ball.
        for item in mytokens:
            item.updateFrame(DISPLAYSURF)

        # Just testing collision code.
        for i in range(len(mytokens)):
            for j in range(i+1, len(mytokens)):
                if mytokens[i].collide(mytokens[j]):
                    print("collide",i,j)
            
        # Update what we put on the canvas.
        pygame.display.update()

        # Wait a bit!
        clock.tick(100)

# Run it
main()
