package ID3FS::Fuse;

use strict;
use warnings;
use ID3FS::Path;
use Fuse;
use POSIX qw(EINVAL EROFS ENOENT EOPNOTSUPP S_IRUSR S_IRGRP S_IROTH S_IXUSR S_IXGRP S_IXOTH);
use vars qw($TYPE_DIR $TYPE_SYMLINK);
($TYPE_DIR, $TYPE_SYMLINK)=(0040, 0120);

sub new
{
    my $proto=shift;
    my $class=ref($proto) || $proto;
    my $self={};
    bless($self,$class);

    $self->{db}=shift;
    $self->{source}=shift;
    $self->{mountpoint}=shift;
    $self->{debug}=shift;
    $self->{perms} = S_IRUSR() | S_IXUSR() | S_IRGRP() | S_IXGRP() | S_IROTH() | S_IXOTH();

    return $self;
}

sub run
{
    my($self)=@_;
    Fuse::main(
	mountpoint  => $self->{mountpoint},
	threaded    => 0,
	debug       => $self->{debug},
	mountopts   => "allow_other,ro",
	getattr     => sub { $self->getattr(@_); },
	readlink    => sub { $self->readlink(@_); },
	getdir      => sub { $self->getdir(@_); },
	# Not used
#	mknod       => sub { $self->mknod(@_); },
#	mkdir       => sub { $self->mkdir(@_); },
#	unlink      => sub { $self->unlink(@_); },
#	rmdir       => sub { $self->rmdir(@_); },
#	symlink     => sub { $self->symlink(@_); },
#	rename      => sub { $self->rename(@_); },
#	link        => sub { $self->link(@_); },
#	chmod       => sub { $self->chmod(@_); },
#	chown       => sub { $self->chown(@_); },
#	truncate    => sub { $self->truncate(@_); },
#	utime       => sub { $self->utime(@_); },
#	open        => sub { $self->open(@_); },
#	read        => sub { $self->read(@_); },
#	write       => sub { $self->write(@_); },
#	statfs      => sub { $self->statfs(@_); },
#	release     => sub { $self->release(@_); },
#	fsync       => sub { $self->fsync(@_); },
#	setxattr    => sub { $self->setxattr(@_); },
#	getxattr    => sub { $self->getxattr(@_); },
#	listxattr   => sub { $self->listxattr(@_); },
#	removexattr => sub { $self->removexattr(@_); },
	);
}

sub getattr
{
    my($self, $filename)=@_;
    print "**GETATTR: $filename\n";
    my $path=ID3FS::Path->new($self->{db}, $filename);
    return(-ENOENT()) unless($path->isvalid());
    my($dev,$ino,$nlink)=(0,0,1);
    my $uid=$<;
    my $gid=(split(/ /, $( ))[0];
    my($rdev,$size)=(0,1);
    my($atime,$mtime,$ctime)=(0,0,0);
    my($blksize,$blocks)=(512,1);
    my $mode=$self->mode( $path->isdir() ? $TYPE_DIR : $TYPE_SYMLINK );
    return($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
	   $atime,$mtime,$ctime,$blksize,$blocks);
}

sub readlink
{
    my($self,$filename)=@_;
    print "**READLINK: $filename\n";
    my $path=ID3FS::Path->new($self->{db}, $filename);
    return(-EINVAL()) if($path->isdir());
    return $path->dest();
}

sub getdir
{
    my($self, $filename)=@_;
    print "**GETDIR: $filename\n";
    my $path=ID3FS::Path->new($self->{db}, $filename);
    return(-ENOENT()) unless($path->isvalid());
    if($path->isdir())
    {
	return(".", "..", $path->dirents(), 0);
    }
    return -ENOTDIR();
}

# unused stubs
sub mknod       { print "mknod\n"; return -EROFS();            }
sub mkdir       { print "mkdir\n"; return -EROFS();            }
sub unlink      { print "unlink\n"; return -EROFS();           }
sub rmdir       { print "rmdir\n"; return -EROFS();            }
sub symlink     { print "symlink\n"; return -EROFS();          }
sub rename      { print "rename\n"; return -EROFS();           }
sub link        { print "link\n"; return -EROFS();             }
sub chmod       { print "chmod\n"; return -EROFS();            }
sub chown       { print "chown\n"; return -EROFS();            }
sub truncate    { print "truncate\n"; return -EROFS();         }
sub utime       { print "utime\n"; return -EINVAL();           }
sub open        { print "open\n"; return -EINVAL();            }
sub read        { print "read\n"; return -EINVAL();            }
sub write       { print "write\n"; return -EROFS();            }
sub statfs      { print "statfs\n"; return -EINVAL();          }
sub release     { print "release\n"; return 0;                 }
sub fsync       { print "fsync\n"; return 0;                   }
sub setxattr    { print "setxattr\n"; return -EOPNOTSUPP();    }
sub getxattr    { print "getxattr\n"; return -EOPNOTSUPP();    }
sub listxattr   { print "listxattr\n"; return -EOPNOTSUPP();   }
sub removexattr { print "removexattr\n"; return -EOPNOTSUPP(); }

sub mode
{
    my($self, $type)=@_;
    return(($type << 9) | $self->{perms});
}



1;
