#       MIT License
#
#       Copyright (c) 2009 Matej Cepl <mcepl () redhat ! com>
#
#       Permission is hereby granted, free of charge, to any person obtaining
#       a copy of this software and associated documentation files (the
#       "Software"), to deal in the Software without restriction, including
#       without limitation the rights to use, copy, modify, merge, publish,
#       distribute, sublicense, and/or sell copies of the Software, and to
#       permit persons to whom the Software is furnished to do so, subject to
#       the following conditions:
#
#       The above copyright notice and this permission notice shall be
#       included in all copies or substantial portions of the Software.
#
#       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
#       EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
#       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
#       IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
#       CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
#       TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
#       SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
use Purple;
use Data::Dumper;

my $pluginName = "open-chats-xmpp";
my $plugin = "";

$botname = "USERSERV";
%PLUGIN_INFO = (
    perl_api_version => 2,
    name => "Perl: Open Chats from XMPP Bookmarks",
    version => "0.2",
    summary => "Opens all XMPP chats according to bookmarks" .
        "stored on the server.",
    description => "Opens all XMPP chats according to bookmarks" .
        "stored on the server.",
    author => "Matěj Cepl <mcepl () redhat ! com>",
    url => "http://matej.ceplovi.cz",
    load => "plugin_load",
    unload => "plugin_unload",
);

# list of outstanding IDs for <iq>s we are waiting to get answer
my @requests_queue = ();

sub is_queued {
    my $element = shift;
    if ($element) {
        my @found = grep($_ eq "$element" , @requests_queue);
        my $count = @found;
        Purple::Debug::misc("$pluginName",
            "Element $element found in queue $count times.\n(@found)\n");
        return $count >0;
    } else {
        return 0 ;
    }
}

sub pick_from_queue {
    my $element = shift ;

    foreach my $item (@requests_queue) {
        if ($item =~ /$element/) {
            @requests_queue = grep (!/$item/,@requests_queue);
            return $item;
        }
    }
    return 0;
}

sub send_iq_request {
    my $conn = shift ;
    my $payload = shift ;
    my $callback_function = shift ;

    my $randid = "bkmks-" . int(rand(100));
    while (is_queued($randid)) {
        $randid = "bkmks-" . int(rand(100));
    }

    my $nodestr = '<iq type="get" id="' . $randid . '">' . $payload . '</iq>';
    Purple::Debug::misc("$pluginName","sending packet:\n$nodestr\nto $conn\n");
    my $ret = Purple::Prpl::send_raw($conn,$nodestr);
    push @requests_queue, $randid;

    my $no_connected_signals = @connected_signals;
    if ($no_connected_signals == 0) {
        Purple::Debug::misc("$pluginName",
        "Connecting got_xml_cb to jabber-receiving-iq signal\n");
        my $jabber = Purple::Find::prpl("prpl-jabber");
        if (!$jabber) {
            die("No jabber protocol?, weird: $!\n");
        }
        $consignal = Purple::Signal::connect($jabber,
            "jabber-receiving-iq",$plugin,\&got_xml_cb, 0);
        push @connected_signals,$consignal;
    }
}

sub get_bookmarks {
    my $im_connection = shift; # current Connection

    send_iq_request($im_connection,
        '<pubsub xmlns="http://jabber.org/protocol/pubsub">' .
        '<items node="storage:bookmarks"/></pubsub>',
        \&bookmarks_cb);
}

sub process_conference_node {
    my $conn = shift ;
    my $curnode = shift ;

    my $autojoin = lc($curnode->get_attrib('autojoin'));
    if ($autojoin) {
        my $count = grep (/$autojoin/ , (1,"true") );
        if ($count > 0){
            my ($room,$server) = split(/@/,$curnode->get_attrib('jid'));
            my $handlenode = $curnode->get_child("nick");
            my $handle = $handlenode->get_data();
            my $blist_chat = Purple::BuddyList::find_chat($conn,$room);
            Purple::Debug::info("$pluginName","\$blist_chat = $blist_chat\n");
            my %components = (
                "room" => $room,
                "server" => $server,
                "handle" => $handle,
                "password" => ""
            );
            Purple::Debug::info("$pluginName",
                "join_chat: " . Dumper(%components) . "\n");
            Purple::Serv::join_chat($conn,\%components);
        }
    }
}

sub got_xml_cb {
    my $queue_length = @requests_queue;
    if ($queue_length == 0) {
        foreach my $signal (@connected_signals) {
            Purple::Prefs::disconnect_by_handle($signal);
        }
        return ;
    }
    my $conn = shift;     # connection
    my $iq_type = shift;  # what type of IQ is this?
    my $iq_id = shift;    # what's the ID of the incoming IQ?
    my $iq_from = shift;  # who is the IQ from?
    my $packet = shift;   # xmlnode
    my $soughtid = shift; # random ID
    Purple::Debug::misc("$pluginName",
        "IQ received: \$iq_type = $iq_type, \$iq_id = $iq_id, ' .
            '\$iq_from = $iq_from\n\$packet = $packet\n");

    if (($iq_type eq 'result') && is_queued($iq_id)) {
        pick_from_queue($iq_id,@requests_queue);

        my $packetstr = $packet->to_str();
        Purple::Debug::info("$pluginName", "packet: $packetstr\n");
        # TODO check that items/@node == "storage:bookmarks" and/or
        # xmlns of storage is that.
        my $curnode = $packet->get_child("pubsub/items/item/storage/conference");
        while ($curnode) {
            Purple::Debug::info("$pluginName", "conference: " .
            $curnode->to_str() . "\n");
            process_conference_node($conn,$curnode);
            $curnode = $curnode->get_next_twin();
        }
    }
}

# information links
# http://xmpp.org/extensions/xep-0048.html
# http://xmpp.org/extensions/xep-0223.html
# http://xmpp.org/extensions/xep-0060.html

sub joined_chat {
    my $conv = shift; # PurpleConversation
    Purple::Debug::info("$pluginName", "joined chat " .
            $conv->get_name() . " for account " .
            $conv->get_account()->get_username() . "\n");
    # if not("chat already registered") then add_to_server
}

sub left_chat {
    my $conv = shift; # PurpleConversation
    Purple::Debug::info("$pluginName", "left chat " .
            $conv->get_name() . " for account " .
            $conv->get_account()->get_username() . "\n");
    # if "chat already registered" then remove_from_server
}

my @connected_signals = ();
my $blist;

sub signed_on {
    my $conn = shift;
    my $account = $conn->get_account();
    my $username = $account->get_username();
    my $protocol_id = $account->get_protocol_id();
    my @buddies ;
    Purple::Debug::misc("$pluginName",
        "signed-on $username @ $account ($protocol_id)\n");
    if ($protocol_id eq "prpl-jabber") {
        get_bookmarks($conn);
        @buddies = Purple::Find::buddies($account,"");
    }
}

sub plugin_load {
    $plugin = shift;
    my $connected_signal;

    # it doesn't make any sense when we don't have jabber
    my $jabber = Purple::Find::prpl("prpl-jabber");
    if (!$jabber) {
        return NULL;
    }

    # connect signed-on signal
    $conn = Purple::Connections::get_handle();
    $consignal = Purple::Signal::connect($conn, "signed-on", $plugin,
        \&signed_on, 0);
    push @connected_signals,$consignal;

    # connect IQ management signals
    $consignal = Purple::Signal::connect($jabber,
        "jabber-receiving-iq",$plugin,\&got_xml_cb, 0);
    push @connected_signals,$consignal;

    # connect chat management signals
    $conn = Purple::Conversations::get_handle();
    $consignal = Purple::Signal::connect($conn,
        "chat-joined",$plugin,\&joined_chat, 0);
    push @connected_signals,$consignal;
    $consignal = Purple::Signal::connect($conn,
        "chat-left",$plugin,\&left_chat, 0);
    push @connected_signals,$consignal;

    # Initialize a buddy list
    # FIXME Do we need it? What it is good for?
    $blist = Purple::get_blist();
    Purple::Debug::misc("$pluginName",
        "Getting the current Buddy List\n" . Dumper($blist) . "\n");
    my $node = Purple::BuddyList::get_root();
}

sub plugin_unload {
    foreach my $signal (@connected_signals) {
        Purple::Prefs::disconnect_by_handle($signal);
    }
    Purple::Debug::info("$pluginName", "Login to $botname plugin unloaded\n");
}
