"""
Match script, useful for public matches. Features verbose announcements
on IRC and a custom timer.

Maintainer: mat^2

edited by thepolm3
"""
from commands import add, admin, name, get_team
from twisted.internet import reactor
from twisted.internet.task import LoopingCall

import json
import commands

COMMAND_POS=None

@admin
@name('timer')
def start_timer(connection, end):
    return connection.protocol.start_timer(int(end)*60)

@admin
@name("final")
def final_timer(connection, end):
    connection.protocol.final=True
    return connection.protocol.start_timer(int(end)*60)
@admin
@name('stoptimer')
def stop_timer(connection):
    return connection.protocol.stop_timer()

@admin
@name('startrecord')
def start_record(connection):
    connection.protocol.start_record()
    return 'Recording started.'

@admin
@name('stoprecord')
def stop_record(connection):
    connection.protocol.stop_record()
    return 'Recording stopped.'

@admin
@name('saverecord')
def save_record(connection, value):
    if not connection.protocol.save_record(value):
        return 'No record file available.'
    return 'Record saved.'

add(start_timer)
add(final_timer)
add(stop_timer)
add(start_record)
add(stop_record)
add(save_record)

def apply_script(protocol, connection, config):
    class MatchConnection(connection):

        def drop_flag(self):
            connection.drop_flag(self)
            if self.team.other.flag.z >=63:
                self.team.other.flag.set(*self.team.other.get_random_location(True))
                self.team.other.flag.update()

        def on_flag_take(self):
            if not self.protocol.timer_end:
                return False
            self.add_message("%s took %s's flag!" %
                (self.printable_name, self.team.other.name.lower()))
            return connection.on_flag_take(self)
        
        def on_flag_drop(self):
            self.add_message("%s dropped %s's flag!" %
                (self.printable_name, self.team.other.name.lower()))
            return connection.on_flag_drop(self)
                
        def on_flag_capture(self):
            self.add_message("%s captured %s's flag!" %
                (self.printable_name, self.team.other.name.lower()))
            return connection.on_flag_capture(self)

        def on_line_build_attempt(self, points):
            if self.protocol.timer_end:
                return connection.on_line_build_attempt(self,points)
            return False

        def on_block_build_attempt(self, x, y, z):
            if self.protocol.timer_end:
                return connection.on_block_build_attempt(self,x,y,z)
            return False

        def on_block_destroy(self, x, y, z,value):
            if self.protocol.timer_end:
                return connection.on_block_destroy(self,x,y,z,value)
            return False

        def on_command(self,command,parameters):
            if self.protocol.timer_end:
                time = self.protocol.timer_end - reactor.seconds()
                minutes_left = int(time / 60.0)
                seconds_left = int(time % 60)
                if command=="time":
                    self.send_chat("%d minutes, %d seconds" %(minutes_left,seconds_left))
                    return False
            return connection.on_command(self,command,parameters)

        def on_chat(self,chat,global_message):
            time = self.protocol.timer_end - reactor.seconds()
            if time:
                if time>0 and global_message and not self.admin:
                    self.send_chat("global messages are disabled")
                    return False
            return connection.on_chat(self,chat,global_message)

        def on_kill(self, killer, type, grenade):
            if not self.protocol.timer_end:
                if killer==self or killer==None:
                    return connection.on_kill(self,killer,type,grenade)
                return False
            if killer is None:
                killer = self
            self.add_message("%s was killed by %s!" %
                (self.printable_name, killer.printable_name))
            self.protocol.add_kill(self, killer)
            return connection.on_kill(self, killer, type, grenade)

        def add_message(self, value):
            self.protocol.messages.append(value)
    
    class MatchProtocol(protocol):
        timer_left = None
        timer_call = None
        timer_end = None
        record = None
        final=False
        blue_command=(0,0,0)
        green_command=(0,0,0)
                
            
        def __init__(self, *arg, **kw):
            protocol.__init__(self, *arg, **kw)
            self.messages = []
            self.send_message_loop = LoopingCall(self.display_messages)
            self.send_message_loop.start(3)
            
        def start_timer(self, end):
            if self.timer_end is not None:
                return 'Timer is running already.'
            self.timer_end = reactor.seconds() + end
            if end/60==1:
                unit="minute"
                end/=60
            elif end/60>1:
                unit="minutes"
                end/=60
            else:
                unit="seconds"
            self.send_chat('Timer started, ending in %d %s' % (end,unit),
                irc = True)
            self.display_timer(True)
            for name in self.players:
                player=self.players[name]
                if player.world_object:
                    if player.team==get_team(player,"blue"):
                        player.spawn(self.blue_command)
                    else:
                        player.spawn(self.green_command)
        
        def stop_timer(self):
            if self.timer_call is not None:
                self.timer_call.cancel()
                self.send_chat('Timer stopped.')
                self.timer_call = None
                self.timer_end = None
                self.final = None
            else:
                return 'No timer in progress.'
        
        def display_timer(self, silent = False):
            time_left = self.timer_end - reactor.seconds()
            minutes_left = time_left / 60.0
            next_call = 60
            if not silent:
                if time_left <= 0:
                    if self.green_team.score==self.blue_team.score and self.final:
                        self.timer_end==None
                        self.send_chat("Time extended due to stalemate")
                        self.start_timer(6000)
                    else:
                        self.send_chat('Timer ended!', irc = True)
                        self.timer_end = None
                        self.final=False
                    return
                elif minutes_left <= 1:
                    self.send_chat('%s seconds left' % int(time_left), 
                        irc = True)
                    next_call = int(time_left / 2.0)
                else:
                    self.send_chat('%s minutes left' % int(minutes_left), 
                        irc = True)
            self.timer_call = reactor.callLater(next_call, self.display_timer)
        
        def display_messages(self):
            if not self.messages:
                return
            message = self.messages.pop(0)
            self.irc_say(message)
        
        # recording
        
        def add_kill(self, player, killing_player):
            if self.record is None:
                return
            self.get_record(player.name)['deaths'] += 1
            self.get_record(killing_player.name)['kills'] += 1
        
        def get_record(self, name):
            try:
                return self.record[name]
            except KeyError:
                record = {'deaths' : 0, 'kills' : 0}
                self.record[name] = record
                return record
        
        def start_record(self):
            self.record = {}
        
        def stop_record(self):
            self.record = None
        
        def save_record(self, value):
            if self.record is None:
                return False
            json.dump(self.record, open(value, 'wb'))
            return True

        def on_base_spawn(self, x, y, z, base, entity_id):
            if entity_id==2:
                self.blue_command=(x,y,z)
            else:
                self.green_command=(x,y,z)
            return protocol.on_base_spawn(self,x,y,z,base,entity_id)

    return MatchProtocol, MatchConnection
