# ==================================================================
# Plugins::SocialMedia - Auto Generated Program Module
#
#   Plugins::SocialMedia
#   Author  : Gossamer Threads Inc.
#   Version : 1.0
#   Updated : Tue Oct 29 11:32:05 2013
#
# ==================================================================
#

package Plugins::SocialMedia;
# ==================================================================

use strict;
use GT::Base;
use GT::Plugins qw/STOP CONTINUE/;
use Links qw/:objects/;
use Links::Build;
use Links::SiteHTML;
use Net::Twitter;
use Links::Plugins;
use LWP::Simple;
use JSON;
use URI;
use utf8;
use vars  qw/$USE_HTML $TIME_START $TOTAL_TIME @CARP_NOT $GRAND_TOTAL/;
#use Scalar::Util 'blessed';
use GT::File::Tools qw/mkpath dirname/;
use Carp;

@CARP_NOT = 'GT::Plugins';

# Inherit from base class for debug and error methods
@Plugins::SocialMedia::ISA = qw(GT::Base);

# Your code begins here.


# PLUGIN HOOKS
# ===================================================================

sub post_twitter {
    my $link = shift;
    $link = format_link($link);
    $link || return;

# When no authentication is required:
    my $nt = Net::Twitter->new(legacy => 0);

    my $consumer_key = "u4xwsqHZBKrdWYPrKCm8Lw";
    my $consumer_secret = "vjDF6FjeoPJW0WVwgqMEJeuJzilgSIu5QbPGQnWrMI";
    my $token = "1921299666-fMicJMBunBjgBb4ieszHo6tYV0mQcbbaMZU5wSB";
    my $token_secret = "Ko9gPpBaLxqQj6u68EWdlgnPinGSseVzrzUvytWric";

#return { error => 'error posting...unknown' };
    my $tags = $IN->param('twitter_hash_tags');
    $tags =~ s/\s+//g;
    my @tags = split(',',$tags);
    my $newtags;
    for (@tags) {
        $newtags .= ' #' . $_;
    }
    my $post_title = $IN->param('twitter_status');

    my $len = length $link->{detailed_url};
    $len = 140 - 5 - $len;
    $post_title = substr($post_title,0,$len) . "..." if (length $post_title > $len);
    $post_title .= " " . $link->{detailed_url};
    $post_title .= $newtags;

# As of 13-Aug-2010, Twitter requires OAuth for authenticated requests
    $nt = Net::Twitter->new(
        traits   => [qw/API::RESTv1_1/],
        consumer_key        => $consumer_key,
        consumer_secret     => $consumer_secret,
        access_token        => $token,
        access_token_secret => $token_secret,
    );

    my $result;
    my $res = eval { $result = $nt->update($post_title) };
    if ( my $err = $@ ) {
        die $@ unless $err and $err->isa('Net::Twitter::Error');
        #warn "HTTP Response Code: ", $err->code, "\n",
        #"HTTP Message......: ", $err->message, "\n",
        #"Twitter error.....: ", $err->error, "\n";
        $result->{error} = $err->error;
    }

    return $result;
}

sub post_facebook {
# -------------------------------------------------------------------
    my $access_token = shift;
    my $id = shift; 
    my $link = format_link($id);

    if ($link->{facebook_hashtags}) {
        $link->{Description} .= " ";
        $link->{Description} .= $link->{facebook_hashtags};
    }

#Publish to a facebook page as admin
    my $cfg = Links::Plugins::get_plugin_user_cfg('Auth_Facebook');
    my $result = facebook_graph_api('/' . $cfg->{fb_fanpageid} . '/links',{
        link => "http://www.slowtwitch.com/temp/$id.html",
        #link => $link->{detailed_url},
        message => $link->{Description},
        picture => $link->{Picture},
        access_token => $access_token,
        method => 'post'
    });

    return $result;
}

sub facebook_graph_api {
# -------------------------------------------------------------------
    my $uri = new URI('https://graph.facebook.com/' . shift);
    $uri->query_form(shift);

    require GT::WWW;
    my $www = GT::WWW->get("$uri");
    my $resp = $www->content;
    return defined $resp ? decode_json($resp) : undef;
}

sub format_link {
# -------------------------------------------------------------------
    my $link = shift;
    if ($link =~ /^(\d+)$/) {
        $link = $DB->table('Links')->get($link);
    }
    $link or return;
    $link = Links::SiteHTML::tags('link',$link);

    my $len = length $link->{detailed_url};
    $len = 140 - 5 - $len;
    $link->{Description} = substr($link->{Description},0,$len) . "..." if (length $link->{Description} > $len);

    my @cats = $DB->table('Category', 'CatLinks')->select('Category.Full_Name', { 'CatLinks.LinkID' => $link->{ID} })->fetchall_list;
    $link->{Category}      = join "\n", sort @cats;

    use Plugins::SlideShow;
    my $paths = Plugins::SlideShow::generate_paths($link->{ID});
    $link->{image_paths} = $paths;
    my $img = $link->{facebook_published_image} || "Image1";
    $link->{Picture} = $paths->{$img . '_largest_path'} if ($paths->{$img . '_largest_path'});

    return $link;
}

sub publish_it {
# -------------------------------------------------------------------
    if ($IN->param('build')) {
        my $linkid = $IN->param('linkid');
        my ($twitter, $fb); 
        use Time::HiRes;
        #Time::HiRes::sleep(5); #.1 seconds
        #print $IN->header;
        $IN->param('t','dev'); #FIXME
        #print $IN->header;
        build_it($linkid);
        my $hash = {};

        #print Links::user_page('add_success_publish.html', { success => '1', built => 1, twitter => $twitter, %$hash });
        #return;

        if ($IN->param('post_facebook')) {
            if ($IN->param('post_twitter')) {
                my $res = post_twitter($linkid);
                if ($res->{id}) {
                    $DB->table('Links')->update({ twitter_published => $res->{id} }, { ID => $linkid });
                    $hash->{twitter_published} = 1;
                }
                else {
                    $DB->table('Links')->update({ twitter_published_message => $res->{error} }, { ID => $linkid });
                    $hash->{twitter_published_message} = $res->{error} if ($res->{error});
                }
            }
            use Plugins::Auth_Facebook;
            Plugins::Auth_Facebook::user_auth($linkid);
            return;
        }
        elsif ($IN->param('post_twitter')) {
            my $res = post_twitter($linkid);
            if ($res->{id}) {
                $DB->table('Links')->update({ twitter_published => $res->{id} }, { ID => $linkid });
                $hash->{twitter_published} = 1;
            }
            else {
                $DB->table('Links')->update({ twitter_published_message => $res->{error} }, { ID => $linkid });
                $hash->{twitter_published_message} = $res->{error} if ($res->{error});
            }
        }
        $IN->param('t','dev'); #FIXME
        print $IN->header;
        print Links::user_page('add_success_publish.html', { success => '1', built => 1, twitter => $twitter, %$hash });
    }
    else {
        print $IN->header;
        print Links::user_page('error.html', { error => 'no error' });
    }
}

sub build_it {
# -------------------------------------------------------------------
#
    my $linkid = shift || return;
    my $unix_time = $CFG->{last_build} ? $CFG->{last_build} : time;
    Links::init_date();
    my $time = GT::Date::date_get($unix_time - $CFG->{date_offset} * 3600, '%yyyy%-%mm%-%dd% %HH%:%MM%:%ss%');

=tag
# Do any backups.
    _build_backup();

# Update isNew, isCool, isPopular flags.
    _build_reset_hits();
    _build_new_flags();
    _build_changed_flags();
    _build_cool_flags();

# Build Home Page.
    $PLG->dispatch('create_home', \&_build_home, {});
=cut

=tag
# Build New Page.
    $PLG->dispatch('create_new', \&_build_new, {});

# Build Cool Page.
    $PLG->dispatch('create_cool', \&_build_cool, {});

# Build Ratings Page.
    $PLG->dispatch('create_ratings', \&_build_ratings, {});
=cut

# Build Changed Detailed Page.
    $PLG->dispatch('create_detailed_changed', \&_build_detailed, GT::SQL::Condition->new('Links.ID', '=', $linkid));

=tag
# Build Changed Category Pages.
    $PLG->dispatch('create_category_changed', \&_build_category, GT::SQL::Condition->new('Timestmp', '>', $time));

    $CFG->{last_build} = time;
    $CFG->save;
=cut

}

sub get_path {
# -------------------------------------------------------------------
#
    my $field = shift;
    my $filefield = $field . "_largest_path";
    my $link = GT::Template->tags();
    if (!$link->{$filefield}) {
        $filefield = $field . "_medium_path";
    }
    return $link->{$filefield};
}

# ------------------------------------------------------------------
# MISC BUILD functions
# ------------------------------------------------------------------
sub _build_home {
# ------------------------------------------------------------------
# Generate the home page.
#
    _time_start();

    my $index = $CFG->{build_home} || $CFG->{build_index};
    my $page = "$CFG->{build_root_path}/$index";
    print $USE_HTML
        ? qq'Building <a href="$CFG->{build_root_url}/$index" target="_blank">Home Page</a>...\n'
        : qq'Building Home Page...\n';

    my $fh = _open_write($page);
    print $fh Links::Build::build(home => {});
    close $fh;
    my $perms = oct $CFG->{build_file_per};
    chmod $perms, $page;

    _display_time();
}

sub _build_detailed {
# ------------------------------------------------------------------
# Generate one html page per link.
#
    require Links::Tools;

    my ($cond, $cust_page, $cust_limit);
    if (ref $_[0] eq 'HASH') {
        $cust_page = $_[0]->{page};
        $cust_limit = $_[0]->{limit};
    }
    else {
        $cond = shift;
    }
    unless ($CFG->{build_detailed}) {
        print "Skipping Detailed Build (disabled).\n\n";
        return;
    }

    _time_start();

    #print "Building Detailed pages...\n";

# Only build validated links
    $cond ||= GT::SQL::Condition->new;
    $cond->add(VIEWABLE);

# Loop through, building 1000 at a time
    my ($limit, $offset, $count, $second_pass) = (1000, 0, 0);
    my $rel = $DB->table(qw/Links CatLinks Category/);
    #print "\t";

    my $Links = $DB->table('Links');
    while () {
# Links can be in multiple categories, make sure their detailed pages are only built once
        $rel->select_options("GROUP BY LinkID") if $CFG->{build_detail_format} eq '%ID%';
        $rel->select_options("ORDER BY LinkID");

        if ($cust_page or $cust_limit) {
            last if $second_pass++;
            $rel->select_options(sprintf "LIMIT %d OFFSET %d", $cust_limit, ($cust_page-1) * $cust_limit);
        }
        else {
            $rel->select_options(sprintf "LIMIT %d OFFSET %d", $limit, $offset*$limit);
        }
        my %links_cols = %{$Links->cols};
        # Only select Category columns that don't conflict with Links columns.
        my @cat_cols = grep !$links_cols{$_}, keys %{$DB->table('Category')->cols};

        my $sth = $rel->select('Links.*', @cat_cols, 'CategoryID' => $cond);

        last unless $sth->rows;

        while (my $link = $sth->fetchrow_hashref) {
            my $format = $Links->detailed_url($link);
            $format = "temp/" . $link->{ID} . ".html"; #FIXME
            my $page = "$CFG->{build_detail_path}/$format";
            my $url  = "$CFG->{build_detail_url}/$format";

            {
                my $fh = _open_write($page);
                print $fh Links::Build::build(detailed => $link);
            }
            my $perms = oct $CFG->{build_file_per};
            chmod $perms, $page;

=tag
            $USE_HTML ?
                print qq'<a href="$url" target="_blank">$link->{ID}</a> ' :
                print "$link->{ID} ";
            print "\n\t" if ++$count % 20 == 0;
=cut
        }
        $offset++;
    }
=tag
    print "\n";
    _display_time();
=cut
}

sub _build_category {
# ------------------------------------------------------------------
# Generate the category pages.
#
    my ($cond, $cust_page, $cust_limit);
    if (ref $_[0] eq 'HASH') {
        $cust_page  = $_[0]->{page};
        $cust_limit = $_[0]->{offset};
        $cond = {};
    }
    else {
        $cond = shift;
    }

    _time_start();

    print "Building Category pages...\n\n";

    my $Cat = $DB->table('Category');
    my $CatLinks = $DB->table('Links', 'CatLinks');

    $Cat->select_options('ORDER BY Full_Name');
    if (defined $cust_page and $cust_limit) {
        $Cat->select_options(sprintf "LIMIT %d OFFSET %d", $cust_limit, ($cust_page-1)*$cust_limit);
    }
    my $sth = $Cat->select(ID => Full_Name => $cond);
    while (my ($id, $name) = $sth->fetchrow_array) {
        my $clean_name = $Cat->as_url($name);
        my $page = $CFG->{build_root_path} . "/" . $clean_name . '/' . $CFG->{build_index};
        my $url  = $CFG->{build_root_url}  . "/" . $clean_name . '/' . $CFG->{build_index};
        print $USE_HTML
            ? "\tBuilding category <a href='$url' target='_blank'>$name</a>...\n"
            : "\tBuilding category $name...\n";
        my $total = $CatLinks->count({ 'CatLinks.CategoryID' => $id }, VIEWABLE);
        print "\t\tLinks: $total\n";

# Do sub-pages if requested.
        if ($CFG->{build_span_pages}) {
            my $lpp       = $CFG->{build_links_per_page} || 25;
            my $num_pages = int($total / $lpp);
            $num_pages++ if $total % $lpp;

# Create the main page.
            {
                my $fh = _open_write($page);
                print $fh Links::Build::build(category => { id => $id,  nh => 1, mh => $lpp });
            }
            my $perms = oct $CFG->{build_file_per};
            chmod $perms, $page;

# Create the sub pages.
            for (2 .. $num_pages) {
                $page = "$CFG->{build_root_path}/$clean_name/$CFG->{build_more}$_$CFG->{build_extension}";
                $url  = "$CFG->{build_root_url}/$clean_name/$CFG->{build_more}$_$CFG->{build_extension}";
                print "\t\tBuilding subpage: " . ($USE_HTML
                    ? "<a href='$url' target='_blank'>$_</a>\n"
                    : "$_\n"
                );
                {
                    my $fh = _open_write($page);
                    print $fh Links::Build::build(category => { id => $id, nh => $_, mh => $lpp });
                }
                chmod $perms, $page;
            }
        }
        else {
            {
                my $fh = _open_write($page);
                print $fh Links::Build::build(category => { id => $id });
            }
            my $perms = oct $CFG->{build_file_per};
            chmod $perms, $page;
        }
        print "\tDone\n\n";
    }
    _display_time("Finished building categories");
}

sub _build_backup {
# ------------------------------------------------------------------
# Create a backup file in our backup directory.
#
    if (! $CFG->{build_use_backup}) {
        print "Creating backup file... skipped\n\n";
        return;
    }
    _time_start();
    print "Creating backup file...\n";
    require Links::Import::S2BK;

    my $max_keep = 7;
    my $root     = $CFG->{admin_root_path} . '/backup';
    my $filename = 'BACKUP';

    for my $n (reverse 0 .. $max_keep) {
        my $oldname = join '.', $filename, $n || ();
        my $newname = join '.', $filename, $n+1;
        if (-e "$root/$oldname") {
            rename "$root/$oldname", "$root/$newname" or print "\tCouldn't rename '$root/$oldname' -> '$root/$newname': $!";
        }
    }
    Links::Import::S2BK::import({ source => "$CFG->{admin_root_path}/defs", destination => "$root/$filename", delimiter => "\t" }, sub { print "\n\tWARNING: @_\n" }, sub { die @_ }, sub { print "\n\tWARNING: @_\n" }, sub { });
    _display_time();
}

sub _build_reset_hits {
# ------------------------------------------------------------------
# Updates the What's New flags.
#
    _time_start();
    print "Resetting hits and rates...\n";
    my $ret = Links::Build::build(reset_hits => shift || {});
    _display_time();
    return $ret;
}

sub _build_new_flags {
# ------------------------------------------------------------------
# Updates the What's New flags.
#
    _time_start();
    print "Updating new flags...\n";
    my $ret = Links::Build::build(new_flags => shift || {});
    _display_time();
    return $ret;
}

sub _build_changed_flags {
# ------------------------------------------------------------------
# Updates the isChanged flags.
#
    _time_start();
    print "Updating changed flags...\n";
    my $ret = Links::Build::build(changed_flags => shift || {});
    _display_time();
    return $ret;
}

sub _build_cool_flags {
# ------------------------------------------------------------------
# Updates the What's Cool flags.
#
    _time_start();
    print "Updating Cool Flags...\n";
    my $ret = Links::Build::build(cool_flags => shift || {});
    _display_time();
    return $ret;
}

sub _time_start {
# ------------------------------------------------------------------
# Start a timer.
#    
    $TIME_START = time;
}

sub _display_time {
# ------------------------------------------------------------------
# Return time results.
#
    my $message = shift || 'Done';
    return;
    printf "%s (%.2fs)\n\n", $message, time - $TIME_START;
}

sub _header {
# ------------------------------------------------------------------
# Print intro.
#
    my ($msg, $msg2, $refresh, $started) = @_;
    my $time    = scalar localtime;

    $refresh ||= '';
    $TOTAL_TIME = $started || time;
    $refresh  &&= "<meta http-equiv='Refresh' content='2; URL=$refresh'>";
    if ($USE_HTML) {
        print $IN->header(-nph => $CFG->{nph_headers});
        print <<BUILDING;
<html>
<head>
$refresh
<title>Building HTML Pages</title>
<body bgcolor="white">
BUILDING
        print Links::header("Building HTML Pages: $msg", $msg2, 0);
        print <<STARTED;
<pre>Started at $time.

STARTED
    }
    else {
        print "Started at $time.\n\nBuilding HTML pages...\n\n";
    }
}

sub _footer {
# ------------------------------------------------------------------
# Print the footer.
#
    my $end = time;
    my $elapsed = sprintf "%.2f", $end - $TOTAL_TIME;

    print "All done. Total time: (${elapsed}s)\n";
    print "</pre></body></html>" if $USE_HTML;
}

sub _open_write {
# -----------------------------------------------------------------------------
# Opens a file for writing (overwriting anything already there), and returns a
# filehandle reference.  Dies with a more user-friendly error then Links::fatal
# if the open fails.  Can take a second argument which, if true, will cause the
# function _not_ to attempt to make the containing directory.
#
    my ($page, $nomkdir) = @_;
    unless ($nomkdir) {
        mkpath(dirname($page), oct $CFG->{build_dir_per});
    }
    my $fh = \do { local *FH; *FH };
    open $fh, "> $page" and return $fh;

    my $error = "$!";
    my $user = eval { getpwuid($>) } || 'webserver';
    if ($error =~ /permission/i) {
        print "\n\n<b>ERROR:</b> Unable to open '$page': $error\n\n";
        if (-e $page) {
            print <<HELP;
This means that the user '$user' is not able to overwrite the existing file.
Please make sure you have set the permissions in the setup to 0666 if you plan
to build from both the web and shell at the same time.

HELP
        }
        else {
            print <<HELP;
This means that the user '$user' is not able to create a file in your pages
directory. Please chmod the main directory 0777 so the program can create the
file.

HELP
        }
        croak "Debug information";
    }
    else {
        croak "Unable to open: '$page': $error";
    }
}

1;

