# -*- coding: utf-8 -*-
#
# Copyright (c) 2012 by nils_2 <weechatter@arcor.de>
# Copyright (c) 2006 by EgS <i@egs.name>
#
# script to keep your nick and recover it in case it's occupied
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# 2012-02-08: nils_2, (freenode.#weechat)
#       0.5 : sync with 0.3.x API (requested by CAHbI4)
#
# requires: WeeChat version 0.3.4
#
# Development is currently hosted at
# https://github.com/weechatter/weechat-scripts
#
#######################################################################
#                                                                     #
# This script enables the user to keep their nicks and recover it in  #
# case it get's stolen. It uses the servers prefered nicks, so there  #
# is no need for any kind of setup.                                   #
#                                                                     #
# Name:    Keepnick                                                   #
# Licence: GPL v2                                                     #
# Author:  Marcus Eggenberger <i@egs.name>                            #
#                                                                     #
#  Usage:                                                             #
#   /keepnick on|off|<positive number>                                #
#                                                                     #
#   use /help command for  detailed information                       #
#                                                                     #
#  Changelog:                                                         #
#   0.4: now starts on load and features user defined check intervals #
#   0.3: Fixed major bug with continuous nickchanges                  #
#   0.2: Fixed Bug: now only checks connected servers                 #
#   0.1: first version released                                       #
#                                                                     #
#######################################################################

try:
    import weechat,sys

except Exception:
    print "This script is to be loaded as PythonScript in WeeChat"
    print "Get WeeChat now at: http://www.weechat.org/"
    quit()

# -------------------------------[ Constants ]-------------------------------------
SCRIPT_NAME     = "keepnick"
SCRIPT_AUTHOR   = "nils_2 <weechatter@arcor.de>"
SCRIPT_VERSION  = "0.5"
SCRIPT_LICENCE  = "GPL3"
SCRIPT_DESC     = "script to keep your nick and recover it in case it's occupied"

ISON = '/ison %s'

OPTIONS         =       { 'delay'       : ('10','delay (in seconds) to look at occupied nick (0 means OFF). It is not recommended to flood the server with /ison requests)'),
                          'timeout'     : ('60','timeout (in seconds) to wait for an answer from server.'),
                          'serverlist'  : ('IRCnet','comma separated list of servers to look at. Only use this service if its not possible to register a nickname on server (see: /msg NickServ help)'),
                          'text'        : ('Nickstealer left Network: %s!','text that will be displayed if your nick will not be occupied anymore. (\"%s\" will be filled with Servername)'),
                          'command'     : ('/nick %s','This command will be used to rename your nick (\"%s\" will be filled with your nickname for specific server)'),
                        }
HOOK            =       { 'timer': '', 'redirect': '' }
serverlist = []

# ================================[ redirection ]===============================
# calling /ison all x seconds using hook:timer()
def ison(bufpointer,servername,nick,nicklist):
    command = ISON % ' '.join(nicklist)
    weechat.hook_hsignal_send('irc_redirect_command',
                                  { 'server': servername, 'pattern': 'ison', 'signal': SCRIPT_NAME, 'count': '1', 'string': servername, 'timeout': OPTIONS['timeout'], 'cmd_filter': '' })
    weechat.hook_signal_send('irc_input_send', weechat.WEECHAT_HOOK_SIGNAL_STRING, '%s;;;;%s' % (servername,command))

def redirect_isonhandler(data, signal, hashtable):
    if hashtable['output'] == '':
        return weechat.WEECHAT_RC_OK

    nothing, message, nicks = hashtable['output'].split(':')
    nicks = [nick.lower() for nick in nicks.split()]
    for nick in servernicks(hashtable['server']):
        if nick.lower() == weechat.info_get('irc_nick',hashtable['server']):
            return weechat.WEECHAT_RC_OK
        elif nick.lower() not in nicks:
            grabnick(hashtable['server'], nick)
            return weechat.WEECHAT_RC_OK

    if 0 in [nick.lower() in [mynick.lower() for mynick in servernicks(hashtable['server'])] for nick in nicks]:
        # if any nick which is return by ison is not on our checklist we're not the caller
        return weechat.WEECHAT_RC_OK
    else:
        # seems like we're the caller -> ignore the output
        return weechat.WEECHAT_RC_OK

# ================================[ functions ]===============================
def servernicks(servername):
    infolist = weechat.infolist_get('irc_server','',servername)
    weechat.infolist_next(infolist)
    nicks = weechat.infolist_string(infolist, 'nicks')
    weechat.infolist_free(infolist)
    servernicks = nicks.split(',')
    return servernicks

def checknicks(data, remaining_calls):
    serverlist = OPTIONS['serverlist'].split(',')
    infolist = weechat.infolist_get('irc_server','','')

    while weechat.infolist_next(infolist):
        servername = weechat.infolist_string(infolist, 'name')
        bufpointer = weechat.infolist_pointer(infolist,'buffer')
        nick = weechat.infolist_string(infolist, 'nick')
        ssl_connected = weechat.infolist_integer(infolist,'ssl_connected')
        is_connected = weechat.infolist_integer(infolist,'is_connected')
        if servername in serverlist:
            if nick and ssl_connected + is_connected:
                ison(bufpointer,servername,nick,servernicks(servername))
    weechat.infolist_free(infolist)
    return weechat.WEECHAT_RC_OK

def grabnick(servername, nick):
    if nick:
        weechat.prnt(weechat.current_buffer(),OPTIONS['text'] % servername)
        weechat.command(weechat.buffer_search('irc','%s.%s' % ('server',servername)), OPTIONS['command'] % nick)

# ================================[ weechat hook ]===============================
def install_hooks():
    global HOOK,OPTIONS

    if HOOK['timer'] != '' or HOOK['redirect'] != '':                                     # should not happen, but...
        return

    if not OPTIONS['delay'] or not OPTIONS['timeout']:
        return
    HOOK['timer'] = weechat.hook_timer(int(OPTIONS['delay']) * 1000, 0, 0, 'checknicks', '')
    HOOK['redirect'] = weechat.hook_hsignal('irc_redirection_%s_ison' % SCRIPT_NAME, 'redirect_isonhandler', '' )

    if HOOK['timer'] == 0:
        weechat.prnt('',"%s: can't enable %s, hook_timer() failed" % (weechat.prefix('error'), SCRIPT_NAME))
    if HOOK['redirect'] == 0:
        weechat.prnt('',"%s: can't enable %s, hook_signal() failed" % (weechat.prefix('error'), SCRIPT_NAME))

def remove_hooks():
    global HOOK

    if HOOK['timer'] != '':
        weechat.unhook(HOOK['timer'])
        HOOK['timer'] = ''
    if HOOK['redirect'] != '':
        weechat.unhook(HOOK['redirect'])
        HOOK['redirect'] = ''

# ================================[ weechat options and description ]===============================
def init_options():
    global HOOK,OPTIONS
    for option,value in OPTIONS.items():
        if not weechat.config_is_set_plugin(option):
            weechat.config_set_plugin(option, value[0])
            weechat.config_set_desc_plugin(option, '%s (default: "%s")' % (value[1], value[0]))
            OPTIONS[option] = value[0]
        else:
            OPTIONS[option] = weechat.config_get_plugin(option)

def toggle_refresh(pointer, name, value):
    global HOOK,OPTIONS
    option = name[len('plugins.var.python.' + SCRIPT_NAME + '.'):]              # get optionname
    OPTIONS[option] = value                                                     # save new value

    if option == 'delay' or option == 'timeout':
        if int(OPTIONS['delay']) > 0 or int(OPTIONS['timeout']) > 0:
            remove_hooks()
            install_hooks()
        else:
            remove_hooks()                                                  # user switched timer off
    return weechat.WEECHAT_RC_OK

# ================================[ main ]===============================
if __name__ == '__main__':
    weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENCE, SCRIPT_DESC, '','')

    version = weechat.info_get("version_number", "") or 0
    if int(version) >= 0x00030400:
        if OPTIONS['delay'] > 0 and OPTIONS['timeout'] > 0:
            init_options()
            install_hooks()
            weechat.hook_config( 'plugins.var.python.' + SCRIPT_NAME + '.*', 'toggle_refresh', '' )
    else:
        weechat.prnt('','%s%s %s' % (weechat.prefix('error'),SCRIPT_NAME,': needs version 0.3.4 or higher'))
        weechat.command('',"/wait 1ms /python unload %s" % SCRIPT_NAME)
