package Buffy::CLI;

# buffycli is Copyright 2008 Penny Leach <penny@mjollnir.org>

# This file is part of buffycli.

# buffycli 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.

# buffycli 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 buffycli.  If not, see <http://www.gnu.org/licenses/>.

use strict;
use Buffy;
use Text::FormatTable;
use Tie::IxHash; # rage

our $VERSION = '0.2.1';

tie my %allcolumns => 'Tie::IxHash',
    name  => {
        align => 'l',
        key   => 'F',
    },
    new     => {
        align => 'r',
        key   => 'N',
    },
    unread  => {
        align => 'r',
        key   => 'U',
    },
    flagged => {
        align => 'r',
        key   => 'FL',
    },
    total => {
        align => 'r',
        key   => 'T',
    };


my @FIELDS = qw(
    config
    locations
    lastinteresting
    columns
    totals
);

#Accessors
sub createFieldAccessor {
  my ($field) = @_;
  no strict 'refs';
  *$field = sub {
      my $self = shift;
      return $self->{$field};
  };
}

createFieldAccessor($_) foreach @FIELDS;
sub new {
    my $class = shift;
    my $config = Buffy::Config->new();
    $config->application('buffycli')->addDefault('ordercolumn', 'new');
    $config->application('buffycli')->addDefault('orderreverse', '1');
    $config->application('buffycli')->addDefault('columns', (join ' ', (grep { !/^name$/ } keys %allcolumns )));
    $config->application('buffycli')->addDefault('showusage', '0');
    $config->application('buffycli')->addDefault('showtotals', 'true');
    $config->save();
    my $self = {
        config          => $config,
        locations       => $config->locations(),
        lastinteresting => [],
        columns         => [ split ' ', $config->application('buffycli')->get('columns') ] ,
        totals          => {},
    };
    bless $self, $class;
    return $self;

}

sub updateInteresting {
    my $self = shift;
    $self->{lastinteresting} = [];
    $self->{totals} = {
        new     => 0,
        unread  => 0,
        flagged => 0,
        total   => 0,
    };
    for (my $i=0; $i<$self->locations()->size(); $i++) {
        my $location = $self->locations()->get($i);
        foreach my $folder (@{Buffy::MailFolder::enumerateFolders($location)}) {
            my $fn = $self->config->folder($folder->path());
            next if $fn->forcehide();
            $folder->updateStatistics();
            unless ($fn->forceview()) {
                next if ($folder->getMsgUnread() == 0
                    && $folder->getMsgNew()      == 0
                    && $folder->getMsgFlagged()  == 0);
            }
            my $stats =  {
                new     => $folder->getMsgNew(),
                name    => $folder->name(),
                path    => $folder->path(),
                unread  => $folder->getMsgUnread(),
                flagged => $folder->getMsgFlagged(),
                total   => $folder->getMsgTotal(),
                folder  => $folder,
            };
            if ($self->{config}->application('buffycli')->getBool('showtotals')) {
                foreach my $key (keys %{$self->{totals}}) {
                    $self->totals->{$key} += $stats->{$key};
                }
            }
            push @{$self->lastinteresting}, $stats;
        }
    }
    my @sorted = sort { $self->userSort($a, $b) } @{$self->lastinteresting};
    $self->{lastinteresting} = \@sorted;
}


sub printInteresting {
    my $self = shift;
    $self->updateInteresting();
    my $index = 0;
    my $headerformat = 'r | l'; #always start with the index and folder name
    my @headernames = ("", "[F]older");
    foreach my $col (@{$self->columns}) {
        $headerformat .= ' | ' . $allcolumns{$col}->{align};
        my $key = lc $allcolumns{$col}->{key};
        my $display = $col;
        $display =~ s/^($key)/[\U$1]/;
        push @headernames, $display;
    }
    my $table = Text::FormatTable->new($headerformat);
    $table->head(@headernames);
    $table->rule('=');
    if (@{$self->lastinteresting}) {
        foreach my $stats (@{$self->lastinteresting}) {
            my @cells = ("[$index]", $stats->{name});
            push @cells, (map $stats->{$_}, @{$self->columns});
            $table->row(@cells);
            $index++;
        }
        if ($self->{config}->application('buffycli')->getBool('showtotals')) {
            $table->rule('=');
            my @cells = ("", "TOTALS");
            push @cells, (map $self->totals->{$_}, @{$self->columns});
            $table->row(@cells);
        }
        $table->rule('=');
    }
    print $table->render(20);
}


sub raiseInputMessage {
    my ($self, $message) = @_;
    print "\n$message\n";
    sleep 2;
}

sub userSort {
    my $self = shift;
    my $sortkey = $self->config->application('buffycli')->get('ordercolumn');
    my $reversesort = $self->config->application('buffycli')->getBool('orderreverse');

    my ($_a, $_b) = $reversesort ? ($b, $a) : ($a, $b);

    return $_a->{$sortkey} cmp $_b->{$sortkey} if $sortkey eq 'name';
    return $_a->{$sortkey} <=> $_b->{$sortkey};
}

sub setShowTotals {
    my $self = shift;
    my $setting = shift;
    $self->config->application('buffycli')->setBool('showtotals', $setting);
    $self->config->save();
}

sub setShowUsage {
    my $self = shift;
    $self->config->application('buffycli')->setBool('showusage',
        !$self->config->application('buffycli')->getBool('showusage'));
    $self->config->save();
}

sub getShowUsage {
    my $self = shift;
    return $self->config->application('buffycli')->getBool('showusage');
}

sub setInterval {
    my $self = shift;
    my $interval = shift;
    $self->config->general->setInterval($interval);
    $self->config->save();
}

sub setOrder {
    my $self = shift;
    my $key = shift;
    my ($column) = $self->_resolveColumn ($key)
        or return $self->raiseInputError("invalid sort column");

    my $currentorder = $self->config->application('buffycli')->get('ordercolumn');
    $self->config->application('buffycli')->set('ordercolumn', $column);
    if ($currentorder eq $column) {
        $self->config->application('buffycli')->setBool('orderreverse',
            !$self->config->application('buffycli')->getBool('orderreverse'));
    }
    else {
        $self->config->application('buffycli')->setBool('orderreverse', 0);
    }
    $self->config->save();
}

sub showColumn {
    my $self = shift;
    my $key = shift;
    if ($key eq 'all') {
        $self->{columns} = [ grep { !/^name$/ } keys %allcolumns ];
        return;
    }
    return if $key eq 'F';
    my ($column) = $self->_resolveColumn ($key)
        or return $self->raiseInputError("invalid column to hide");

    return if (grep (/$column/,  @{$self->columns}));
    my @columns = keys %allcolumns;
    my( $origindex )= grep $columns[$_] eq $column, 0..$#columns;
    $origindex--; # allcolumns has the folder name on the start
    splice @{$self->columns}, $origindex, 0, $column ;
    $self->config->application('buffycli')->set('columns', (join ' ', @{$self->columns}));
    $self->config->save();
}

sub hideColumn {
    my $self = shift;
    my $key = shift;
    my ($column) = $self->_resolveColumn ($key)
        or return $self->raiseInputError("invalid column to hide");

    return $self->raiseInputError("Folder name cannot be hidden") if $key eq 'F';

    $self->{columns} = [ grep { !/^$column$/ }  @{$self->columns} ];
    $self->config->application('buffycli')->set('columns', (join ' ', @{$self->columns}));
    $self->config->save();
}

sub showAllFolders {
    my $self = shift;
    for (my $i=0; $i<$self->locations()->size(); $i++) {
        my $location = $self->locations()->get($i);
        foreach my $folder (@{Buffy::MailFolder::enumerateFolders($location)}) {
            my $fn = $self->config->folder($folder->path());
            $fn->setForceHide(0) if $fn->forcehide();
        }
    }
    $self->config->save();
}

sub showFolders {
    my $self = shift;
    my $indexes = shift;

    foreach my $index (@$indexes) {
        my $folder = $self->lastinteresting()->[$index]
            or return $self->raiseInputError("invalid folder to always show");

        my $fn = $self->config->folder($folder->{path});
        $fn->setForceView(1);
    }
    $self->config->save();
}

sub hideFolders {
    my $self = shift;
    my $indexes = shift;

    foreach my $index (@$indexes) {
        my $folder = $self->lastinteresting()->[$index]
            or return $self->raiseInputError("invalid folder to always hide");

        my $fn = $self->config->folder($folder->{path});
        $fn->setForceHide(1);
    }
    $self->config->save();
}

sub _resolveColumn {
    my $self = shift;
    my $column = shift;
    return grep {  $allcolumns{$_}->{key} eq $column } keys %allcolumns;
}


1;

