#include "pidgin-twitter.h"
#include <gtkutils.h>
#include <pidginstock.h>
#include <gtkblist.h>

extern GRegex *regp[];
extern guint64 reply_to_msgid;
extern PurpleAccount *account_for_twitter;

/* prototypes */
static gchar *twitter_memrchr(const gchar *s, int c, size_t n);


/* functions */

/* this function has been taken from autoaccept plugin */
gboolean
ensure_path_exists(const char *dir)
{
	if (!g_file_test(dir, G_FILE_TEST_IS_DIR)) {
		if (purple_build_dir(dir, S_IRUSR | S_IWUSR | S_IXUSR))
			return FALSE;
	}

	return TRUE;
}

static gchar *
twitter_memrchr(const gchar *s, int c, size_t n)
{
    int nn = n;

    g_return_val_if_fail(s != NULL, NULL);

    while(nn+1) {
        if((int)*(s+nn) == c)
            return (gchar *)(s+nn);
        nn--;
    }
    return NULL;
}

static gchar *html_tags[] = {
    "<a ",
    "</a>",
    "<b>",
    "</b>",
    "<p>",
    "</p>",
    "<div ",
    "</div>",
    "<span ",
    "</span>",
    "<body>",
    "<body ",
    "</body>",
    "<i>",
    "</i>",
    "<font ",
    "</font>",
    "<br>",
    "<br/>",
    "<img ",
    "<html>",
    "<html ",
    "</html>",
    NULL
};

gchar *
strip_html_markup(const gchar *src)
{
    gchar *head, *tail;     /* head and tail of html */
    gchar *begin, *end;     /* begin:<  end:> */
    gchar *html, *str;      /* copied src and string to be returned */
/*    gchar *vis1, *vis2; */     /* begin and end of address part */
    gchar *startp;          /* starting point marker */
    gchar **tagp;           /* tag iterator */
    gchar *tmp, *tmp2;      /* scratches */

    g_return_val_if_fail(src != NULL, NULL);

    const gchar *ptr, *ent;
    gchar *ptr2;
    gint srclen;
    gint entlen;

    /* unescape &x; */
    srclen = strlen(src);
    html = g_malloc0(srclen + 1);
    ptr2 = html;
    for(ptr = src; *ptr; ) {
        if(*ptr == '&') {
            ent = purple_markup_unescape_entity(ptr, &entlen);
            if(ent != NULL) {
                while(*ent) {
                    if(ptr2 - html < srclen)
                        *ptr2++ = *ent++;
                    else
                        ent++;
                }
                ptr += entlen;
            }
            else {
                if(ptr2 - html < srclen)
                    *ptr2++ = *ptr++;
                else
                    ptr++;
            }
        }
        else {
            if(ptr2 - html < srclen)
                *ptr2++ = *ptr++;
            else
                ptr++;
        }
    } /* for */

    str = g_strdup("\0");

    head = html;
    tail = head + strlen(html);
    startp = head;

loop:
    begin = NULL;
    end = NULL;

    if(startp >= tail) {
        g_free(html);
        return str;
    }

    end = strchr(startp, '>');
    if(end) {
        begin = twitter_memrchr(startp, '<', end - startp);
        if(begin < startp)
            begin = NULL;

        if(!begin) { /* '>' found but no corresponding '<' */
            tmp = g_strndup(startp, end - startp + 1); /* concat until '>' */
            tmp2 = g_strconcat(str, tmp, NULL);
            g_free(str);
            g_free(tmp);
            str = tmp2;
            startp = end + 1;
            goto loop;
        }
    }
    else { /* neither '>' nor '<' were found */
        tmp = g_strconcat(str, startp, NULL); /* concat the rest */
        g_free(str);
        str = tmp;
        g_free(html);
        return str;
    }

    /* here, both < and > are found */
    /* concatenate leading part to dest */
    tmp = g_strndup(startp, begin - startp);
    tmp2 = g_strconcat(str, tmp, NULL);
    g_free(tmp);
    g_free(str);
    str = tmp2;

    /* find tag */
    for(tagp = html_tags; *tagp; tagp++) {
        if(!g_ascii_strncasecmp(begin, *tagp, strlen(*tagp))) {
            /* we found a valid tag */
            /* if tag is <a href=, extract address. */
#if 0
            if(!strcmp(*tagp, "<a href=")) {
                vis1 = NULL; vis2 = NULL;

                vis1 = strchr(begin, '\'');
                if(vis1)
                    vis2 = strchr(vis1+1, '\'');
                if(!vis1) {
                    vis1 = strchr(begin, '\"');
                    if(vis1)
                        vis2 = strchr(vis1+1, '\"');
                }
                if(vis1 && vis2) {
                    *vis2 = '\0';
                    /* generate "[ http://example.com/ ] anchor " */
                    tmp = g_strconcat(str, "[ ", vis1+1, " ]", " ", NULL);
                    g_free(str);
                    str = tmp;
                }
                startp = end + 1;
                goto loop;
            } /* <a href= */
            else {
                /* anything else: discard whole <>. */
                startp = end + 1;
                goto loop;
            }
#else
            /* anything else: discard whole <>. */
            startp = end + 1;
            goto loop;
#endif
        }  /* valid tag */
    }

    /* no valid tag was found: copy <brabra> */
    tmp = g_strndup(begin, end - begin + 1);
    tmp2 = g_strconcat(str, tmp, NULL);
    g_free(tmp);
    g_free(str);
    str = tmp2;
    startp = end + 1;
    goto loop;
}

/* string utilities */
void
escape(gchar **str)
{
    GMatchInfo *match_info = NULL;
    gchar *newstr = NULL, *match = NULL;
    gboolean flag = FALSE;

    /* search genuine command */
    g_regex_match(regp[COMMAND], *str, 0, &match_info);
    while(g_match_info_matches(match_info)) {
        match = g_match_info_fetch(match_info, 1);
        twitter_debug("command = %s\n", match);
        g_free(match);
        g_match_info_next(match_info, NULL);
        flag = TRUE;
    }
    g_match_info_free(match_info);
    match_info = NULL;

    if(flag)
        return;

    /* if not found, check pseudo command */
    g_regex_match(regp[PSEUDO], *str, 0, &match_info);
    while(g_match_info_matches(match_info)) {
        match = g_match_info_fetch(match_info, 1);
        twitter_debug("pseudo = %s\n", match);
        g_free(match);
        g_match_info_next(match_info, NULL);
        flag = TRUE;
    }
    g_match_info_free(match_info);
    match_info = NULL;

    /* if there is pseudo one, escape it */
    if(flag) {
        /* put ". " to the beginning of buffer */
        newstr = g_strdup_printf(". %s", *str);
        twitter_debug("*str = %s newstr = %s\n", *str, newstr);
        g_free(*str);
        *str = newstr;
    }
}

void
strip_markup(gchar **str, gboolean escape)
{
    gchar *plain;

    plain = strip_html_markup(*str);
    g_free(*str);
    if(escape) {
        *str = g_markup_escape_text(plain, -1);
        g_free(plain);
    }
    else {
        *str = plain;
    }
    twitter_debug("result=%s\n", *str);
}

gboolean
is_twitter_account(PurpleAccount *account, const char *name)
{
    const gchar *proto = purple_account_get_protocol_id(account);

    if(g_strstr_len(name,  19, "twitter@twitter.com") &&
       g_strstr_len(proto, 11, "prpl-jabber")) {
        return TRUE;
    }

    return FALSE;
}

gboolean
is_twitter_conv(PurpleConversation *conv)
{
    g_return_val_if_fail(conv != NULL, FALSE);

    const char *name = purple_conversation_get_name(conv);
    PurpleAccount *account = purple_conversation_get_account(conv);

    return is_twitter_account(account, name);
}

gboolean
is_wassr_account(PurpleAccount *account, const char *name)
{
    const gchar *proto = purple_account_get_protocol_id(account);

    if(g_strstr_len(name,  18, "wassr-bot@wassr.jp") &&
       g_strstr_len(proto, 11, "prpl-jabber")) {
        return TRUE;
    }

    return FALSE;
}

gboolean
is_wassr_conv(PurpleConversation *conv)
{
    g_return_val_if_fail(conv != NULL, FALSE);

    const char *name = purple_conversation_get_name(conv);
    PurpleAccount *account = purple_conversation_get_account(conv);

    return is_wassr_account(account, name);
}

gboolean
is_identica_account(PurpleAccount *account, const char *name)
{
    const gchar *proto = purple_account_get_protocol_id(account);

    if(g_strstr_len(name,  16, "update@identi.ca") &&
       g_strstr_len(proto, 11, "prpl-jabber")) {
        return TRUE;
    }

    return FALSE;
}

gboolean
is_identica_conv(PurpleConversation *conv)
{
    g_return_val_if_fail(conv != NULL, FALSE);

    const char *name = purple_conversation_get_name(conv);
    PurpleAccount *account = purple_conversation_get_account(conv);

    return is_identica_account(account, name);
}

gboolean
is_jisko_account(PurpleAccount *account, const char *name)
{
    const gchar *proto = purple_account_get_protocol_id(account);

    if(g_strstr_len(name,  16, "bot@jisko.net") &&
       g_strstr_len(proto, 11, "prpl-jabber")) {
        return TRUE;
    }

    return FALSE;
}

gboolean
is_jisko_conv(PurpleConversation *conv)
{
    g_return_val_if_fail(conv != NULL, FALSE);

    const char *name = purple_conversation_get_name(conv);
    PurpleAccount *account = purple_conversation_get_account(conv);

    return is_jisko_account(account, name);
}

gboolean
is_ffeed_account(PurpleAccount *account, const char *name)
{
    const gchar *proto = purple_account_get_protocol_id(account);

    if(g_strstr_len(name,  22, "ff@chat.friendfeed.com") &&
       g_strstr_len(proto, 11, "prpl-jabber")) {
        return TRUE;
    }

    return FALSE;
}

gboolean
is_ffeed_conv(PurpleConversation *conv)
{
    g_return_val_if_fail(conv != NULL, FALSE);

    const char *name = purple_conversation_get_name(conv);
    PurpleAccount *account = purple_conversation_get_account(conv);

    return is_ffeed_account(account, name);
}

gint
get_service_type_by_account(PurpleAccount *account, const char *sender)
{
    gint service = unknown_service;

    g_return_val_if_fail(account != NULL, unknown_service);
    g_return_val_if_fail(sender != NULL, unknown_service);

    if(is_twitter_account(account, sender))
        service = twitter_service;
    else if(is_wassr_account(account, sender))
        service = wassr_service;
    else if(is_identica_account(account, sender))
        service = identica_service;
    else if(is_jisko_account(account, sender))
        service = jisko_service;
    else if(is_ffeed_account(account, sender))
        service = ffeed_service;

    return service;
}

gint
get_service_type(PurpleConversation *conv)
{
    gint service = unknown_service;

    g_return_val_if_fail(conv != NULL, unknown_service);

    if(is_twitter_conv(conv))
        service = twitter_service;
    else if(is_wassr_conv(conv))
        service = wassr_service;
    else if(is_identica_conv(conv))
        service = identica_service;
    else if(is_jisko_conv(conv))
        service = jisko_service;
    else if(is_ffeed_conv(conv))
        service = ffeed_service;

    return service;
}

void cancel_retweet(void *data)
{
    /* do nothing */
}

void do_retweet(void *data)
{
    guint64 msgid = *(guint64 *)data;
    twitter_debug("msgid=%llu\n", (long long unsigned int)msgid);
    retweet_with_api(msgid);
}

gboolean
pt_uri_handler(const char *proto, const char *cmd, GHashTable *params)
{
    char *idstr = NULL;
	const char *acct_id = NULL;
	PurpleConversation *conv = NULL;
	PidginConversation *gtkconv = NULL;
    guint64 msgid = 0;
    gchar *sender = NULL, *recipient = NULL, *msg = NULL;

    if(g_ascii_strcasecmp(proto, "pt"))
       return FALSE;

    twitter_debug("params=%p\n", params);

    acct_id = purple_prefs_get_string(OPT_SCREEN_NAME_TWITTER);
    twitter_debug("acct_id=%s\n", acct_id);

    if(strstr(cmd, "reply-twitter")) {
        sender = g_hash_table_lookup(params, "user");
        idstr = g_hash_table_lookup(params, "id");
        if(idstr)
            msgid = strtoull(idstr, NULL, 10);

        /* find conv */
        conv = purple_find_conversation_with_account(
            PURPLE_CONV_TYPE_ANY, "twitter@twitter.com",
            account_for_twitter); /* xxx */
        twitter_debug("conv=%p\n", conv);
        gtkconv = PIDGIN_CONVERSATION(conv);

        twitter_debug("sender=%s, id=%llu\n", sender, (unsigned long long)msgid);

        recipient = g_strdup_printf("@%s ", sender);
        gtk_text_buffer_insert_at_cursor(gtkconv->entry_buffer,
                                         recipient, -1);

        gtk_widget_grab_focus(GTK_WIDGET(gtkconv->entry));
        g_free(recipient);
        reply_to_msgid = msgid;

        return TRUE;
    }
    else if(strstr(cmd, "fav-twitter")) {
        idstr = g_hash_table_lookup(params, "id");
        fav_with_api(strtoull(idstr, NULL, 10));
        return TRUE;
    }
    else if(strstr(cmd, "retweet-twitter")) {
        GtkWidget *retweet_dialog;
        static guint64 retweet_msgid = 0;

        idstr = g_hash_table_lookup(params, "id");
        retweet_msgid = strtoull(idstr, NULL, 10);
        twitter_debug("retweet_msgid=%llu\n", (long long unsigned int)retweet_msgid);

        retweet_dialog = pidgin_make_mini_dialog(
            NULL,
            PIDGIN_STOCK_DIALOG_INFO,
            "Are you sure to retweet this message?",
            NULL, /* secondary */
            (void *)&retweet_msgid, /* user data */
            "Cancel", PURPLE_CALLBACK(cancel_retweet),
            "Retweet", PURPLE_CALLBACK(do_retweet),
            NULL);
        pidgin_blist_add_alert(retweet_dialog);

        return TRUE;
    }
    else if(strstr(cmd, "quotetweet-twitter")) {
        gchar *msg0;
        sender = g_hash_table_lookup(params, "user");
        idstr = g_hash_table_lookup(params, "id");
        msg0 = g_hash_table_lookup(params, "msg");
        msg = g_uri_unescape_string(msg0, NULL);

        if(idstr)
            msgid = strtoull(idstr, NULL, 10);

        /* find conv */
        conv = purple_find_conversation_with_account(
            PURPLE_CONV_TYPE_ANY, "twitter@twitter.com",
            account_for_twitter); /* xxx */
        twitter_debug("conv=%p\n", conv);
        gtkconv = PIDGIN_CONVERSATION(conv);

        twitter_debug("sender=%s, id=%llu\n", sender, (unsigned long long)msgid);

        recipient = g_strdup_printf("QT @%s: %s", sender, msg);
        g_free(msg);
        gtk_text_buffer_insert_at_cursor(gtkconv->entry_buffer,
                                         recipient, -1);

        GtkTextIter iter;
        gtk_text_buffer_get_start_iter(gtkconv->entry_buffer, &iter);
        gtk_text_buffer_place_cursor(gtkconv->entry_buffer, &iter);

        gtk_widget_grab_focus(GTK_WIDGET(gtkconv->entry));
        g_free(recipient);
        reply_to_msgid = msgid;

        return TRUE;
    }
    return FALSE;
}

gchar *
twitter_rip_link_string(gchar **str)
{
    GMatchInfo *match_info = NULL;
    gchar *body0 = NULL, *body = NULL;
    gchar *newstr = NULL, *linkstr = NULL;
    gchar *user = NULL;

    twitter_debug("called\n");

    /* buffer without pttag= */
    body0 = g_regex_replace(regp[SENDER], *str, -1, 0, "", 0, NULL);
    body = g_regex_replace(regp[PTTAG_TWITTER], body0, -1, 0, "", 0, NULL);
    g_free(body0);
    body0 = NULL;
    twitter_debug("body = %s\n", body);

    body0 = g_uri_escape_string(body, " !$()*,;:@/?#[]", TRUE);
    g_free(body);
    body = body0;

    /* sender */
    g_regex_match(regp[SENDER], *str, 0, &match_info);
    if(g_match_info_matches(match_info)) {
        user = g_match_info_fetch(match_info, 2);
        twitter_debug("user = %s\n", user);
        g_match_info_free(match_info);
        match_info = NULL;
    }

    /* link string */
    g_regex_match(regp[PTTAG_TWITTER], *str, 0, &match_info);
    if(match_info) {
        gchar *msg_id_str = NULL;
        gchar *in_reply_to_status_id_str = NULL;
        long long unsigned int in_reply_to_status_id = 0;

        msg_id_str = g_match_info_fetch(match_info, 1);
        in_reply_to_status_id_str = g_match_info_fetch(match_info, 2);
        if(in_reply_to_status_id_str)
            in_reply_to_status_id = strtoull(in_reply_to_status_id_str, NULL, 10);
        g_free(in_reply_to_status_id_str);
        in_reply_to_status_id_str = NULL;

        if(in_reply_to_status_id) {
            gchar *in_reply_to_screen_name;

            in_reply_to_screen_name = g_match_info_fetch(match_info, 3);
            linkstr = g_strdup_printf(IN_REPLY_TO_FORMAT_TWITTER LINK_FORMAT_TWITTER,
                                      in_reply_to_screen_name,
                                      in_reply_to_status_id,
                                      in_reply_to_screen_name,
                                      msg_id_str, user,         /* Reply */
                                      msg_id_str,               /* Favorite */
                                      msg_id_str,               /* Retweet */
                                      msg_id_str, user, body); /* Quotetweet */

            g_free(in_reply_to_screen_name);
            in_reply_to_screen_name = NULL;
        }
        else {
            linkstr = g_strdup_printf(LINK_FORMAT_TWITTER,
                                      msg_id_str, user,         /* Reply */
                                      msg_id_str,               /* Favorite */
                                      msg_id_str,               /* Retweet */
                                      msg_id_str, user, body); /* Quotetweet */
        }

        twitter_debug("linkstr = %s\n", linkstr);

        newstr = g_regex_replace(regp[PTTAG_TWITTER], *str, -1, 0, "", 0, NULL);

        twitter_debug("newstr = %s\n", newstr);

        g_free(*str);
        *str = newstr;

        g_free(msg_id_str);
        msg_id_str = NULL;

        g_match_info_free(match_info);
        match_info = NULL;
    }

    g_free(user);
    g_free(body);

    return linkstr;
}
