package Calendar::OO;

use warnings;
use strict;
use DateTime;
use Data::Dumper;

=head1 NAME

Calendar::OO - The great new Calendar::OO!

=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 Calendar::OO;

    my $foo = Calendar::OO->new();
    ...

=head1 ATTRIBUTES

=cut

sub _defaults {
  return (
	  dow_offset => 0,
	  first => DateTime->today()->truncate(to => 'month'),
	 );
}

sub _days { return shift->_scalar('_days',@_); }

sub first { return shift->_scalar('first',@_); }
sub _last { return shift->_scalar('_last',@_); }
sub _today { return shift->_scalar('_today',@_); }

sub dow_offset { return shift->_scalar('_dow_offset',@_); }

=pod

=head1 METHODS

=cut

sub _init {
  my $self = shift;
  while ( my ($method, $parameter) = splice(@_,0,2)) {
    $self->$method($parameter);
  }
  $self->_last( $self->first->clone->add(months => 1));

  my $first_dow = ($self->first->dow + $self->dow_offset) % 7 ;

  my @days;
  
  my $today = $self->first->clone();
  $today = $today->add(days => -$first_dow);
  while ($today < $self->_last || @days % 7) {
    push @days, $today->clone;
    $today->add(days => 1);
  }

  $self->_days(\@days);
  return $self;
}

sub month {
  my ($self, $month) = @_;
  $self->first( DateTime->new ( %$month ));
}

sub new {
  my $class = shift;
  my $self = bless({},$class);
  return $self->_init($class->_defaults, @_);
}

sub process {
  my ($self) = @_;
  my @weeks;

  my @days = map { $self->render_day($_->month() eq $self->first->month() ? $_ : undef, calendar_date => $_)  } @{$self->_days};
  
  push @weeks, $self->render_week( splice(@days, 0, 7)) while @days;

  return $self->render_month( grep defined, ($self->month_row,
					     $self->day_row,
					     @weeks));
}

sub render_day {
  my ($self, $date) = @_;
  return $date ? sprintf("%2d", $date->day ) : q(  ) ;
}

sub render_week {
  my ($self, @days) = @_;
  return "@days";
}

sub render_month {
  my ($self, @rows) = @_;
  return map { "$_\n" }  @rows;
}

sub month_row {
  my ($self) = @_;
  my $month_row = $self->first->month_name . ' ' . $self->first->year;
  my $num_blanks = (21 - length ($month_row)) / 2;
  return ' ' x $num_blanks . $month_row;
}

sub day_row {
  return " S  M Tu  W Th  F  S";
}

=head1 AUTHOR

Lawrence Statton, <lawrence at cluon.com>

=head1 BUGS

Please report any bugs or feature requests to
C<bug-html-calendar-oo at rt.cpan.org>, or through the web interface at
L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=HTML-Calendar-OO>.
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 Calendar::OO

You can also look for information at:

=over 4

=item * AnnoCPAN: Annotated CPAN documentation

L<http://annocpan.org/dist/HTML-Calendar-OO>

=item * CPAN Ratings

L<http://cpanratings.perl.org/d/HTML-Calendar-OO>

=item * RT: CPAN's request tracker

L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=HTML-Calendar-OO>

=item * Search CPAN

L<http://search.cpan.org/dist/HTML-Calendar-OO>

=back

=head1 ACKNOWLEDGEMENTS

=head1 COPYRIGHT & LICENSE

Copyright 2007 Lawrence Statton, all rights reserved.

This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.

=cut

sub _scalar {
  my ($self, $attribute) = splice(@_,0,2);
  if (@_) {
    $self->{$attribute} = shift;
    return $self;
  } else {
    return $self->{$attribute};
  }
}


sub draw_month {
  my ($class, %arg_for) = @_;
  my $calendar = $class->new(month => \%arg_for );
  return $calendar->process;
}

1; # End of Calendar::OO
