# Arch Perl library, Copyright (C) 2004 Mikhael Goikhman, Enno Cramer
#
# This program 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 2 of the License, or
# (at your option) any later version.
#
# This program 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 this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

use 5.006;
use strict;
use warnings;

package ArchWay::Widget::Inventory::Directory;

use Glib qw(TRUE FALSE);

use Arch::Inventory qw(:category :type);
use Arch::Changes qw(:type);
use POSIX qw(strftime);

use base qw(ArchWay::Widget::Tree);

use constant MODEL_COL_TYPES => qw(
	Glib::String
	Glib::String
	Glib::String
	Glib::String
	Glib::String
	Glib::String
	Glib::String

	Glib::String
	Glib::UInt
	Glib::UInt

	Glib::Scalar
);

use constant MODEL_COL_TYPE     => 0;
use constant MODEL_COL_CATEGORY => 1;
use constant MODEL_COL_NAME     => 2;
use constant MODEL_COL_STATUS   => 3;
use constant MODEL_COL_SIZE     => 4;
use constant MODEL_COL_MODE     => 5;
use constant MODEL_COL_MODIFIED => 6;
use constant MODEL_COL_SORT_NAME => 7;
use constant MODEL_COL_SORT_SIZE => 8;
use constant MODEL_COL_SORT_MODIFIED => 9;
use constant MODEL_COL_ENTRY    => 10;

my %CATEGORY_NAMES = (
	TREE()         => 'Arch Tree Root',
	SOURCE()       => 'Source',
	PRECIOUS()     => 'Precious',
	BACKUP()       => 'Backup',
	JUNK()         => 'Junk',
	UNRECOGNIZED() => 'Unrecognized',
);

sub new ($$) {
	my $class     = shift;
	my $inventory = shift;

	my $self = $class->SUPER::new(Gtk2::ListStore->new(MODEL_COL_TYPES));
	$self->add_columns(
		{
			title  => 'Filename',
			renderers => [
				{
					class   => 'Gtk2::CellRendererPixbuf',
					static  => {},
					dynamic => { stock_id => MODEL_COL_TYPE },
				},
				{
					class   => 'Gtk2::CellRendererText',
					static  => {},
					dynamic => { text => MODEL_COL_NAME },
				},
			],
			sort_column => MODEL_COL_SORT_NAME,
		},
		{
			title  => 'Category',
			renderer => {
				class   => 'Gtk2::CellRendererText',
				static  => {},
				dynamic => { text => MODEL_COL_CATEGORY },
			},
			sort_column => MODEL_COL_CATEGORY,
		},
		{
			title  => 'Status',
			renderer => {
				class   => 'Gtk2::CellRendererText',
				static  => {},
				dynamic => { text => MODEL_COL_STATUS },
			},
			sort_column => MODEL_COL_STATUS,
		},
		{
			title  => 'Size',
			renderer => {
				class   => 'Gtk2::CellRendererText',
				static  => { xalign => 1.0 },
				dynamic => { markup => MODEL_COL_SIZE },
			},
			sort_column => MODEL_COL_SORT_SIZE,
		},
		{
			title  => 'Mode',
			renderer => {
				class   => 'Gtk2::CellRendererText',
				static  => {},
				dynamic => { markup => MODEL_COL_MODE },
			},
		},
		{
			title  => 'Last Modified',
			renderer => {
				class   => 'Gtk2::CellRendererText',
				static  => {},
				dynamic => { markup => MODEL_COL_MODIFIED },
			},
			sort_column => MODEL_COL_SORT_MODIFIED,
		}
	);
	
	$self->get_model->set_sort_column_id(MODEL_COL_SORT_NAME, 'ascending');
	$self->set_search_column(MODEL_COL_NAME);
	$self->show($inventory) if ($inventory);

	return $self;
}

sub get_selected_path ($) {
	my $self = shift;

	return $self->get_selection->count_selected_rows
		? $self->get_selected(MODEL_COL_ENTRY)->{path}
		: undef;
}

sub select_by_path ($$) {
	my $self = shift;
	my $path = shift;

	$self->select(sub { $_[0]->get($_[1], MODEL_COL_ENTRY)->{path} eq $path });
}

sub show ($$$) {
	my $self      = shift;
	my $inventory = shift;
	my $parent    = shift;

	my $model = $self->get_model;
	$model->clear;

	return unless (defined $inventory);

	list_model_append($model, '.',  $inventory);
	list_model_append($model, '..', $parent)
		if $parent;

	foreach my $name (sort keys %{$inventory->{children}}) {
		list_model_append($model, $name, $inventory->{children}->{$name});
	}

	$self->get_selection->select_iter($self->get_model->iter_nth_child(undef, 0));	
}

sub inventory_entry_status ($) {
	my $entry = shift;

	my $status;
	if (exists $entry->{changes}) {
		if (exists $entry->{changes}->{ADD()}) {
			$status = 'New';
		} elsif (exists $entry->{changes}->{REMOVE()}) {
			$status = 'Removed';
		} else {
			$status = 'Modified';
		}
	} elsif ($entry->{category} eq SOURCE) {
		$status = 'Unmodified';
	} else {
		$status = 'Not arch controlled';
	}

	return $status;
}

sub list_model_append ($$$) {
	my ($model, $name, $entry) = @_;

	my $stockid;

	if ($entry->{type} eq DIRECTORY) {
		$stockid = 'gtk-directory';
	} elsif ($entry->{type} eq SYMLINK) {
		$stockid = 'gtk-redo';
	} else {
		$stockid = 'gtk-file';
	}

	my $iter = $model->append;
	$model->set($iter,
		MODEL_COL_TYPE,     $stockid,
		MODEL_COL_CATEGORY, $CATEGORY_NAMES{$entry->{category}},
		MODEL_COL_NAME,     $name,
		MODEL_COL_STATUS,   inventory_entry_status($entry),

		# sort . and .. first, then directories, then files
		MODEL_COL_SORT_NAME, (
			$name =~ /^\.\.?$/ ? 0 : $entry->{type} eq DIRECTORY ? 1 : 2
		) . $name,

		MODEL_COL_ENTRY,    $entry,
	);

	if ($entry->{stat}) {
		$model->set($iter,
			MODEL_COL_SIZE,     $entry->{stat}->[7],
			MODEL_COL_MODE,     mode_string($entry->{stat}->[2]),
			MODEL_COL_MODIFIED, strftime('%c', localtime($entry->{stat}->[9])),

			MODEL_COL_SORT_SIZE,     $entry->{stat}->[7],
			MODEL_COL_SORT_MODIFIED, $entry->{stat}->[9],
		);
	} else {
		$model->set($iter,
			MODEL_COL_SIZE,     '<i>unknown</i>',
			MODEL_COL_MODE,     '<i>unknown</i>',
			MODEL_COL_MODIFIED, '<i>unknown</i>',

			MODEL_COL_SORT_SIZE,     0,
			MODEL_COL_SORT_MODIFIED, 0,
		);
	}
}

sub mode_string ($) {
	my $mode = shift;

	my @modes = qw(--- --x -w- -wx r-- r-x rw- rwx);
	my %types = ( 4 => 'd', 8 => '-', 10 => 'l' );

	return ($types{$mode >> 12} || '?') .
		join('', map { $modes[($mode >> 3*$_) & 7] } (2, 1, 0));
}

1;

__END__
