/lib/perl/Blerg-Database/lib/Blerg/Database.pm
package Blerg::Database;

use 5.008000;
use strict;
use warnings;
use Carp;

require Exporter;
use AutoLoader;

our @ISA = qw(Exporter);

# Items to export into callers namespace by default. Note: do not export
# names by default without a very good reason. Use EXPORT_OK instead.
# Do not simply export all your public functions/methods/constants.

# This allows declaration	use Blerg::Database ':all';
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
# will save memory.
our %EXPORT_TAGS = ( 'all' => [ qw(
	
) ] );

our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );

our @EXPORT = qw(
	
);

our $VERSION = '1.9.0';

sub AUTOLOAD {
    # This AUTOLOAD is used to 'autoload' constants from the constant()
    # XS function.

    my $constname;
    our $AUTOLOAD;
    ($constname = $AUTOLOAD) =~ s/.*:://;
    croak "&Blerg::Database::constant not defined" if $constname eq 'constant';
    my ($error, $val) = constant($constname);
    if ($error) { croak $error; }
    {
	no strict 'refs';
	# Fixed between 5.005_53 and 5.005_61
#XXX	if ($] >= 5.00561) {
#XXX	    *$AUTOLOAD = sub () { $val };
#XXX	}
#XXX	else {
	    *$AUTOLOAD = sub { $val };
#XXX	}
    }
    goto &$AUTOLOAD;
}

require XSLoader;
XSLoader::load('Blerg::Database', $VERSION);

# Preloaded methods go here.

if (!Blerg::Database::init()) {
    die "Could not initialize C library";
}

sub open {
    my ($class, $name) = @_;
    my $ptr = Blerg::Database::_open($name);
    my $obj = {
        ptr => $ptr,
        name => $name,
    };
    return bless $obj, $class;
}

sub open_existing {
    my ($class, $name) = @_;

    if (Blerg::Database::exists($name)) {
        return Blerg::Database->open($name);
    }
    return undef;
}

sub _ensure_pointer {
    my ($obj) = @_;
    if (!defined $obj->{ptr}) {
        croak "Attempted to use closed Blerg::Database";
    }
}

sub close {
    my ($obj) = @_;
    if (!(defined $obj && defined $obj->{ptr})) {
        # Welp, nothing to do here!
        return;
    }
    Blerg::Database::_close($obj->{ptr});
    delete $obj->{ptr};
}

DESTROY {
    my ($obj) = @_;
    $obj->close;
}

sub record_count {
    my ($obj) = @_;
    $obj->_ensure_pointer;
    return Blerg::Database::_get_record_count($obj->{ptr});
}

sub set_subscription_mark {
    my ($obj) = @_;
    $obj->_ensure_pointer;
    return Blerg::Database::_set_subscription_mark($obj->{ptr});
}

sub get_subscription_mark {
    my ($obj) = @_;
    $obj->_ensure_pointer;
    return Blerg::Database::_get_subscription_mark($obj->{ptr});
}

sub subscription_list {
    my ($obj) = @_;
    $obj->_ensure_pointer;
    return Blerg::Database::_subscription_list($obj->{name}, 0, -1);
}

sub mute {
    my ($obj, $v) = @_;
    $obj->_ensure_pointer;
    if (defined $v) {
        return Blerg::Database::_set_status($obj->{ptr}, $obj->BLERGSTATUS_MUTED, $v);
    } else {
        return Blerg::Database::_get_status($obj->{ptr}, $obj->BLERGSTATUS_MUTED);
    }
}

sub mention {
    my ($obj, $v) = @_;
    $obj->_ensure_pointer;
    if (defined $v) {
        return Blerg::Database::_set_status($obj->{ptr}, $obj->BLERGSTATUS_MENTIONED, $v);
    } else {
        return Blerg::Database::_get_status($obj->{ptr}, $obj->BLERGSTATUS_MENTIONED);
    }
}

sub refs {
    my ($obj) = @_;
    return Blerg::Database::tag_list('@' . $obj->{name}, 50, -1);
}

sub store {
    my ($obj, $data) = @_;
    $obj->_ensure_pointer;
    return Blerg::Database::_store($obj->{ptr}, $data);
}

sub fetch {
    my ($obj, $record) = @_;
    $obj->_ensure_pointer;
    return Blerg::Database::_fetch($obj->{ptr}, $record);
}

sub timestamp {
    my ($obj, $record) = @_;
    $obj->_ensure_pointer;
    return Blerg::Database::_get_timestamp($obj->{ptr}, $record);
}

# Convenience shortcuts
sub hash_tag_list {
    my ($name, $str_offset, $direction) = @_;
    return Blerg::Database::tag_list("#$name", $str_offset, $direction);
}

sub ref_tag_list {
    my ($name, $str_offset, $direction) = @_;
    return Blerg::Database::tag_list("@$name", $str_offset, $direction);
}

# Autoload methods go after =cut, and are processed by the autosplit program.

1;
__END__

=head1 NAME

=encoding utf8

Blerg::Database - Perl extension for reading Blërg! databases

=head1 SYNOPSIS

  use Blerg::Database;

  my $blerg = Blerg::Database->open_existing('foo');
  my $record = $blerg->post('This is some data!');
  $blerg->fetch($record);

=head1 DESCRIPTION

Blerg::Database is a utility library wrapping the core Blërg! database.  It
provides nicer OO wrappers around the core C library that powers Blërg!.

=head1 MODULE FUNCTIONS

=head2 GENERAL

=over

=item exists(name)

Returns 1 if the named database exists, or C<undef> if it doesn't.

=item tag_list(tag, offset, direction)

Returns a list of hashrefs describing blerg posts related to the given tag.
C<tag> includes the leading '@' or '#'.  Each item has two keys, C<author> and
C<record>.

=item hash_tag_list(name, offset, direction)

Convenience for C<tag_list> so that you don't have to prepend '#' to the name.

=item ref_tag_list(name, offset, direction)

Convenience for C<tag_list> so that you don't have to prepend '@' to the name.

=item subscription_add(from, to)

Adds a subscription from C<from> to C<to>.

=item subscription_remove(from, to)

The opposite of subscription_add.

=item valid_tag_name(name)

Validates that C<name> is a valid tag name.

=item valid_name(name)

Validates that C<name> is a valid username.

=item configuration()

Returns a hashref containing runtime configuration information.  Contains these fields:

=over

=item base_path

The base path to the Blërg database

=item data_path

The path under base_path for account data

=item hash_tags_path

The path under base_path for hashtag data

=item ref_tags_path

The path under base_path for mention data

=back

=back

=head2 AUTHENTICATION

=over

=item auth_set_password(username, password)

Sets the password for the given username.  Returns 1 on success, 0 otherwise.

=item auth_check_password(username, password)

Checks the password for the given username.  Returns 1 on successful
authentication, 0 on failed authentication or error.

=item auth_login(username, password)

Authenticates and logs the user in.  Returns the authentication token if
successful, or undef on failure or error.

=item auth_logout(username, token)

Logs the given user out if the token represents a valid session.  Returns 1 on
success, or 0 on failure.  Failure can happen if the token is no longer valid
(meaning the user has been automatically logged out), so the return status is
probably best ignored..

=item auth_check_token(username, token)

Checks that the token represents a valid session for the given username.
Returns 1 if the session is valid, 0 otherwise.  Also resets the expiration
time of the session.

=item auth_get_counter(username)

Gets an opaque "counter" value for the auth information of the given username.
This counter is changed every time the authentication information is changed,
making it useful for protecting password changes against replay attacks.
Returns a 32-bit integer on success, or undef on failure.

=back

=head1 CONSTRUCTOR

=over

=item open(name)

Opens the named database, creating it if it doesn't exist.

=item open_existing(name)

Opens the named database.  If it doesn't exist, returns C<undef>.

=back

=head1 CLASS METHODS

=head2 RECORDS

=over

=item record_count()

Returns the number of records in the database.

=item store(data)

Stores a new record containing C<data>.  Returns the record number of the new
record.

=item fetch(record)

Fetches a record from the database.

=item timestamp(record)

Returns a unix epoch timestamp for when the record was created.

=back

=head2 SUBSCRIPTIONS

=over

=item set_subscription_mark()

Mark all items on the subscription list as read.

=item get_subscription_mark()

Return the subscription list mark.

=item subscription_list()

Return a list of hashrefs describing posts in your subscription feed.  Each
hashref has a C<author> and C<record> key.

=back

=head2 REFS, MUTE, CLEANUP

=over

=item refs()

Convenience for listing references to the database.  Equivalent to
C<tag_list('@' . $obj-E<gt>{name})>.

=item mute(v)

When v = 1, mute the user, otherwise, unmute.  If v is absent, return the mute status.

=item close()

Closes the database.

=back

=head1 SEE ALSO

See the Blërg! website at http://blerg.cc.  More detailed docs about the
database internals are available in the source repo under www/doc, or at
http://blerg.cc/doc/

=head1 AUTHOR

Chip Black, E<lt>bytex64@bytex64.netE<gt>

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2013 by Chip Black

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.16.1 or,
at your option, any later version of Perl 5 you may have available.

=cut