package Text::JSON::Nibble;

use 5.006;
use strict;
use warnings;

=head1 NAME

Text::JSON::Nibble - Nibble complete JSON objects from buffers

=head1 VERSION

Version 0.01

=cut

our $VERSION = '0.01';


=head1 SYNOPSIS

Quick summary of what the module does.

Perhaps a little code snippet.

	use warnings;
	use strict;

	use Text::JSON::Nibble;
	use JSON::MaybeXS;

	my $json = JSON->new;
	my $item = Text::JSON::Nibble->new();

	my $test = {
			lol => {
					a => [1,2,3],
					b => "lol"
			}
	};

	my $jsontext = $json->encode($test);

	$jsontext = "$jsontext$jsontext";

	print "jsontext: $jsontext\n";

	my ($text,$offset) = $item->digest($jsontext);

	print "Text: $text\n";
	print "Offset: $offset\n";

	# Beware the offset is a real offset so the first character is classed as 0, the literal length is 1 greater;
	$jsontext = substr($jsontext,$offset+1);

	print "new jsontext: $jsontext\n";


=head1 WARNING

This module should be used with caution, it will not handle 'badly formed' json well, its entire purpose was because I was experiencing 
segfaults with Cpanel::XS's decode_prefix when dealing with a streamnig socket buffer.

Use this only when needed.

=head1 SUBROUTINES/METHODS

=head2 new

Generate a new JSON Nibble object

=cut

sub new {
	my $class = shift;

	my $self = { };

	bless $self, $class;

	return $self;
}

=head2 digest

Digest the text that is fed and attempt to return a complete JSON object from it, returns two items the JSON object (in text form) and the offset in the buffer.

On a failure it will return "" and 0

=cut

sub digest {
	my $self = shift;
	my $data = shift;

	# If we got passed a blank data scalar just return failure
	return ("",0) if (!$data);

	# First split the data into an array
	my @jsonArray = split(//,$data);

	# Crawl through the array counting our open data brackets
	my $typeAOpen = 0;
	my $typeBOpen = 0;
	my $arrayPlace = 0;
	foreach my $chr ( @jsonArray ) {
		my $prevChar = "";

		if ($arrayPlace > 0) { $prevChar = $jsonArray[$arrayPlace - 1] }

		if ( ord($prevChar) != 92 ) { 
			my $charCode = ord($chr);

			# Handle { } type brackets
			if ( $charCode == 123 )  { $typeAOpen++ }
			elsif ( $charCode == 125 ) { $typeAOpen-- }
	
			# Handle [ ] type brackets
			if ( $charCode == 91 ) { $typeBOpen++ }
			elsif ( $charCode == 93 ) { $typeBOpen-- }
		}

		# If we have a complete object then leave
		if ( $arrayPlace > 1 && !$typeAOpen && !$typeBOpen ) { 
			# Convert the offset into a length
			last;
		}
		else { $arrayPlace++ }
	}

	if ( !$typeAOpen && !$typeBOpen ) {
		# Return what we found
		return ( join('',@jsonArray[0..$arrayPlace]), $arrayPlace );
	} else {
		return ("",0);
	}
}

=head1 AUTHOR

Paul G Webster, C<< <daemon at cpan.org> >>

=head1 BUGS

Please report any bugs or feature requests to C<bug-text-json-nibble at rt.cpan.org>, or through
the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Text-JSON-Nibble>.  I will be notified, and then you'll
automatically be notified of progress on your bug as I make changes.




=head1 SUPPORT

You can find documentation for this module with the perldoc command.

    perldoc Text::JSON::Nibble


You can also look for information at:

perl=over 4

=item * RT: CPAN's request tracker (report bugs here)

L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Text-JSON-Nibble>

=item * AnnoCPAN: Annotated CPAN documentation

L<http://annocpan.org/dist/Text-JSON-Nibble>

=item * CPAN Ratings

L<http://cpanratings.perl.org/d/Text-JSON-Nibble>

=item * Search CPAN

L<http://search.cpan.org/dist/Text-JSON-Nibble/>

=back


=head1 ACKNOWLEDGEMENTS


=head1 LICENSE AND COPYRIGHT

Copyright 2017 Paul G Webster.

This program is released under the following license: BSD


=cut

1; # End of Text::JSON::Nibble
