package Padre::Wx::StatusBar;

=pod

=head1 NAME

Padre::Wx::StatusBar - Encapsulates status bar customizations

=head1 DESCRIPTION

C<Padre::Wx::StatusBar> implements Padre's status bar. It is the bottom
pane holding various, err, status information on Padre.

The information shown are (in order):

=over 4

=item * File name of current document, with a leading star if file has
been updated and not saved

=item * (Optional) Icon showing status of background tasks

=item * (Optional) MIME type of current document

=item * Type of end of lines of current document

=item * Position in current document

=back

It inherits from C<Wx::StatusBar>, so check Wx documentation to see all
the available methods that can be applied to it besides the added ones
(see below).

=cut

use 5.008;
use strict;
use warnings;
use Padre::Constant            ();
use Padre::Current             ();
use Padre::Util                ();
use Padre::Wx                  ();
use Padre::Wx::Icon            ();
use Padre::Wx::Role::MainChild ();
use Padre::MimeTypes           ();

use Class::XSAccessor accessors => {
	_task_sbmp   => '_task_sbmp',   # Static bitmap holding the task status
	_task_status => '_task_status', # Current task status
	_task_width  => '_task_width',  # Current width of task field
};

our $VERSION = '0.54';
our @ISA     = qw{
	Padre::Wx::Role::MainChild
	Wx::StatusBar
};

use constant {
	FILENAME    => 0,
	TASKLOAD    => 1,
	HIGHLIGHTER => 2,
	MIMETYPE    => 3,
	NEWLINE     => 4,
	POSTRING    => 5,
	RDONLY      => 6,
};

#####################################################################

=pod

=head1 METHODS

=head2 C<new>

    my $statusbar = Padre::Wx::StatusBar->new( $main );

Create and return a new Padre status bar. One should pass the C<$main>
Padre window as argument, to get a reference to the status bar parent.

=cut

sub new {
	my $class = shift;
	my $main  = shift;

	# Create the basic object
	my $self = $class->SUPER::new(
		$main,
		-1,
		Wx::wxST_SIZEGRIP | Wx::wxFULL_REPAINT_ON_RESIZE
	);

	$self->{main} = $main;

	# create the static bitmap that will hold the task load status
	my $sbmp = Wx::StaticBitmap->new( $self, -1, Wx::wxNullBitmap );
	$self->_task_sbmp($sbmp);
	$self->_task_status('foobar'); # init status to sthg defined
	Wx::Event::EVT_LEFT_DOWN(
		$sbmp,
		sub {
			require Padre::TaskManager;
			Padre::TaskManager::on_dump_running_tasks(@_);
		},
	);

	# Set up the fields
	$self->SetFieldsCount(7);

	#$self->SetStatusWidths( -1, 0, 100, 100, 50, 100 );

	# react to resize events, to adapt size of icon field
	Wx::Event::EVT_SIZE( $self, \&on_resize );

	return $self;
}

#####################################################################

=pod

=head2 C<clear>

    $statusbar->clear;

Clear all the status bar fields, i.e. they will display an empty string
in all fields.

=cut

sub clear {
	my $self = shift;
	$self->SetStatusText( "", FILENAME );
	$self->SetStatusText( "", HIGHLIGHTER );
	$self->SetStatusText( "", MIMETYPE );
	$self->SetStatusText( "", NEWLINE );
	$self->SetStatusText( "", POSTRING );
	$self->SetStatusText( "", RDONLY );
	return;
}

=pod

=head2 C<refresh>

    $statusbar->refresh;

Force an update of the document fields in the status bar.

=cut

sub refresh {
	my $self    = shift;
	my $current = $self->current;

	# Blank the status bar if no document is open
	my $editor = $current->editor or return $self->clear;

	# Prepare the various strings that form the status bar
	my $main     = $self->{main};
	my $notebook = $current->notebook;
	my $document = $current->document;
	my $newline  = $document->get_newline_type || Padre::Constant::NEWLINE;
	my $pageid   = $notebook->GetSelection;
	my $filename = $document->filename || '';
	my $old      = $notebook->GetPageText($pageid);
	my $text =
		$filename
		? File::Basename::basename($filename)
		: substr( $old, 1 );
	$self->{_last_editor}   = $editor;
	$self->{_last_modified} = $editor->GetModify;
	my $modified       = $self->{_last_modified} ? '*' : ' ';
	my $title          = $modified . $text;
	my $position       = $editor->GetCurrentPos;
	my $line           = $editor->GetCurrentLine;
	my $start          = $editor->PositionFromLine($line);
	my $lines          = $editor->GetLineCount;
	my $char           = $position - $start;
	my $width          = $self->GetCharWidth;
	my $highlighter    = Padre::MimeTypes->get_highlighter_name( $document->get_highlighter );
	my $mime_type_name = Padre::MimeTypes->get_mime_type_name( $document->get_mimetype );
	my $percent        = int( 100 * $line / $lines );

	# Set some defaults to advoid "use of uninittialized value" - messages:
	$mime_type_name = '???' if !defined($mime_type_name);

	#my $postring  = Wx::gettext('L:') . ( $line + 1  ) . ' ' . Wx::gettext('Ch:') . "$char $percent%";
	my $format   = '%' . length( $lines + 1 ) . 's,%-3s %3s%%';
	my $length   = length( $lines + 1 ) + 8;
	my $postring = sprintf( $format, ( $line + 1 ), $char, $percent );
	my $rdstatus = $self->is_read_only;

	# update task load status
	$self->update_task_status;

	# Write the new values into the status bar and update sizes
	if (    defined( $main->{infomessage} )
		and ( $main->{infomessage} ne '' )
		and ( $main->{infomessage_timeout} > time ) )
	{
		$self->SetStatusText( $main->{infomessage}, FILENAME );
	} else {
		$self->SetStatusText( "$modified $filename", FILENAME );
	}
	$self->SetStatusText( $highlighter,    HIGHLIGHTER );
	$self->SetStatusText( $mime_type_name, MIMETYPE );
	$self->SetStatusText( $newline,        NEWLINE );
	$self->SetStatusText( $postring,       POSTRING );
	$self->SetStatusText( $rdstatus,       RDONLY );
	$self->SetStatusWidths(
		-1,
		$self->_task_width,
		( length($highlighter) + 2 ) * $width,
		( length($mime_type_name) + 2 ) * $width,
		( length($newline) + 2 ) * $width,
		( $length + 2 ) * $width,
		length($rdstatus) * $width,
	);

	# move the static bitmap holding the task load status
	$self->_move_bitmap;

	# Fixed ticket #190: Massive GDI object leakages
	# http://padre.perlide.org/ticket/190
	# Please remember to call SetPageText once per the same text
	# This still leaks but far less slowly (just on undo)
	if ( $old ne $title ) {
		$notebook->SetPageText( $pageid, $title );
	}

	return;
}

=pod

=head2 C<update_task_status>

    $statusbar->update_task_status;

Checks whether a task status icon update is in order and if so, changes
the icon to one of the other states

=cut

sub update_task_status {
	my $self   = shift;
	my $status = $self->_get_task_status;
	return if $status eq $self->_task_status; # Nothing to do

	# Store new status
	$self->_task_status($status);
	my $sbmp = $self->_task_sbmp;

	# If we're idling, just hide the icon in the statusbar
	if ( $status eq 'idle' ) {
		$sbmp->Hide;
		$sbmp->SetBitmap(Wx::wxNullBitmap);
		$sbmp->SetToolTip('');
		$self->_task_width(0);
		return;
	}

	# Not idling, show the correct icon in the statusbar
	$sbmp->SetBitmap( Padre::Wx::Icon::find("status/padre-tasks-$status") );
	$sbmp->SetToolTip(
		$status eq 'running'
		? Wx::gettext('Background Tasks are running')
		: Wx::gettext('Background Tasks are running with high load')
	);
	$sbmp->Show;
	$self->_task_width(20);
}

=pod

=head2 C<update_pos>

    $statusbar->update_pos;

Update the cursor position

=cut

sub update_pos {
	my $self = shift;

	my $current  = $self->current;
	my $editor   = $current->editor or return $self->clear;
	my $position = $editor->GetCurrentPos;

	# Skip expensive update if there is nothing to update:
	return if defined( $self->{Last_Pos} ) and ( $self->{Last_Pos} == $position );

	# Detect modification:
	unless (defined( $self->{_last_editor} )
		and ( $self->{_last_editor} eq $editor )
		and defined( $self->{_last_modified} )
		and ( $self->{_last_modified} == $editor->GetModify ) )
	{

		# Either the tab has changed or the file has been modified:
		$self->refresh;

	}

	$self->{Last_Pos} = $position;

	my $line    = $editor->GetCurrentLine;
	my $start   = $editor->PositionFromLine($line);
	my $lines   = $editor->GetLineCount;
	my $char    = $position - $start;
	my $percent = int( 100 * $line / $lines );

	my $format = '%' . length( $lines + 1 ) . 's,%-3s %3s%%';
	my $postring = sprintf( $format, ( $line + 1 ), $char, $percent );

	$self->SetStatusText( $postring, POSTRING );

}

#####################################################################

=pod

=head2 C<on_resize>

    $statusbar->on_resize( $event );

Handler for the C<EVT_SIZE> C<$event>. Used to move the task load bitmap to
its position.

=cut

sub on_resize {
	my ($self) = @_;

	# note: parent resize method will be called automatically

	$self->_move_bitmap;
	$self->Refresh;
}

#####################################################################
# Private methods

#
# my $status = $self->_get_task_status;
#
# return 'idle', 'running' or 'load' depending on the number of threads
# currently working.
#
sub _get_task_status {
	my $self    = shift;
	my $manager = $self->current->ide->task_manager;

	# still in editor start-up phase, default to idle
	return 'idle' unless defined $manager;

	my $running = $manager->running_tasks;
	return 'idle' unless $running;

	my $max_workers = $manager->max_no_workers;
	my $jobs        = $manager->task_queue->pending + $running;

	# high load is defined as the state when the number of
	# running and pending jobs is larger that twice the
	# MAXIMUM number of workers
	return ( $jobs > 2 * $max_workers ) ? 'load' : 'running';
}

#
# $statusbar->_move_bitmap;
#
# move the static bitmap holding the task load status to its proper location.
#
sub _move_bitmap {
	my ($self) = @_;
	my $sbmp   = $self->_task_sbmp;
	my $rect   = $self->GetFieldRect(TASKLOAD);
	my $size   = $sbmp->GetSize;
	$sbmp->Move(
		$rect->GetLeft + ( $rect->GetWidth - $size->GetWidth ) / 2,
		$rect->GetTop +  ( $rect->GetHeight - $size->GetHeight ) / 2,
	);
	$sbmp->Refresh;
}

sub is_read_only {
	my ($self) = @_;
	my $file = $self->current->document->file || '';
	my $is_rdonly = $file ? $file->readonly : undef;
	return $is_rdonly ? Wx::gettext('Read Only') : ':)';
}


1;

=pod

=head1 SEE ALSO

Icons for background status courtesy of Mark James, at
L<http://www.famfamfam.com/lab/icons/silk/>.

=head1 COPYRIGHT & LICENSE

Copyright 2008-2010 The Padre development team as listed in Padre.pm.

This program is free software; you can redistribute
it and/or modify it under the same terms as Perl itself.

The full text of the license can be found in the
LICENSE file included with this module.

=cut

# Copyright 2008-2010 The Padre development team as listed in Padre.pm.
# LICENSE
# This program is free software; you can redistribute it and/or
# modify it under the same terms as Perl 5 itself.
