from netadmin.exceptions import ParseError
from protocol import ReceivedMessage, IRCString, Channel, User

BINARY_COMMANDS = (
    'PING',
    'PONG',
)
TERNARY_COMMANDS = (

)

def get_event_name(msg):
    return 'on_' + msg.command.lower()


def parse_line(line):
    msg = ReceivedMessage()
    msg.line = clean_line = line.rstrip('\r\n')
    msg.tokens = tokens = clean_line.split(' ')

    if len(tokens) < 3:
        raise ParseError('Line does not have enough tokens: "{}"'.format(clean_line))

    def _parse_user(token):
        user = User()
        if '!' in token:
            c1, c2 = token.index('!'), token.index('@')
            nick, ident, host = token[:c1], token[c1+1:c2], token[c2+1:]
        else:
            c = token.index('@')
            nick, ident, host = token[:c], None, token[c+1:]
        return nick, ident, host

    def _parse_source(token):
        def _parse_server():
            return token
        return _parse_user(token) if '@' in token else _parse_server(token)

    def _parse_target(*tokens):
        token = ' '.join(tokens)  # target is one or more tokens, we'll handle them all
        def _target_string():
            return IRCString(token[1:])  # just strip the ':' and done
        def _target_chan():
            chan = Channel()
            chan.name = token
            return chan
        def _target_user():
            user = User()
            user.nick, user.ident, user.host = _parse_user(token)
            return user

        if token.startswith(':'):
            return _target_string()
        elif token.startswith('#'):
            return _target_chan()
        elif '@' in token:
            return _target_user()
        else:
            raise ParseError('Unknown format of target "{}"'.format(token))

    def _parse_2ary():
        left, right = tokens[0], tokens[2:]  # the right is one or more tokens
        left = _parse_source(left)  # left is always a source
        right = _parse_target(*right)  # right is always a target
        return (left, command) + tuple(right)

    def _parse_3ary():
        pass

    command = tokens[1]  # parse the line based on what the command is
    if command in BINARY_COMMANDS:
        msg.parsed = _parse_2ary()
    elif command in TERNARY_COMMANDS:
        msg.parsed = _parse_3ary()
    else:
        raise ParseError("Unknown command {}".format(command))

    return msg


if __name__ == '__main__':
    print parse_line(':user!ident@host PONG :hey there')
