# Arup Guha
# Started 6/16/2023, last updated 6/21/2023
# Sushi game functions

import random
import math
import time
import pygame, sys
from pygame.locals import *

# Useful Constants
SCREEN_W = 1000
SCREEN_H = 600
DY = 5
DX = 0
WHITE = pygame.Color(255,255,255)
BLUE = pygame.Color(0,0,255)
RED = pygame.Color(255,0,0)

# Returns how many items in sushiList intersect with me and removes them from sushiList.
def numIntersect(sushiList, me):

    i = len(sushiList)-1
    res = 0

    # Go through list backwards.
    while i >= 0:

        # Here is a collision, add 1 to answer and remove from list.
        if rectIntersect(sushiList[i], me):
            res += 1
            sushiList.pop(i)

        # Continue going backwards through the list.
        i-=1

    # Here is our answer.
    return res

def rectIntersect(obj1, obj2):

    # obj1 is to left of obj2 completely.
    if obj1[0]+obj1[4] < obj2[0]:
        return False

    # obj1 is to the right of obj2 completely.
    if obj1[0] > obj2[0]+obj2[4]:
        return False

    # obj1 is above obj2.
    if obj1[1]+obj1[5] < obj2[1]:
        return False

    # obj1 is below obj2.
    if obj1[1] > obj2[1]+obj2[5]:
        return False

    # Must intersect if we're here.
    return True

# This function handles moving each item listed in items.
def move(items):
    for item in items:
        item[0] += item[2]
        item[1] += item[3]

# This function removes all items that will never be visible again.
def removeUseless(items):
    for item in items:
        if item[1] > SCREEN_H:
            items.remove(item)

def draw(text, font, color, surface, x, y):
    # Draw text on a new Surface. Title, antialias and color are used.
    text = font.render(text, 1, color)

    # Returns a new rectangle covering the entire surface.
    # This rectangle will always start at (0, 0) with a width and height the same size as the image.
    textrect = text.get_rect()

    # Sets location of text.
    textrect.topleft = (x, y)

    # Draw one image onto another. Source and destination are passed. Source is textobj and it will be written onto textrect,
    surface.blit(text, textrect)

# Plays the game for player.
def playgame(player):

    # Basic set up.
    pygame.init()
    DISPLAYSURF = pygame.display.set_mode((SCREEN_W, SCREEN_H))
    pygame.display.set_caption("Sushi Game!")
    clock = pygame.time.Clock()

    # Store sushi here....
    sushi = []

    # Store Deetos here.
    detos = []

    myscore = 0
    lives = 2

    # This is the one image we will use.
    sushiPic = pygame.image.load("dangoo.jpg")
    sushiPic = pygame.transform.scale(sushiPic,(100,50))

    # This is what we're avoiding.
    detosPic = pygame.image.load("detosarenogood.png")
    detosPic = pygame.transform.scale(detosPic,(50,50))

    myImage = pygame.image.load("spottedoof.jpg")
    myImage = pygame.transform.scale(myImage,(80,80))
    me = [SCREEN_W/2, SCREEN_H-80, 0, 0, myImage.get_width(), myImage.get_height()]

    # So we know how many frames we've run.
    step = 0

    curT = time.time()

    # Event loop.
    while True:
        
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                sys.exit()


            if event.type == KEYDOWN:
                 if event.key == K_LEFT: #If the left arrow was pressed, then we want our ball to move to the left
                     me[2] -= 4
                     if me[2] > 0:
                         me[2] = 0
                 if event.key == K_RIGHT: #If the right arrow was pressed, then we want our ball to move to the right
                     me[2] += 4
                     if me[2] < 0:
                         me[2] = 0

        # These images are big, so I only add a drop once every 10 time steps.
        if step%50 == 0:
            x = random.randint(1, SCREEN_W)
            sushi.append([x,0,DX,DY, sushiPic.get_width(), sushiPic.get_height()])

            
        # These will be created half as often as the sushi.
        if step%100 == 0:
            x = random.randint(1, SCREEN_W)
            detos.append([x,0,DX,DY, detosPic.get_width(), detosPic.get_height()])
            
         
        DISPLAYSURF.fill(WHITE)

        # blit allows us to draw a surface onto another surface.
        for item in sushi:
            DISPLAYSURF.blit(sushiPic,(item[0], item[1]))

        # blit allows us to draw a surface onto another surface.
        for item in detos:
            DISPLAYSURF.blit(detosPic,(item[0], item[1]))

        DISPLAYSURF.blit(myImage,(me[0], me[1]))

        # Update score, lives.
        myscore += numIntersect(sushi, me)
        lives -= numIntersect(detos, me)
        font = pygame.font.SysFont("Arial", 24)

        # Draw score, lives.
        txtsurf = font.render("Score: "+str(myscore), True, BLUE)
        txtsurf2 = font.render("Lives: "+str(lives), True, RED)
        DISPLAYSURF.blit(txtsurf,( 20 , 20 ))
        DISPLAYSURF.blit(txtsurf2,( 20 , 120 ))

        # Move the drops for the next iteration and remove useless ones.
        move(sushi)
        move(detos)

        # Move me...
        me[0] += me[2]
        if me[2] > 10:
            me[2] -= 1
        elif me[2] < -10:
            me[2] += 1

        # Does the wrap around.
        me[0] = (me[0] + SCREEN_W)%SCREEN_W

        # We have died.
        if lives == 0:

            # Display final score, wait a bit and return.
            txtsurf3 = font.render(player+", you Died. Final Score: "+str(myscore), True, BLUE)
            DISPLAYSURF.blit(txtsurf3,( 20 , 220 ))
            print("You Died. Final Score: "+str(myscore))
            pygame.display.update()
            pygame.time.wait(2000)

            # We return this to the main screen.
            return myscore
            
        pygame.display.update()        
        removeUseless(sushi)
        clock.tick(30)
        step += 1

# Shows the high scores from the file, fileName.
def showhighscores(fileName):

    # Set up.
    pygame.init()
    screen = pygame.display.set_mode((SCREEN_W, SCREEN_H))
    screen.fill(WHITE)
    pygame.display.set_caption("Leaderboard")
    clock = pygame.time.Clock()

    # Open the file with the scores.
    myFile = open(fileName, "r")

    # Read in file contents, store names, scores, assumed to be in order.
    n = int(myFile.readline())
    names = []
    scores = []
    for i in range(n):
        toks = myFile.readline().split()
        names.append(toks[1])
        scores.append(int(toks[0]))
    myFile.close()

    # Game loop...
    while True:

        # Created buttons. X, Y, Width, Height.
        button_1 = pygame.Rect(350, 500, 300, 100)

        # Draws buttons onto screen
        pygame.draw.rect(screen, (192,192,192), button_1)
        font = pygame.font.SysFont(None, 36)
        draw('Return to Main Menu', font, (255, 255, 255), screen, 370, 535)

        # We'll used thiese two fonts as well.
        font = pygame.font.SysFont("Arial", 36)
        font2 = pygame.font.SysFont("Arial", 48)
        txtsurf = font2.render("LEADERBOARD", True, (0,0,0))
        screen.blit(txtsurf, (350, 0))

        # Draw top 10 scores, at most.
        for i in range(0, min(10,n)):
            txtsurf = font.render(str(i+1)+". "+names[i], True, BLUE)
            screen.blit(txtsurf,( 350 , 70+40*i ))
            txtsurf2 = font.render(str(scores[i]), True, BLUE)
            screen.blit(txtsurf2,( 600 , 70+40*i ))

        # Look for events - basically to go back to other screen.
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                sys.exit()

            if event.type == MOUSEBUTTONDOWN:
                # 1 - left click, 2 - middle click, 3 - right click, 4 - scroll up, 5 - scroll down
                if event.button == 1:

                    mx, my = pygame.mouse.get_pos()
                    
                    # We just go back.
                    if button_1.collidepoint((mx, my)):
                        return

        # Update portions of the screen for software displays
        pygame.display.update()

        # Update the clock in milliseconds. Should be called once per frame.
        clock.tick(60)

# This function updates the scores in fileName based on this new entry.
def updateScores(fileName,entry):

    # Open the file with the scores.
    myFile = open(fileName, "r")

    # Read in file contents, store as list of lists...
    n = int(myFile.readline())
    items = []
    scores = []
    for i in range(n):
        toks = myFile.readline().split()
        items.append([int(toks[0]),toks[1]])
    myFile.close()

    # Add this new entry in.
    items.append(entry)

    # Re-sort and reverse.
    items.sort()
    items.reverse()

    # Write everything back out to the file.
    myFile = open(fileName, "w")
    myFile.write(str(n+1)+"\n")
    for i in range(n+1):
        myFile.write(str(items[i][0])+" "+items[i][1]+"\n")
    myFile.close()
    
