The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Kephra::File::Session;
our $VERSION = '0.17';

use strict;
use warnings;

# intern API
sub _config      { Kephra::API::settings()->{file}{session} }
sub _dialog_l18n { Kephra::Config::Localisation::strings()->{dialog} }
sub _saved_properties {[ qw(
	syntaxmode EOL codepage readonly tab_size tab_use
	cursor_pos edit_pos marked_lines folded_lines
	file_path config_file
)]}

sub _forget_gone_files  {
	my @true_files = ();
	my $node       = shift;
	$node = $$node if ref $node eq 'REF' and ref $$node eq 'ARRAY';
	if ( ref $node eq 'ARRAY' ) {
		my @files = @{$node};
		for ( 0 .. $#files ) {
			if ( defined $files[$_]{file_path} and -e $files[$_]{file_path} ) {
				my %file_properties = %{ $files[$_] };
				push( @true_files, \%file_properties );
			}
		}
	}
	return \@true_files;
}

sub _remember_directory {
	my ( $filename, $dir, @dirs ) = shift;
	if ( length($filename) > 0 ) {
		@dirs = split( /\\/, $filename ) if $filename =~ /\\/ ;
		@dirs = split( /\//, $filename ) if $filename =~ /\// ;
		$dir .= "$dirs[$_]/" for 0 .. $#dirs - 1;
		_config()->{dialog_dir} = $dir if $dir;
	}
}
sub _add {
	my $session_data = shift; # session data
	return unless %$session_data
			and $session_data->{document}
			and $session_data->{document}[0];

	my @load_files = @{Kephra::Config::Tree::_convert_node_2_AoH
			( \$session_data->{document} )};
	@load_files = @{ _forget_gone_files( \@load_files ) };
	my $start_nr    =  Kephra::Document::Data::current_nr();
	my $prev_doc_nr = Kephra::Document::Data::previous_nr();
	my $loaded = Kephra::Document::Data::get_value('loaded');
	Kephra::Document::Data::update_attributes($start_nr);
	$start_nr = $session_data->{current_nr}
		if $session_data->{current_nr}
		and not $loaded and Kephra::App::EditPanel::_ref()->GetText eq '';

	# open remembered files with all properties
	Kephra::Document::restore( $_ ) for @load_files;
	my $buffer = Kephra::Document::Data::get_value('buffer');

	# selecting starting doc nr
	$start_nr = 0 if (not defined $start_nr) or ($start_nr < 0 );
	$start_nr = $buffer - 1 if $start_nr >= $buffer;

	# activate the starting document & some afterwork
	Kephra::Document::Change::to_number($start_nr);
	Kephra::Document::Data::set_previous_nr($prev_doc_nr);
	Kephra::App::Window::refresh_title();
}
#
# extern API
#
sub restore   {
	my $file = shift;
	return unless -e $file;
	Kephra::File::close_all();
	add($file);
}

sub restore_from { # 
	my $file = Kephra::Dialog::get_file_open(
			_dialog_l18n()->{file}{open_session},
			Kephra::Config::filepath( _config->{directory}
		), $Kephra::temp{file}{filterstring}{config}
	);
	restore($file);
}

sub add       {
	my $file = shift;
	my $restore = shift;
	if (-r $file) {
		my $session_def = Kephra::Config::File::load($file);
		if (ref $session_def eq 'HASH'){
			_add($session_def);
		} else {
			Kephra::Dialog::warning_box($file, _dialog_l18n()->{error}{config_parse});
		}
	} else {
		Kephra::Dialog::warning_box($file, _dialog_l18n()->{error}{file_read});
	}
}

sub add_from  {
	my $file = Kephra::Dialog::get_file_open(
		_dialog_l18n()->{file}{add_session},
		Kephra::Config::filepath( _config->{directory} ),
		$Kephra::temp{file}{filterstring}{config}
	);
	add($file);
}

sub save      {
	my $file = shift;
	return unless $file;

	Kephra::Config::Global::update();
	my $doc2vis = \&Kephra::App::TabBar::_doc2vis_pos;
	my $config = _config();
	my %temp_config = %{ Kephra::Config::File::load($file) } if -r $file;
	$temp_config{current_nr} = $doc2vis->(Kephra::Document::Data::current_nr());
	$temp_config{document} = [];
	my @doc_list = @{ Kephra::Document::Data::_attributes() };
	for my $nr (0 .. $#doc_list) {
		my $vis_pos = $doc2vis->($nr);
		$temp_config{document}[$vis_pos]{$_} = $doc_list[$nr]{$_}
			for @{ _saved_properties() };
	}
	@{ $temp_config{document} } = @{ _forget_gone_files( \$temp_config{document} ) };
	Kephra::Config::File::store( $file, \%temp_config );
}

sub save_as   {
	my $file_name = Kephra::Dialog::get_file_save(
		_dialog_l18n()->{file}{save_session},
		Kephra::Config::filepath( _config->{directory} ),
		$Kephra::temp{file}{filterstring}{config}
	);
	if ( length($file_name) > 0 ) {
		save( $file_name, "files" );
		_remember_directory($file_name);
	}
}
# default session handling
sub do_autosave { # answers if autosave is turned on by config settings
	my $config = _config()->{auto}{save};
	return 1 if defined $config and $config and not $config eq 'not';
	return 0;
}
sub autoload {    # restore session that was opened while last app shut down
	if ( do_autosave() ) {
		my $config = _config();
		my $session_file = Kephra::Config::filepath
			( $config->{directory}, $config->{auto}{file} );
		restore($session_file);
	} else { Kephra::Document::reset() }
}
sub autosave {
	my $config = _config();
	my $file = Kephra::Config::filepath($config->{directory}, $config->{auto}{file});
	save( $file ) if do_autosave();
}
# backup session handling
sub load_backup {
	my $config = _config();
	restore( Kephra::Config::filepath( $config->{directory}, $config->{backup} ) );
}

sub save_backup {
	my $config = _config();
	save( Kephra::Config::filepath( $config->{directory}, $config->{backup} ) );
}
# other session formats
sub import_scite {
	my $err_msg = _dialog_l18n()->{error};
	my $file = Kephra::Dialog::get_file_open (
		_dialog_l18n()->{file}{open_session},
		$Kephra::temp{path}{config},
		$Kephra::temp{file}{filterstring}{scite}
	);
	if ( -r $file ) {
		if ( open my $FH, '<', $file ) {
			my @load_files;
			my ( $start_file_nr, $file_nr );
			while (<$FH>) {
				m/<pos=(-?)(\d+)> (.+)/;
				if ( -e $3 ) {
					$start_file_nr = $file_nr if $1;
					$load_files[$file_nr]{cursor_pos} = $2;
					$load_files[$file_nr++]{file_path}    = $3;
				}
			}
			if (@load_files) {
				&Kephra::File::close_all;
				for (@load_files) {
					Kephra::Document::add( ${$_}{file_path} );
					Kephra::Edit::_goto_pos( ${$_}{cursor_pos} );
				}
				Kephra::Document::Change::to_number($start_file_nr);
				$Kephra::document{previous_nr} = $start_file_nr;
			} else {
				Kephra::Dialog::warning_box($file, $err_msg->{config_parse});
			}
		} else {
			Kephra::Dialog::warning_box 
				($err_msg->{file_read}." $file", $err_msg->{file});
		}
	}
}

sub export_scite {
	my $win = Kephra::App::Window::_ref();
	my $file = Kephra::Dialog::get_file_save(
		_dialog_l18n()->{file}{save_session},
		$Kephra::temp{path}{config},
		$Kephra::temp{file}{filterstring}{scite}
	);
	if ( length($file) > 0 ) {
		if ( open my $FH, '>', $file ) {
			my $current = Kephra::Document::Data::current_nr();
			my $output;
			for ( @{ Kephra::Document::Data::all_nr() } ) {
				my %file_attr = %{ Kephra::Document::Data::_hash($_) };
				if ( -e $file_attr{file_path} ) {
					$output .= "<pos=";
					$output .= "-" if $_ == $current;
					$output .= "$file_attr{cursor_pos}> $file_attr{file_path}\n";
				}
			}
			print $FH $output;
		} else {
			my $err_msg = _dialog_l18n()->{error};
			Kephra::Dialog::warning_box
				($err_msg->{file_write}." $file", $err_msg->{file} );
		}
	}
}

1;