# -*- coding: utf-8 -*-
# Copyright (C) 2011 Rocky Bernstein <rocky@cpan.org>

use strict;
eval "use rlib '../..'";
use feature 'switch';

# require_relative 'default'                # default debugger settings

package Devel::Trepan::Client;
use Devel::Trepan::Interface::ComCodes;
use Devel::Trepan::Interface::Client;
use Devel::Trepan::Interface::Script;
use English;

sub new
{
    my ($class, $settings) = @_;
    my  $intf = Devel::Trepan::Interface::Client->new( 
	undef, undef, undef, undef, 
	{host => $settings->{host},
	 port => $settings->{port}}
	);
    my $self = {
	intf => $intf,
	user_inputs => [$intf->{user}]
    };
    bless $self, $class;
}

sub errmsg($$)
{
    my ($self, $msg) = @_;
    $self->{intf}{user}->errmsg($msg);
}

sub msg($$)
{
    my ($self, $msg) = @_;
    chomp $msg;
    $self->{intf}{user}->msg($msg);
}

sub run_command($$$$)
{
    my ($self, $intf, $current_command) = @_;
    if (substr($current_command, 0, 1) eq '.') {
	$current_command = substr($current_command, 1);
        my @args = split(' ', $current_command);
	my $cmd_name = shift @args;
	my $script_file = shift @args;
	given($cmd_name) {
	    when ("source") { 
		my $result = 
		    Devel::Trepan::Util::invalid_filename($script_file);
		unless (defined $result) {
		    $self->errmsg($result);
		    return 0;
		}
		my $script_intf = 
		    Devel::Trepan::Interface::Script->new($script_file);
		unshift @{$self->{user_inputs}}, $script_intf->{input};
		$current_command = $script_intf->read_command;
	    };
	    default {
		$self->errmsg(sprintf "Unknown command: '%s'", $cmd_name);
		return 0;
	    }
	};
    } eval {
	$intf->write_remote(COMMAND, $current_command);
    };
    return 1;
}

sub start_client($)
{
    my $options = shift;
    printf "Client option given\n";
    my $client = Devel::Trepan::Client->new(
	{client      => 1,
	 cmdfiles    => [],
	 initial_dir => $options->{chdir},
	 nx          => 1,
	 host        => $options->{host},
	 port        => $options->{port}}
    );
    my $intf = $client->{intf};
    my ($control_code, $line);
    while (1) {
	eval {
	    ($control_code, $line) = $intf->read_remote;
	};
	if ($EVAL_ERROR) {
	    $client->msg("Remote debugged process closed connection");
	    last;
	}
	# p [control_code, line]
	given ($control_code) {
	    when (PRINT) { $client->msg("$line"); }
	    when (CONFIRM_TRUE) {
		my $response = $intf->confirm($line, 1);
		$intf->write_remote(CONFIRM_REPLY, $response ? 'Y' : 'N');
	    }
	    when (CONFIRM_FALSE) {
		my $response = $intf->confirm($line, 1);
		$intf->write_remote(CONFIRM_REPLY, $response ? 'Y' : 'N');
	    }
	    when (PROMPT) {
		my $command;
		my $leave_loop = 0;
		until ($leave_loop) {
		    eval {
			$command = $client->{user_inputs}[0]->read_command($line);
		    };
		    # if ($intf->is_input_eof) {
		    # 	print "user-side EOF. Quitting...\n";
		    # 	last;
		    # }
		    if ($EVAL_ERROR) {
			if (scalar @{$client->{user_inputs}} == 0) {
			    $client->msg("user-side EOF. Quitting...");
			    last;
			} else {
			    shift @{$client->{user_inputs}};
			    next;
			}
		    };
		    $leave_loop = $client->run_command($intf, $command);
		    if ($EVAL_ERROR) {
			$client->msg("Remote debugged process died");
			last;
		    }
		}
	    }
	    when (QUIT) { 
		last 
	    }
	    when (RESTART) { 
		$intf->close;
		# Make another connection..
		$client = Devel::Trepan::Client->new(
		    {client      => 1,
		     cmdfiles    => [],
		     initial_dir => $options->{chdir},
		     nx          => 1,
		     host        => $options->{host},
		     port        => $options->{port}}
		    );
		$intf = $client->{intf};
	    }
	    when (SERVERERR) {
		$client->errmsg($line);
	    }
	    default {
		$client->errmsg("Unknown control code: '$control_code'");
	    }
	}
    }
}

unless (caller) {
    Devel::Trepan::Client::start_client({host=>'127.0.0.1', port=>1954});
}

1;
