#!/usr/bin/python
import os
import sys
import random
import argparse

import pygame

from core import colors
from core import elements
from core.utils import scale

dbg = True
dbg = False
dbg_detect = False


def main(mapfile=None):
    pygame.init()
    pygame.display.set_caption('RocketPwn')
    mode = (800, 600)
    mode = (1200, 700)
    #mode = (1366, 768)
    FPS = 60

    screen = pygame.display.set_mode(map(int, mode))
    font = pygame.font.Font(None, 30)
    bigfont = pygame.font.Font(None, 60)
    smallfont = pygame.font.Font(None, 20)

    bg = pygame.Surface(mode)
    bg.fill(colors.t)

    win = pygame.Surface(mode)
    win.fill(colors.t)
    wintext = font.render("YOU WIN", 1, colors.g)
    win.blit(wintext, (mode[0] / 2 - wintext.get_rect().width / 2, mode[1] / 2))

    wel = pygame.Surface(mode)
    wel.fill(colors.t)
    weltext = bigfont.render("RocketPwn", 1, colors.g)
    crewtext = font.render("The crew of your triangle vessel went rogue,", 1, colors.g)
    crewtext2 = font.render("you only get one thruster to save your ship!", 1, colors.g)
    keys = font.render("Keys: space to play, q to quit", 1, colors.g)
    timing = smallfont.render("Timing is everything.", 1, colors.g)
    wel.blit(weltext, (mode[0] / 2 - weltext.get_rect().width / 2, mode[1] / 4))
    wel.blit(crewtext, (mode[0] / 2 - crewtext.get_rect().width / 2, mode[1] / 3))
    wel.blit(crewtext2, (mode[0] / 2 - crewtext2.get_rect().width / 2, mode[1] / 3 + crewtext2.get_rect().height))
    wel.blit(keys, (mode[0] / 2 - keys.get_rect().width / 2, mode[1] * 2 / 3))
    wel.blit(timing, (mode[0] / 2 - timing.get_rect().width / 2, mode[1] * 2 / 3 + keys.get_rect().height * 2))

    ui = pygame.sprite.RenderUpdates()
    particles = pygame.sprite.RenderUpdates()

    if not mapfile:
        mapfile = 'lvl/1'

    num_lvl = 1
    l = os.path.split(mapfile)[-1]
    if l.isdigit():
        num_lvl = int(l)

    s = mode[1] - 120
    map_sq = pygame.rect.Rect(mode[0] - (s + 100), 60, s, s)
    pygame.draw.rect(bg, colors.g, map_sq, 3)
    map_sq.move_ip(1, 1)
    tile_size = int(1. * s / 9)
    ship_size = int(tile_size * 2 / 3)
    if dbg:
        print("Tile size: {}".format(tile_size))
        print("Ship size: {}".format(ship_size))

    def load_level(mapfile):
        ships = pygame.sprite.RenderUpdates()
        tiles = pygame.sprite.RenderUpdates()

        if not os.path.isfile(mapfile):
            print('Map {} not found'.format(mapfile))
            mapfile = 'lvl/1'

        with open(mapfile) as f:
            lines = f.readlines()

        _lvl = map(lambda x: x.strip('\n').ljust(9, ' '), lines[1:])
        lvl = ['' for line in _lvl]

        for line in _lvl:
            for i, c in enumerate(line):
                lvl[i] += c
            if dbg:
                print(line)

        for i in range(0, 9):
                for j in range(0, 9):
                    rect = pygame.rect.Rect(map_sq[0] + tile_size * i, map_sq[1] + tile_size * j, tile_size, tile_size)
                    t = elements.Tile(rect, colors.t)

                    if lvl[i][j] == '-':
                        t = elements.Tile(rect, colors.g)
                    if lvl[i][j] == 'b':
                        t = elements.Tile(rect, colors.b)
                    elif lvl[i][j] == 'T':
                        t = elements.Tile(rect, colors.r)
                    elif lvl[i][j] == '>':
                        t = elements.Tile(rect, colors.dr)
                        ship_init = rect.center

                    t.coords = (i, j)
                    tiles.add(t)

        ship = elements.Ship(ship_init, (1, 0), size=ship_size)
        lrect = pygame.rect.Rect(0, 30, map_sq.topleft[0], mode[1])
        dship = elements.Ship((lrect.centerx, lrect.height / 3), (0, 1), color=colors.r, size=ship_size * 2)
        ships.add(ship)
        ships.add(dship)

        return ship, dship, ships, lvl, tiles

    ship, dship, ships, lvl, tiles = load_level(mapfile)

    thrust_progress = elements.Progress((0, 0), (mode[0], 30), colors.g)
    power_progress = elements.Progress((0, mode[1] - 30), (mode[0], 30), colors.dr)
    ui.add(thrust_progress)
    ui.add(power_progress)
    running, moving = True, False
    f_low, f_high = 0.02, 0.03
    # hard?
    # f_low, f_high = 0.01, 0.10

    nextforce = random.uniform(f_low, f_high)
    s_thrust_interval = 4000
    s_thrust_counter = 3000
    s_thrust_duration = 2000
    thrust_interval, thrust_duration = s_thrust_interval, s_thrust_duration
    thrust_counter = s_thrust_counter
    crash_counter, crash_delay = 0, 0
    ticks = 0
    crashed = False
    won = False
    nextlevel = False
    welcome = True

    screen.blit(wel, (0, 0))
    clock = pygame.time.Clock()
    pygame.display.flip()

    while running:
        if dbg_detect:
            print map(lambda (x, y): (round(x, 4), round(y)), [ship.ta, ship.tb, ship.tc])
            print ship.image.get_rect()
            pygame.draw.polygon(
                screen,
                colors.r,
                ship.triangle_points(),
                1)

            pygame.display.flip()

        time_passed = clock.tick(FPS)
        ticks += time_passed
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
                break
            if event.type == pygame.KEYDOWN:
                if event.key in (pygame.K_ESCAPE, pygame.K_q):
                    running = False
                    break

                if welcome:
                    welcome = False
                    screen.blit(bg, (0, 0))
                    pygame.display.flip()
                    break

                if event.key == pygame.K_SPACE:
                    moving = True
                    if won:
                        sys.exit(0)
            if event.type == pygame.KEYUP:
                moving = False
        if dbg:
            print "s=%f f=%f" % (ship.speed, ship.force)
            print "Ship dir:%f head:%f" % (ship.dir.angle, ship.heading.angle)
            print "Ship dir:%s head:%s" % (ship.dir, ship.heading)

        if dbg:
            print 'ticks', ticks
            print 'tp', thrust_counter / thrust_interval
            print 'dt', time_passed

        if crashed:
            if crash_counter >= crash_delay:
                crashed = False
                crash_counter = 0
                ship, dship, ships, lvl, tiles = load_level(mapfile)
                nextforce = random.uniform(f_low, f_high)
                thrust_interval, thrust_duration = s_thrust_interval, s_thrust_duration
                thrust_counter = s_thrust_counter
                screen.blit(bg, (0, 0))
                pygame.display.flip()

            crash_counter += 1
        elif welcome:
            pass
        elif won:
            print 'uu'
        elif nextlevel:
            nextlevel = False
            num_lvl += 1
            if num_lvl == 10:
                won = True
                num_lvl = 1
                screen.blit(win, (0, 0))
            else:
                mapfile = 'lvl/{}'.format(num_lvl)
                ship, dship, ships, lvl, tiles = load_level(mapfile)
                nextforce = random.uniform(f_low, f_high)
                thrust_interval, thrust_duration = s_thrust_interval, s_thrust_duration
                thrust_counter = s_thrust_counter
                screen.blit(bg, (0, 0))

            pygame.display.flip()
        else:
            thrust_counter += time_passed
            if thrust_counter >= thrust_interval:
                ship.force = nextforce
                nextforce = random.uniform(f_low, f_high)
                nextforce = 0.04
                thrust_counter = random.randrange(0, 1000)

            if ship.force > 0:
                ship.force -= 0.0002
                size = int(ship_size * scale(ship.force, 0, f_high, 0.7, 0))
                if size <= 0:
                    size = 1
                particles.add(elements.Particle(
                    (ship.rect.x + ship.te[0], ship.rect.y + ship.te[1]),
                    ship.heading.rotated(180 + random.uniform(0, 1) * 30),
                    colors.r,
                    size=size))

                for p in particles:
                    px, py = p.rect.centerx, p.rect.centery
                    if px < 0 or px > mode[0] or py < 0 or py > mode[1]:
                        particles.remove(p)

            if moving and not crashed:
                ship.rotate(5)
                particles.add(elements.Particle(
                    (ship.rect.x + ship.tt[0], ship.rect.y + ship.tt[1]),
                    ship.heading.rotated(45 + random.uniform(0, 1) * 30),
                    colors.lb,
                    size=10))

            dship.heading = ship.dir

            ships.update(time_passed)
            thrust_progress.update(1. * thrust_counter / thrust_interval)
            if ship.force <= 0:
                power_progress.update(1 - 10. * nextforce)
            else:
                power_progress.update(1 - 10. * ship.force)

            for point in ship.triangle_points():
                if not map_sq.collidepoint(point):
                    crashed = True

                for tile in tiles:
                    if tile.crect.collidepoint(point):
                        c = lvl[tile.coords[0]][tile.coords[1]]
                        if c == '-':
                            crashed = True
                        elif c == 'T':
                            nextlevel = True

                        break

            ui.clear(screen, bg)
            particles.clear(screen, bg)
            particles.update(time_passed)
            tiles.clear(screen, bg)
            ships.clear(screen, bg)
            dirty = ui.draw(screen)
            dirty += tiles.draw(screen)
            dirty += particles.draw(screen)
            dirty += ships.draw(screen)
            pygame.display.update(dirty)


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('-m', '--map', help='map FILE', metavar='FILE')

    args = parser.parse_args()

    main(mapfile=args.map)
