__module_name__ = "Cloner"
__module_version__ = "0.2"
__module_description__ = "Channel cloner with RAWTO."

import xchat;
import pickle;

class cloner:
    srcnet = '';
    srcchan = '';
    dstnet = '';
    dstchan = '';
    prefix = '';
    active = 1;

active = 0;
hooks = [];
cfilename = xchat.get_info('xchatdir') + '/clonefile.pkl';
print "Loading clone file from: " + cfilename;
try:
    clonefile = open(cfilename, 'r');
    cloned = pickle.load(clonefile);
    clonefile.close();
except IOError:
    cloned = [];

def writeconf(conf):
    global cfilename, clonefile;
    
    clonefile = open(cfilename, 'w');
    pickle.dump(conf, clonefile, 0);
    clonefile.close();

def cnames(word, word_eol, userdata):
    nick = word[1];
    chan = word[2];
    server = xchat.get_info("server");
    users = [];
    payload = '';
    
    for i in range(3, len(word)):
	schan = word[i];
	if(schan.startswith("'")):
	    prefix = schan[1:schan.find('#')];
	    schan = schan[schan.find('#'):];
	else: prefix = '';
	if(schan.startswith('#')):
	    context = xchat.find_context(channel=schan);
	    chanlist = context.get_list("users");
	    for user in chanlist:
		if not user.nick.startswith(prefix) or len(prefix) == 0:
		    users.append("%s%s%s" % (user.prefix, prefix, user.nick));
	else:
	    users.append(word[i]);

    users.sort();
    last = users[-1];
    for i in range(len(users)-2, -1, -1):
	if last == users[i]: del users[i];
	else: last = users[i];
	
    payload = dpayload = "RAWTO %s ::%s 353 %s = %s :" % (nick, server, nick, chan);
    for user in users:
	payload += "%s " % user;
	if(len(payload) > 300):
	    xchat.command(payload.strip());
	    payload = dpayload;
	    
    xchat.command(payload.strip());
    xchat.command("RAWTO %s ::%s 366 %s %s :End of /NAMES list." %
	    (nick, server, nick, chan)
	);
    return xchat.EAT_ALL

def cclone(word, word_eol, userdata):
    global active, cloned, hooks;
    try: action = word[1].strip().lower();
    except: action = 'help';
    
    if(action == 'add'):
	nc = cloner();
	nc.srcchan = word[2];
	nc.dstnet = xchat.get_info("server");
	nc.dstchan = word[3].lower();
	if(nc.srcchan.startswith("'")):
            nc.prefix = nc.srcchan[:nc.srcchan.find('#')];
            nc.srcchan = nc.srcchan[nc.srcchan.find('#'):];
        else: nc.prefix = '';
	context = xchat.find_context(channel = nc.srcchan);
	nc.srcnet = context.get_info("server");
	cloned.append(nc);
	writeconf(cloned);
    elif(action == 'del'):
	if(word[2].isdigit()):
	    delwhat = int(word[2]);
	    if(delwhat >= 0 and delwhat < len(cloned)):
		del cloned[delwhat];
		writeconf(cloned);
	    else: xchat.prnt("Out of range.");
	else: xchat.prnt("Not a number.");
    elif(action == 'on' or action == 'off'):
	if(len(word) > 2 and word[2].isdigit()):
	    i = int(word[2]);
	    if(i >= 0 and i < len(cloned)):
		if(action == 'on'):
		    cloned[i].active = 1;
		    isactive = 'x';
		else:
		    cloned[i].active = 0;
		    isactive = ' ';
		writeconf(cloned);
		xchat.prnt("#%d: [%s] %s' | %s@%s -> %s@%s |" % (
		    i, isactive, cloned[i].prefix,
		    cloned[i].srcnet, cloned[i].srcchan,
		    cloned[i].dstnet, cloned[i].dstchan
		    )
		);
	else:
	    if(action == 'on'):
		active = 1;
		xchat.prnt("Cloning is \002\00306enabled\003\002.");
		for hook in hooks: xchat.unhook(hook);
		for hook in [ "PRIVMSG", "JOIN", "PART", "MODE", "KICK", "NICK", "TOPIC", "QUIT" ]:
		    hooks.append(xchat.hook_server(hook, doclone));
	    else:
		active = 0;
		xchat.prnt("Cloning is \002\00304disabled\003\002.");
		for hook in hooks: xchat.unhook(hook);
    elif(action == 'server'):
	xchat.prnt("Available servers:");
	chanlist = xchat.get_list("channels");
	for chan in chanlist:
	    if(chan.type == 1):
		xchat.prnt("%s (%s)" % (chan.server, chan.channel));
    elif(action == 'list'):
	if(len(cloned) <= 0):
	    xchat.prnt("Not cloning anything.");
	else:
	    clonedlist = [];
	    numlen = len(str(len(cloned)));
	    prefixlen = len("Prefix");
	    srclen = len("Source");
	    dstlen = len("Destination");
	    for i in range(len(cloned)):
		if(cloned[i].active == 1): isactive = 'x';
		elif(cloned[i].active == 2): isactive = '\002\00304!\003\002';
		else: isactive = ' ';
		numtxt = str(i).ljust(numlen);
		activetxt = "[%s]" % isactive;
		prefixtxt = cloned[i].prefix;
		prefixlen = max(len(prefixtxt), prefixlen)
		srctxt = "%s@%s" % (cloned[i].srcchan, cloned[i].srcnet);
		srclen = max(len(srctxt), srclen);
		dsttxt = "%s@%s" % (cloned[i].dstchan, cloned[i].dstnet);
		dstlen = max(len(dsttxt), dstlen);
		clonedlist.append([ numtxt, activetxt, prefixtxt, srctxt, dsttxt ]);

	    xchat.prnt("\037%s\002#: ON  %s  \002|\002 %s \002||\002 %s \002|" % (
		    "#".center(numlen,'#'),
		    "Prefix".center(prefixlen),
		    "Source".center(srclen),
		    "Destination".center(dstlen)
		)
	    );
	    
	    for i in clonedlist:
		xchat.prnt("#%s: %s %s' | %s -> %s |" % 
		    (
			i[0],
			i[1],
			i[2].rjust(prefixlen),
			i[3].rjust(srclen),
			i[4].ljust(dstlen)
		    )
		);
	    if(active == 1): xchat.prnt("Cloning is \002\00306enabled\003\002.");
	    else: xchat.prnt("Cloning is \002\00304disabled\003\002.");
    else: xchat.prnt("On, Off, Add, Del, List or Server?");
    
    return xchat.EAT_ALL;

def doclone(word, word_eol, userdata):
    global cloned;
    if(active == 0): return;
    
    for nc in cloned:
	if(nc.active != 1): continue;
	context = xchat.find_context(channel=nc.dstchan, server=nc.dstnet);
	rcontext = xchat.find_context(channel=nc.srcchan, server=nc.srcnet);
	if(context == None or rcontext == None):
	    nc.active = 2;
	    continue;
	nick = word[0][1:];
	nick = nick[:nick.find('!')];
	action = word[1].upper();
	if(action == 'QUIT'):
	    action = "PART";
	    word.insert(2, nc.srcchan);
	    chanlist = rcontext.get_list("users");
	    i = 0;
	    for user in chanlist:
		if(user.nick.lower() == nick.lower()):
		    i = 1;
		    break;
	    if(i == 0): return;

	if(len(nc.prefix) > 1): prefix = nc.prefix[1:];
	else: prefix = '';
	chan = word[2].lower();
	if(chan[0] == ':'): chan = chan[1:];
	userhost = ":%s%s" % (prefix, word[0][1:]);
	if(chan == nc.srcchan):
	    chanlist = context.get_list("users");
	    for user in chanlist:
		if not user.nick.startswith(prefix) or prefix == '':
		    payload = '';
		    if(action == 'MODE'):
			payload = ' ' + word[3];
			try:
			    for rnick in word_eol[4].split(' '):
				payload += " %s%s" % (prefix, rnick);
			except: pass;
		    elif(action == 'JOIN'): pass;
		    elif(action == 'KICK' or word[1].upper() == 'PART'):
			try:
			    if(word[1].upper() != 'PART'):
				payload = ' ' + prefix + word[3];
			    try: payload+= ' ' + word_eol[4];
			    except: pass;
			except: return;
		    else:
			try: payload = ' ' + word_eol[1][word_eol[1].find(':'):];
			except: payload = '';				
		    context.command("RAWTO %s :%s %s %s%s" %
			(user.nick, userhost, action, nc.dstchan, payload)
		    );
	elif(chan == nc.dstchan and (not nick.startswith(prefix) or prefix == '')):
	    if(action == 'JOIN'):
		cnames(["cnames", nick, nc.dstchan, nick, nc.dstchan, nc.prefix + nc.srcchan], None, None);
		context.command("RAWTO %s ::%s 332 %s %s :%s" % 
		    (nick, context.get_info("server"),
		     nick, nc.dstchan, rcontext.get_info("topic")
		    )
		);
	
xchat.hook_command("CNAMES", cnames, help="/RAWNAMES <nick> <chan> <users>");
xchat.hook_command("CCLONE", cclone, help="/CCLONE [on|off|add <prefix'#chan@server> <#chan@server>|del #|list|server]");
