The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#! perl

use strict;
use warnings;

package Music::ChordBot::Opus::Section;

=head1 NAME

Music::ChordBot::Opus::Section - ChordBot song section.

=cut

our $VERSION = 0.01;

use parent 'Music::ChordBot::Opus::Base';

use Music::ChordBot::Opus::Section::Chord;
use Music::ChordBot::Opus::Section::Style;

=head1 SYNOPSIS

    use Music::ChordBot::Opus::Section;
    my $sect = Music::ChordBot::Opus::Section->new;
    $sect->name("First movement");
    $sect->set_style("Kubiac");
    $sect->add_chord(...);
    $sect->add_chord(...);

=cut

#### TODO: Repeat sections.
#
# A repeat section has a name, optionally a style, and no chords. The
# field 'repeat' contains the index of the original section that is to
# be repeated. This can be tricky when inserting/deleting sections.

=head1 METHODS

=head2 new [ args ]

Creates a new Music::ChordBot::Opus::Section object.

Initial attributes may be passed as a hash.

Attributes:

=over 4

=item name

The name of the section.

=item chords

An arrayref containing Music::ChordBot::Opus::Section::Chord objects,
more commonly known as 'chords',

=item style

A hashref representing the attributes of a style. See
L<Music::ChordBot::Opus::Section::Style>.

=cut

sub new {
    my $pkg = shift;
    my $data = { name => "Section 1",
		 chords => [],
		 style => { chorus => 4, reverb => 8,
			    tracks => [ { volume => 7, id => 95 } ] },
		 @_ };
    bless { data => $data }, $pkg;
}

=head2 name [ I<value> ]

Sets or gets the name of the section.

=cut

sub name { shift->_setget( "name", @_ ) }

=head2 add_chord I<chord>

Adds a chord to the section.

I<chord> must be a Music::ChordBot::Opus::Section::Chord object, or a
string denoting a chord, e.g. "C Maj 4". For convenience, the three
elements may also be passed separately, e.g., C<add_chord("C", "Maj",
4)>.

A bass note can be specified by adding the note to the key, separated
by a slash, e.g., C<"C/B">.

=cut

sub add_chord {
    my ( $self, $chord ) = @_;
    my $ok = 0;
    eval { push( @{$self->{data}->{chords}}, $chord->{data} ); $ok = 1 };
    return if $ok;
    shift;
    push( @{$self->{data}->{chords}},
	  Music::ChordBot::Opus::Section::Chord->new(@_)->data );
}

sub chords {
    wantarray
      ? @{ $_[0]->{data}->{chords} }
      : $_[0]->{data}->{chords};
}

=head2 no_style

A newly created Music::ChordBot::Opus::Section object has a default
style associated. Calling this method removes the style from the
section.

=cut

sub no_style {
    delete $_[0]->{data}->{style};
}

=head2 set_style [ I<style> ]

Sets the style for the section.

I<style> must be a Music::ChordBot::Opus::Section::Style object, or the
name of a predefined (preset) style.

If I<style> is omitted, the current style is removed from the section.

=cut

sub set_style {
    my ( $self, $style ) = @_;
    $self->no_style, return unless defined $style;
    my $ok = 0;
    eval { $self->{data}->{style} = $style->{data}; $ok = 1 };
    return if $ok;
    $self->{data}->{style} =
      Music::ChordBot::Opus::Section::Style->preset($style)->data;
}

=head1 AUTHOR, COPYRIGHT & LICENSE

See L<Music::ChordBot>.

=cut

1;