package Plugins::SqueezeESP32::Graphics;

use strict;

use base qw(Slim::Display::Squeezebox2);

use Slim::Utils::Prefs;
use Slim::Utils::Log;

my $prefs = preferences('plugin.squeezeesp32');
my $log   = logger('plugin.squeezeesp32');

my $VISUALIZER_NONE = 0;
my $VISUALIZER_VUMETER = 1;
my $VISUALIZER_SPECTRUM_ANALYZER = 2;
my $VISUALIZER_WAVEFORM = 3;
my $VISUALIZER_VUMETER_ESP32 = 0x11;
my $VISUALIZER_SPECTRUM_ANALYZER_ESP32 = 0x12;

my %SPECTRUM_DEFAULTS = (
	scale => 25,
	small => {
		size => 25,
		band => 5.33
	},
	full => {
		band => 8
	},
);

{
	#__PACKAGE__->mk_accessor('array', 'modes');
	__PACKAGE__->mk_accessor('rw', 'modes');
	__PACKAGE__->mk_accessor('rw', qw(vfdmodel));
}

sub new {
	my $class = shift;
	my $client = shift;
	
	my $display = $class->SUPER::new($client);
	my $cprefs = $prefs->client($client);
	
	$cprefs->init( { 
		width => 128,
		small_VU => 15,
		spectrum => \%SPECTRUM_DEFAULTS,
	} );

	$prefs->migrateClient(2, sub {
		my ($cprefs, $client) = @_;
		sanitizeSpectrum($cprefs->get('spectrum'));
		1;
	});

	$display->init_accessor(
		modes => $display->build_modes,
		# Only seems to matter for screensaver and update to decide font. Not 
		# any value is acceptable, so use Boom value which seems to be best 
		# compromise
		vfdmodel => 'graphic-160x32',	
	);	
	
	return $display;
}

=comment
sub modes {
	return \@modes;
}
=cut

sub nmodes {
	return scalar($#{shift->modes()});
}

sub displayWidth {
	my $display = shift;
	my $client = $display->client;
	
	# if we're showing the always-on visualizer & the current buttonmode 
	# hasn't overridden, then use the playing display mode to index
	# into the display width, otherwise, it's fullscreen.
	my $mode = 0;
	
	if ( $display->showVisualizer() && !defined($client->modeParam('visu')) ) {
		my $cprefs = preferences('server')->client($client);
		$mode = $cprefs->get('playingDisplayModes')->[ $cprefs->get('playingDisplayMode') ];
	}
	
	if ($display->widthOverride) {
		my $artwork = $prefs->client($client)->get('artwork');
		if ($artwork->{'enable'} && $artwork->{'y'} < 32 && ($client->isPlaying || $client->isPaused)) {
			return ($artwork->{x} || $display->widthOverride) + ($display->modes->[$mode || 0]{_width} || 0);
		} else {
			return $display->widthOverride + ($display->modes->[$mode || 0]{_width} || 0);
		}	
	} else {
		return $display->modes->[$mode || 0]{width};
	}	
}

sub brightnessMap {
	return (0 .. 5);
}

=comment
sub bytesPerColumn {
	return 4;
}
=cut

# I don't think LMS renderer handles properly screens other than 32 pixels. It
# seems that all we get is a 32 pixel-tall data with anything else padded to 0
# i.e. if we try 64 pixels height, bytes 0..3 and 4..7 will contains the same 
# pattern than the 32 pixels version, where one would have expected bytes 4..7
# to be empty
sub displayHeight {
	return 32;
}

sub sanitizeSpectrum {
	my ($spectrum) = shift;

	$spectrum->{small}->{size} ||= $SPECTRUM_DEFAULTS{small}->{size};
	$spectrum->{small}->{band} ||= $SPECTRUM_DEFAULTS{small}->{band};
	$spectrum->{full}->{band} ||= $SPECTRUM_DEFAULTS{full}->{band};

	return $spectrum;
}

sub build_modes {
	my $client = shift->client;
	my $cprefs = $prefs->client($client);
	
	my $artwork = $cprefs->get('artwork');
	my $disp_width = $cprefs->get('width') || 128;

	# if artwork is in main display, reduce width but when artwork is (0,0) fake it
	my $width = ($artwork->{'enable'} && $artwork->{'y'} < 32 && $artwork->{'x'}) ? $artwork->{'x'} : $disp_width;
	my $width_low = ($artwork->{'enable'} && $artwork->{'x'} && ($artwork->{'y'} >= 32 || $disp_width - $artwork->{'x'} > 32)) ? $artwork->{'x'} : $disp_width;
			
	my $small_VU = $cprefs->get('small_VU');
	my $spectrum = sanitizeSpectrum($cprefs->get('spectrum'));

	my $small_spectrum_pos = { x => $width - int ($spectrum->{small}->{size} * $width / 100),
						 width => int ($spectrum->{small}->{size} * $width / 100),
			};
	my $small_VU_pos = { x => $width - int ($small_VU * $width / 100), 
						 width => int ($small_VU * $width / 100),
			};		
	
	my @modes = (
		# mode 0
		{ desc => ['BLANK'],
		bar => 0, secs => 0,  width => $width, 
		params => [$VISUALIZER_NONE] },
		# mode 1
		{ desc => ['PROGRESS_BAR'],
		bar => 1, secs => 0,  width => $width,
		params => [$VISUALIZER_NONE] },
		# mode 2
		{ desc => ['ELAPSED'],
		bar => 0, secs => 1,  width => $width,
		params => [$VISUALIZER_NONE] },
		# mode 3
		{ desc => ['ELAPSED', 'AND', 'PROGRESS_BAR'],
		bar => 1, secs => 1,  width => $width, 
		params => [$VISUALIZER_NONE] },
		# mode 4
		{ desc => ['REMAINING'],
		bar => 0, secs => -1, width => $width,
		params => [$VISUALIZER_NONE] },
		# mode 5  
		{ desc => ['CLOCK'],
		bar => 0, secs => 0, width => $width, clock => 1,
		params => [$VISUALIZER_NONE] },
		# mode 6	  
		{ desc => ['SETUP_SHOWBUFFERFULLNESS'],
		bar => 0, secs => 0,  width => $width, fullness => 1,
		params => [$VISUALIZER_NONE] },
		# mode 7
		{ desc => ['VISUALIZER_VUMETER_SMALL'],
		bar => 0, secs => 0,  width => $width, _width => -$small_VU_pos->{'width'},
		# extra parameters (width, height, col (< 0 = from right), row (< 0 = from bottom), left_space)
		params => [$VISUALIZER_VUMETER_ESP32, $small_VU_pos->{'width'}, 32, $small_VU_pos->{'x'}, 0, 2] },
		# mode 8
		{ desc => ['VISUALIZER_SPECTRUM_ANALYZER_SMALL'],
		bar => 0, secs => 0,  width => $width, _width => -$small_spectrum_pos->{'width'},
		# extra parameters (width, height, col (< 0 = from right), row (< 0 = from bottom), left_space, #bars, scale)
		params => [$VISUALIZER_SPECTRUM_ANALYZER_ESP32, $small_spectrum_pos->{width}, 32, $small_spectrum_pos->{'x'}, 0, 2, $small_spectrum_pos->{'width'} / $spectrum->{small}->{band}, $spectrum->{scale}] },  
		# mode 9	 
		{ desc => ['VISUALIZER_VUMETER'],
		bar => 0, secs => 0,  width => $width,
		params => [$VISUALIZER_VUMETER_ESP32, $width_low, 0] },
		# mode 10	
		{ desc => ['VISUALIZER_ANALOG_VUMETER'],
		bar => 0, secs => 0,  width => $width,
		params => [$VISUALIZER_VUMETER_ESP32, $width_low, 1] },
		# mode 11
		{ desc => ['VISUALIZER_SPECTRUM_ANALYZER'],
		bar => 0, secs => 0,  width => $width,
		# extra parameters (bars)
		params => [$VISUALIZER_SPECTRUM_ANALYZER_ESP32, $width_low, int ($width/$spectrum->{full}->{band}), $spectrum->{scale}] },	  
	);

my @extra = (
		# mode E1
		{ desc => ['VISUALIZER_VUMETER', 'AND', 'ELAPSED'],
		bar => 0, secs => 1,  width => $width,
		params => [$VISUALIZER_VUMETER_ESP32, $width_low, 0] },
		# mode E2	 
		{ desc => ['VISUALIZER_ANALOG_VUMETER', 'AND', 'ELAPSED'],
		bar => 0, secs => 1,  width => $width,
		params => [$VISUALIZER_VUMETER_ESP32, $width_low, 1] },
		# mode E3
		{ desc => ['VISUALIZER_SPECTRUM_ANALYZER', 'AND', 'ELAPSED'],
		bar => 0, secs => 1,  width => $width,
		# extra parameters (bars)
		params => [$VISUALIZER_SPECTRUM_ANALYZER_ESP32, $width_low, int ($width/$spectrum->{full}->{band}), $spectrum->{scale}] },	  
		# mode E4	 
		{ desc => ['VISUALIZER_VUMETER', 'AND', 'REMAINING'],
		bar => 0, secs => -1,  width => $width,
		params => [$VISUALIZER_VUMETER_ESP32, $width_low, 0] },
		# mode E5
		{ desc => ['VISUALIZER_ANALOG_VUMETER', 'AND', 'REMAINING'],
		bar => 0, secs => -1,  width => $width,
		params => [$VISUALIZER_VUMETER_ESP32, $width_low, 1] },
		# mode E6
		{ desc => ['VISUALIZER_SPECTRUM_ANALYZER', 'AND', 'REMAINING'],
		bar => 0, secs => -1,  width => $width,
		# extra parameters (bars)
		params => [$VISUALIZER_SPECTRUM_ANALYZER_ESP32, $width_low, int ($width/$spectrum->{full}->{band}), $spectrum->{scale}] },	
		# mode E7	 
		{ desc => ['VISUALIZER_VUMETER', 'AND', 'PROGRESS_BAR', 'AND', 'REMAINING'],
		bar => 1, secs => -1,  width => $width,
		params => [$VISUALIZER_VUMETER_ESP32, $width_low, 0] },
		# mode E8
		{ desc => ['VISUALIZER_ANALOG_VUMETER', 'AND', 'PROGRESS_BAR', 'AND', 'REMAINING'],
		bar => 1, secs => -1,  width => $width,
		params => [$VISUALIZER_VUMETER_ESP32, $width_low, 1] },
		# mode E9
		{ desc => ['VISUALIZER_SPECTRUM_ANALYZER', 'AND', 'PROGRESS_BAR', 'AND', 'REMAINING'],
		bar => 1, secs => -1,  width => $width,
		# extra parameters (bars)
		params => [$VISUALIZER_SPECTRUM_ANALYZER_ESP32, $width_low, int ($width/$spectrum->{full}->{band}), $spectrum->{scale}] },	
	);		
	
	@modes = (@modes, @extra) if $cprefs->get('height') > 32;

	return \@modes;
}	

1;