#!/usr/bin/perl

=pod

=head1 NAME

padre-client - client for Padre

=cut

use 5.008005;
use strict;
use warnings;
use Getopt::Long    ();
use Carp            ();
use Padre::Constant ();
use Padre::Startup  ();

our $VERSION = '0.55';

#####################################################################
# Client Startup Procedure

# Runs the (as light as possible) startup process for Padre.
# XXX Mostly cut-n-pasted from Padre::Startup, except for the socket command handling
sub connect_to_server {
	my (%options) = @_;
	# Start with the default settings
	my %setting = (
		main_singleinstance      => Padre::Constant::DEFAULT_SINGLEINSTANCE(),
		main_singleinstance_port => Padre::Constant::DEFAULT_SINGLEINSTANCE_PORT(),
		startup_splash           => 1,
	);

	# Load and overlay the startup.yml file
	if ( -f Padre::Constant::CONFIG_STARTUP ) {
		require YAML::Tiny;
		my $yaml = YAML::Tiny::LoadFile(
			Padre::Constant::CONFIG_STARTUP
		);
		foreach ( sort keys %setting ) {
			next unless exists $yaml->{$_};
			$setting{$_} = $yaml->{$_};
		}
	}

	# Attempt to connect to the single instance server
	if ( $setting{main_singleinstance} ) {
		# This blocks for about 1 second
		require IO::Socket;
		my $socket = IO::Socket::INET->new(
			PeerAddr => ($options{ host } || '127.0.0.1'),
			PeerPort => ($options{ port } || $setting{main_singleinstance_port}),
			Proto    => 'tcp',
			Type     => IO::Socket::SOCK_STREAM(),
		);
		if ( $socket ) {
			my $pid = '';
			my $read = $socket->sysread( $pid, 10 );
			if ( defined $read and $read == 10 ) {
				# Got the single instance PID
				$pid =~ s/\s+\s//;
				if ( Padre::Constant::WIN32 ) {
					require Padre::Util::Win32;
					Padre::Util::Win32::AllowSetForeground($pid);
				}
			};
			binmode $socket;
			return $socket
		} else {
			# Main Padre instance unreachable or does not exist
		}
	}

	# Show the splash image now we are starting a new instance
	# Shows Padre's splash screen if this is the first time
	# It is saved as BMP as it seems (from wxWidgets documentation)
	# that it is the most portable format (and we don't need to
	# call Wx::InitAllImageHeaders() or whatever)
	if ( $setting{startup_splash} ) {
		# Don't show the splash screen during testing otherwise
		# it will spoil the flashy surprise when they upgrade.
		unless ( $ENV{HARNESS_ACTIVE} or $ENV{PADRE_NOSPLASH} ) {
			require File::Spec;

			# Find the base share directory
			my $share = undef;
			if ( $ENV{PADRE_DEV} ) {
				require FindBin;
				$share = File::Spec->catdir(
					$FindBin::Bin,
					File::Spec->updir,
					'share',
				);
			} else {
				require File::ShareDir;
				$share = File::ShareDir::dist_dir('Padre');
			}

			# Locate the splash image without resorting to the use
			# of any Padre::Util functions whatsoever.
			my $splash = File::Spec->catfile(
				$share, 'padre-splash-ccnc.png'
			);

			# Use CCNC-licensed version if it exists and fallback
			# to the boring splash so that we can bundle it in
			# Debian without their packaging team needing to apply
			# any custom patches to the code, just delete the file.
			unless ( -f $splash ) {
				$splash = File::Spec->catfile(
					$share, 'padre-splash.png',
				);
			}

			# Load just enough modules to get Wx bootstrapped
			# to the point it can show the splash screen.
			require Wx;
			#$SPLASH = Wx::SplashScreen->new(
		#		Wx::Bitmap->new(
		#			$splash,
		#			Wx::wxBITMAP_TYPE_BMP()
		#		),
		#		Wx::wxSPLASH_CENTRE_ON_SCREEN() | Wx::wxSPLASH_TIMEOUT(),
		#		3500, undef, -1
		#	);
		}
	}

	return 1;
}

# Destroy the splash screen if it exists
#sub destroy_splash {
#	if ($SPLASH) {
#		$SPLASH->Destroy;
#		$SPLASH = 1;
#	}
#}

local $| = 1;
local $SIG{__DIE__} =
	$ENV{PADRE_DIE}
	? sub { print STDERR Carp::longmess "\nDIE: @_\n" . ( "-" x 80 ) . "\n" }
	: $SIG{__DIE__};

# Handle special command line cases early, because options like --home
# MUST be processed before the Padre.pm library is loaded.
my $getopt      = Getopt::Long::GetOptions(
	'help|usage'    => \my $USAGE,
	'version'       => \my $show_VERSION,
	'home=s'        => \my $HOME,
	'host=s'        => \my $host,
	'port=s'        => \my $port,
);

if ( $USAGE or !$getopt ) {
	my $port = Padre::Constant::DEFAULT_SINGLEINSTANCE_PORT();

	print <<"END_USAGE";
Usage: $0 [FILENAMES]

--home=dir          Forces Padre's "home" directory to a specific location
--host=hostname     Connect to padre using this host (default is localhost)
--port=port         Connect to padre using this port number (default is $port)
--home=dir          Forces Padre's "home" directory to a specific location
--help              Shows this help message
--version           Prints Padre version and quits

END_USAGE
	exit(1);
}

local $ENV{PADRE_HOME} = defined($HOME) ? $HOME : $ENV{PADRE_HOME};

# Special execution modes
if ($show_VERSION) {
	require Padre;
	my $msg = "Perl Application Development and Refactoring Environment $Padre::VERSION\n";
	if ( $^O eq 'MSWin32' and $^X =~ /wperl\.exe/ ) {

		# Under wperl, there is no console so we will use
		# a message box
		require Padre::Wx;
		Wx::MessageBox(
			$msg,
			Wx::gettext("Version"),
			Wx::OK(),
		);
	} else {
		print $msg;
	}
	exit(0);
}

my $socket = connect_to_server( host => $host, port => $port );

if (ref $socket) {
	my %pending;
	for (@ARGV) {
		my $full = File::Spec->rel2abs($_);
		$pending{ $full } = 1;
		print {$socket} "open-sync $full\r\n"
	}
	while (<$socket>) {
		next unless s/^closed://;
		s/\s*$//;
		delete $pending{ $_ };
		warn "Closed file $_";
		last unless keys %pending;
	};
	exit;
};

# XXX Here we should launch Padre in the background, and (re)try connecting
# to it. If that fails, we should simply launch ourselves as (another)
# Padre instance.

require Padre;

# Build the application
my $app = Padre->new;
unless ( $app ) {
	die "Failed to create Padre instance";
}

# Start the application
$app->run;

# Copyright 2008-2011 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.
