package Padre::Wx::Notebook;

=pod

=head1 NAME

Padre::Wx::Notebook - Notebook that holds a set of editor objects

=head1 DESCRIPTION

B<Padre::Wx::Notebook> implements the tabbed notebook in the main window
that stores the editors for open documents in Padre.

=head1 METHODS

=cut

use 5.008;
use strict;
use warnings;
use Params::Util          ();
use Padre::Wx             ();
use Padre::Wx::Role::Main ();

our $VERSION = '1.00';
our @ISA     = qw{
	Padre::Wx::Role::Main
	Wx::AuiNotebook
};





######################################################################
# Constructor and Accessors

sub new {
	my $class = shift;
	my $main  = shift;
	my $aui   = $main->aui;

	# Create the basic object
	my $self = $class->SUPER::new(
		$main,
		-1,
		Wx::DefaultPosition,
		Wx::DefaultSize,
		Wx::AUI_NB_TOP | Wx::BORDER_NONE | Wx::AUI_NB_SCROLL_BUTTONS | Wx::AUI_NB_TAB_MOVE
			| Wx::AUI_NB_CLOSE_ON_ACTIVE_TAB | Wx::AUI_NB_WINDOWLIST_BUTTON
	);

	# Add ourself to the main window
	$aui->AddPane(
		$self,
		Padre::Wx->aui_pane_info(
			Name           => 'notebook',
			Resizable      => 1,
			PaneBorder     => 0,
			Movable        => 1,
			CaptionVisible => 0,
			CloseButton    => 0,
			MaximizeButton => 0,
			Floatable      => 1,
			Dockable       => 1,
			Layer          => 1,
			)->Center,
	);
	$aui->caption(
		'notebook' => Wx::gettext('Files'),
	);

	Wx::Event::EVT_AUINOTEBOOK_PAGE_CHANGED(
		$self, $self,
		sub {
			shift->on_auinotebook_page_changed(@_);
		},
	);

	Wx::Event::EVT_AUINOTEBOOK_PAGE_CLOSE(
		$main, $self,
		sub {
			shift->on_close(@_);
		},
	);

	return $self;
}





######################################################################
# GUI Methods

sub refresh {
	my $self = shift;

	# Hand off to the refresh_notebook method for each
	# of the individual editors.
	foreach my $editor ( $self->editors ) {
		$editor->refresh_notebook;
	}

	return;
}

# Do a normal refresh on relocale, that should be enough
sub relocale {
	$_[0]->refresh;
}





######################################################################
# Main Methods

=pod

=head2 show_file

  $notebook->show_file('/home/user/path/script.pl');

The C<show_file> method takes a single parameter of a fully resolved
filesystem path, finds the notebook page containing the editor for that
file, and sets that editor to be the currently selected foreground page.

Returns true if found and displayed, or false otherwise.

=cut

sub show_file {
	my $self = shift;
	my $file = shift or return;
	foreach my $i ( 0 .. $self->GetPageCount - 1 ) {
		my $editor   = $self->GetPage($i)  or next;
		my $document = $editor->{Document} or next;
		my $filename = $document->filename;
		if ( defined $filename and $file eq $filename ) {
			$self->SetSelection($i);
			return 1;
		}
	}
	return;
}





######################################################################
# Event Handlers

sub on_auinotebook_page_changed {
	my $self   = shift;
	my $main   = $self->main;
	my $lock   = $main->lock( 'UPDATE', 'refresh', 'refresh_outline' );
	my $editor = $self->current->editor;

	if ($editor) {
		my $page_history = $main->{page_history};
		my $current      = Scalar::Util::refaddr($editor);
		@$page_history = grep { $_ != $current } @$page_history;
		push @$page_history, $current;
	}

	# Hide the Find Fast panel when this changes
	$main->show_findfast(0);

	$main->ide->plugin_manager->plugin_event('editor_changed');
}





######################################################################
# Introspection and Convenience


=pod

=head2 pageids

    my @ids = $notebook->pageids;

Return a list of all current tab ids (integers) within the notebook.

=cut

sub pageids {
	return ( 0 .. $_[0]->GetPageCount - 1 );
}

=pod

=head2 pages

    my @pages = $notebook->pages;

Return a list of all notebook tabs. Those are the real objects, not page ids,
and should be L<Padre::Wx::Editor> objects (although they are not
guarenteed to be).

=cut

sub pages {
	my $self = shift;
	return map { $self->GetPage($_) } $self->pageids;
}

=pod

=head2 editors

    my @editors = $notebook->editors;

Return a list of all current editors. Those are the real objects, not page ids,
and are guarenteed to be L<Padre::Wx::Editor> objects.

Note: for now, this has the same meaning as the C<pages> method, but this will
change once we get specialised non-text entry tabs.

=cut

sub editors {
	return grep { Params::Util::_INSTANCE( $_, 'Padre::Wx::Editor' ) } $_[0]->pages;
}

=pod

=head2 documents

    my @document = $notebook->documents;

Return a list of all current documents, in the specific order
they are open in the notepad.

=cut

sub documents {
	return map { $_->{Document} } $_[0]->editors;
}

=pod

=head2 prefix

The C<prefix> method scans the list of all local documents, and finds the
common root directory for all of them.

=cut

sub prefix {
	my $self   = shift;
	my $found  = 0;
	my @prefix = ();
	foreach my $i ( 0 .. $self->GetPageCount - 1 ) {
		my $document = $self->GetPage($i)->{Document} or next;
		my $file = $document->file or next;
		$file->isa('Padre::File::Local') or next;
		unless ( $found++ ) {
			@prefix = $file->splitvdir;
			next;
		}

		# How deep do the paths match
		my @path = $file->splitvdir;
		if ( @prefix > @path ) {
			foreach ( 0 .. $#path ) {
				unless ( $prefix[$_] eq $path[$_] ) {
					@path = @path[ 0 .. $_ - 1 ];
					last;
				}
			}
			@prefix = @path;
		} else {
			foreach ( 0 .. $#prefix ) {
				unless ( $prefix[$_] eq $path[$_] ) {
					@prefix = @prefix[ 0 .. $_ - 1 ];
					last;
				}
			}
		}
	}

	return @prefix;
}

# Build a page id to label map
# returns list of ARRAY refs
#   in each ARRAY ref the first value is the label
#   the second value is the full path
sub labels {
	my $self   = shift;
	my @prefix = $self->prefix;
	my @labels = ();
	foreach my $i ( 0 .. $self->GetPageCount - 1 ) {
		my $document = $self->GetPage($i)->{Document};
		unless ($document) {
			push @labels, undef;
			next;
		}

		# "Untitled N" files
		my $file = $document->file;
		unless ($file) {
			my $title = $self->GetPageText($i);
			$title =~ s/[ *]+//;
			push @labels, [ $title, $title ];
			next;
		}

		# Show local files relative to the common prefix
		if ( $file->isa('Padre::File::Local') ) {
			my @path = $file->splitall;
			@path = @path[ scalar(@prefix) .. $#path ];
			push @labels, [ File::Spec->catfile(@path), $file->filename ];
			next;
		}

		# Show the full path to non-local files
		push @labels, [ $file->{filename}, $file->{filename} ];
	}

	return @labels;
}

sub find_pane_by_label {
	my $self   = shift;
	my $label  = shift;
	my @labels = $self->labels;
	my ($id) = grep { $label eq $labels[$_][0] } 0 .. $#labels;
	return $id;
}

1;

=pod

=head1 COPYRIGHT & LICENSE

Copyright 2008-2013 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-2013 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.
