package Mojolicious::Plugin::DevexpressHelpers::Helpers;
$Mojolicious::Plugin::DevexpressHelpers::Helpers::VERSION = '0.151410';
#ABSTRACT: Helpers for Devexpress controls are defined here
use Modern::Perl;
use Mojo::ByteStream;
use MojoX::AlmostJSON qw(encode_json);

sub out{
	my $tag = shift;
	return Mojo::ByteStream->new($tag);
}

sub new{
	my $class = shift;
	my $self = bless { 
			next_id => 1,
			bindings => '',
		}, $class;
	return $self;
}

sub add_binding{
	my $self = shift;
	$self->{bindings} .= join "\n", @_;
}

sub next_id{
	my $self = shift;
	return "dxctl".($self->{next_id}++);
}

sub new_id{
	my ($c, $attrs) = @_;
	#should compute a new uniq id 
	$c->stash('dxHelper')->next_id;
}

sub dxbind{
	my ($c, $control, $id, $attrs, $extensions) = @_;
	#should return html code to be associated to the control
	my $binding = '$("#'.$id.'").'.$control.'({';
    my @options;
    for my $k ( sort keys %$attrs){
		my $v = $attrs->{$k};
		if(ref($v) eq 'SCALAR'){
			#unref protected scalar
			$v = $$v;
		}
		elsif ($v!~/^\s*(?:function\s*\()/) {
			$v =  encode_json $v;
		}
		push @options, "$k: $v";
    }
    $binding .= join ",\n", @options;
    $binding .= '});';
	#append some extensions (eg: dxdatagrid)
	$binding .= join ";\n", @$extensions if defined $extensions;
	$c->stash('dxHelper')->add_binding($binding);
	#TODO: Possible extension: may add html attributs or sub content from special attributs
	out '<div id="'.$id.'"></div>';
}


sub parse_attributs{
	my $c = shift;
	my @implicit_args = @{shift()};
	my %attrs;
	IMPLICIT_ARGUMENT:
	while(@_ and ref($_[0]) =~ /^(?:|SCALAR)$/){
		$attrs{ shift @implicit_args } = shift @_;
	}
	if(my $args = shift){
		if(ref($args) eq 'HASH'){
			NAMED_ARGUMENT:
			while(my($k,$v)=each %$args){
				$attrs{$k} = $v;
			}
		}
	}
	return \%attrs;
}	


sub dxbutton {
    my $c = shift;
	my $attrs = parse_attributs( $c, [qw(id text onClick type)], @_ );
	my $id = delete($attrs->{id}) // new_id( $c, $attrs );	
	dxbind( $c, 'dxButton' => $id => $attrs);
}


sub dxdatagrid{
	my $c = shift;
	my $attrs = parse_attributs( $c, [qw(id dataSource)], @_ );
	my $id = delete($attrs->{id}) // new_id( $c, $attrs );
	my @extensions;
	#dxbind( $c, 'dxDataGrid' => $id => $attrs, [ $dataSource ]);
	if (ref($attrs->{dataSource}) eq '') {
		my $dataSource = delete $attrs->{dataSource};
		#push @extensions, '$.getJSON("' . $dataSource . '",function(data){$("#'.$id.'").dxDataGrid({ dataSource: data });});';
		#$attrs->{dataSource} = \'[]';	#protect string to be "stringified" within dxbind

		#\"" is to protect string to be "stringified" within dxbind
		$attrs->{dataSource} = \"{store:{type:'odata',url:'$dataSource'}}";
	}
	dxbind( $c, 'dxDataGrid' => $id => $attrs, \@extensions);
}


sub dxpopup{
	my $c = shift;
	my $attrs = parse_attributs( $c, [qw(id title contentTemplate)], @_ );
	my $id = delete($attrs->{id}) // new_id( $c, $attrs );
	
	dxbind( $c, 'dxPopup' => $id => $attrs );
}

sub dxbuild {
	my $c = shift;
	my $dxhelper = $c->stash('dxHelper') or return;
	if($dxhelper->{bindings}){
		out '<script language="javascript">$(function(){'.$dxhelper->{bindings}.'});</script>';
	}
}


sub require_asset{
	my $c = shift;
	my $dxhelper = $c->stash('dxHelper') or return;
	
	push @{ $dxhelper->{required_assets} }, $_ for @_;
	
	return $c;
}


sub required_assets{
	my $c = shift;
	my $dxhelper = $c->stash('dxHelper') or return;
	my $required_assets = $dxhelper->{required_assets} // [];
	my $results = Mojo::ByteStream->new();
	ASSET:
	for my $asset (@$required_assets){
		#not sure about how to simulate " %= asset 'resource' " that we can use in template rendering, 
		#nor how to output multiple Mojo::ByteStream objets at a time (is returning required ?)
		$$results .= ${ $c->asset($asset) };
	}
	return $results;
}



1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Mojolicious::Plugin::DevexpressHelpers::Helpers - Helpers for Devexpress controls are defined here

=head1 VERSION

version 0.151410

=head1 SUBROUTINES/METHODS

=head2 out

Output string in template

	out '<div id="'.$id.'"></div>';

=head2 new

Internal usage.

	my $dxHelper = Mojolicous::Plugin::DevexpressHelpers::Helpers->new;
	$c->stash( dxHelper => $dxHelper );

=head2 add_binding

Internal usage.

	$dxHelper->add_binding($binding, [$binding2,...] );

=head2 next_id

Internal usage.

	my $next_id_number = $dxHelper->next_id;

=head2 new_id

Internal usage.

	my $new_id = $dxHelper->new_id;

=head2 dxbind

Internal usage.

	dxbind( $c, 'dxButton' => $id => $attrs, \@extensions);

Produce a div tag with an computed id, which will be binded to
a dxButton with C<$attrs> attributs at call to dxbuild

=head2 parse_attributs

Internal usage

	my $attrs = parse_attributs( $c, \@implicit_arguments, @attributs )

=head2 dxbutton C<[ $id, [ $text, [ $onclick ] ] ], [ \%options ]>

	%= dxbutton myButtonId => 'My button' => q{ function (){ alert('onClick!'); } }
	
	%= dxbutton undef, 'My button' => '/some/url'
	
	%= dxbutton {
			id      => myId,
			text    => 'My button',
			onClick => q{ function (){ alert('onClick!'); } },
			type    => 'danger',
			icon    => 'user'
		};

=head2 dxdatagrid C<[ $id, [ $datasource, ] ] [ \%opts ]>

	%= dxdatagrid 'myID' => '/products.json', { columns => [qw( name description price )] }
	
	%= dxdatagrid undef, '/products.json'
	
	%= dxdatagrid { id => myId, dataSource => '/products.json' }

=head2 dxpopup C<[ $id, [ $title, [ $contentTemplate, ] ] ], [\%opts]>

	%= dxpopup myPopupID => 'Popup Title', \q{function(contentElement){
			contentElement.append('<p>Hello!</p>');
		}};

=head2 dxbuild

Build the binding between jQuery and divs generated by plugin helpers such as dxbutton.
It is should to be called in your template just before you close the body tag.

	<body>
		...
		%= dxbuild
	</body>

=head2 require_asset @assets

Used to specify one or more assets dependencies, that will be appended on call to required_assets.
This function need 'AssetPack' plugin to be configurated in your application.

in your template:

	<body>
		...
		%= require_asset 'MyScript.js'
		...
	</body>

in your layout:

	<head>
		...
		%= required_assets
		...
	</head>

=head2 required_assets

Add assets that was specified by calls to require_asset.
See require_asset for usage.

=head1 AUTHOR

Nicolas Georges <xlat@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is Copyright (c) 2015 by Nicolas Georges.

This is free software, licensed under:

  The MIT (X11) License

=cut
