/usr/local/CPAN/Catalog/Catalog/path.pm


#
#   Copyright (C) 1999 Loic Dachary
#
#   This program is free software; you can redistribute it and/or modify it
#   under the terms of the GNU General Public License as published by the
#   Free Software Foundation; either version 2, or (at your option) any
#   later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with this program; if not, write to the Free Software
#   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
#
# 
# $Header: /cvsroot/Catalog/Catalog/lib/Catalog/path.pm,v 1.4 1999/09/07 14:48:04 loic Exp $
#
# 
package Catalog::path;
use strict;
use vars qw(@EXPORT_OK @ISA);

require Exporter;

use MD5;
use Carp;

use Catalog::tools::tools;

@ISA = qw(Exporter);
@EXPORT_OK = qw(&path_simplify_component &path_simplify_path);

#
# Mandatory
# name : name of the catalog
# root : id of the catalog root
# url : base location of catalog
# db : DBI database pointer
# either pathname or id or path
#
# Optional
# path : comma separated list of id
# pathname : readable path name
# id : id of category
#
sub new {
    my($type, %args) = @_;

    my($self) = \%args;
    bless($self, $type);
    $self->initialize();
    return $self;
}

sub initialize {
    my($self) = @_;

    error("missing url") if(!defined($self->{'url'}));
    error("missing name") if(!defined($self->{'name'}));
    error("missing db") if(!defined($self->{'db'}));
    error("missing root") if(!defined($self->{'root'}));

    my($key);
    foreach $key (qw(pathname path id)) {
	$self->{$key} = undef if(!$self->{$key});
    }
}

sub fill {
    my($self) = @_;
    my($db) = $self->{'db'};

    return if($self->{'filled'});

    my($row);
    if(defined($self->{'id'})) {
	$row = $db->exec_select_one("select * from catalog_path_$self->{'name'} where id = $self->{'id'}");
    } elsif(defined($self->{'pathname'})) {
	my($md5) = MD5->hexhash($self->{'pathname'});
	$row = $db->exec_select_one("select * from catalog_path_$self->{'name'} where md5 = '$md5'");
	
    } elsif(defined($self->{'path'})) {
	my($id) = $self->{'path'} =~ /(\d+)$/;
	$row = $db->exec_select_one("select * from catalog_path_$self->{'name'} where id = $id");
    } else {
	my($id) = $self->{'root'};
	$row = $db->exec_select_one("select * from catalog_path_$self->{'name'} where id = $id");
    }
    error("no row found") if(!defined($row));

    my($key);
    foreach $key (qw(pathname path id)) {
	$self->{$key} = $row->{$key};
    }

    $self->{'path'} =~ s/^,(.*),$/$1/;

    $self->{'filled'} = 1;
}

sub fashion {
    my($self) = @_;
    return $self->{'fashion'};
}

sub name {
    my($self) = @_;
    return $self->{'name'};
}

sub root {
    my($self) = @_;
    return $self->{'root'};
}

sub db {
    my($self) = @_;
    return $self->{'db'};
}

sub path {
    my($self) = @_;
    $self->fill() if(!defined($self->{'path'}));
    return $self->{'path'};
}

sub path_array {
    my($self) = @_;
    return split(',', $self->path());
}

sub pathname {
    my($self) = @_;
    $self->fill() if(!defined($self->{'pathname'}));
    return $self->{'pathname'};
}

sub pathname_array {
    my($self) = @_;

    return split('/', substr($self->pathname(), 1, -1));
}

sub id {
    my($self) = @_;
    $self->fill() if(!defined($self->{'id'}));
    return $self->{'id'};
}

sub pathname_file {
    my($self) = @_;

    return path_simplify_pathname($self->pathname());
}

sub pathname_file_array {
    my($self) = @_;

    return map { path_simplify_component($_) } $self->pathname_array();
}

sub pathname_html_array {
    my($self) = @_;

    my($fashion) = $self->{'fashion'};

    my(%params) = (
		   'root_label' => 'root',
		   'separator' => ':',
		   'last_link' => undef,
		   'root_constant' => undef,
		   );
    my($key);
    foreach $key (qw(root_label separator last_link root_constant)) {
	my($param);
	if(defined($self->{"path_$key"})) {
	    if(ref($self->{"path_$key"})) {
		$param = $self->{"path_$key"}->{$self->{'name'}};
	    } else {
		$param = $self->{"path_$key"};
	    }
	}
	$params{$key} = $param if(defined($param));
    }

    my(@html);
    my($url) = $self->{'url'};
    if($fashion eq 'intuitive') {
	push(@html, "<a href=$url/>$params{'root_label'}</a>$params{'separator'}") if(!defined($params{'root_constant'}));

	my($new_path) = '/';
	my(@names) = $self->pathname_array();
	my($count) = scalar(@names);
	my($i) = 1;
	my($name);
	foreach $name (@names) {
	    my($printed_name) = $name;
	    $printed_name =~ s/_/ /go;
	    $new_path .= "$name/";
	    if($i >= $count && !defined($params{'last_link'})) {
		push(@html, "$printed_name");
	    } else {
		push(@html, "<a href=$url$new_path>$printed_name</a>$params{'separator'}");
	    }
	    $i++;
	}
    } else {
	push(@html, "<a href=$url&id=$self->{'root'}>$params{'root_label'}</a>$params{'separator'}") if(!defined($params{'root_constant'}));;

	my($path) = $self->path();
	#
	# Root has no path at all, do nothing
	#
	if($path) {
	    my($rows) = $self->{'db'}->exec_select("select rowid,name from catalog_category_$self->{'name'} where rowid in ( $path )");
	    $rows = { map { $_->{'rowid'} => $_ } @$rows };

	    my($new_path) = '';
	    my($rowid);
	    my(@path) = split(',', $path);
	    my($last) = $path[$#path];
	    foreach $rowid (@path) {
		my($row) = $rows->{$rowid};
		$new_path .= "$rowid";
		if($rowid eq $last  && !defined($params{'last_link'})) {
		    push(@html, "$row->{'name'}");
		} else {
		    push(@html, "<a href=$url&id=$row->{'rowid'}&path=$new_path>$row->{'name'}</a>$params{'separator'}");
		}
		$new_path .= ",";
	    }
	}
    }

    return @html;
}

sub path_text_array {
    my($self) = @_;

    my(%params) = (
		   'root_label' => 'root',
		   );

    my($key);
    foreach $key (qw(root_label)) {
	my($param);
	if(defined($self->{"path_$key"})) {
	    if(ref($self->{"path_$key"})) {
		$param = $self->{"path_$key"}->{$self->{'name'}};
	    } else {
		$param = $self->{"path_$key"};
	    }
	}
	$params{$key} = $param if(defined($param));
    }

    my(@text) = $params{'root_label'};
    
    my($path) = $self->path();
    #
    # Root has no path at all, do nothing
    #
    if($path) {
	my($rows) = $self->{'db'}->exec_select("select rowid,name from catalog_category_$self->{'name'} where rowid in ( $path )");
	my(%rowid2name) = map { $_->{'rowid'} => $_->{'name'} } @$rows;
	push(@text, map { $rowid2name{$_} } split(',', $path));
    }

    return @text;
}

sub pathname_html {
    my($self) = @_;

    return join('', $self->pathname_html_array());
}

sub ptemplate_set {
    my($self, $template) = @_;

    my($assoc) = $template->{'assoc'};

    my($skip) = 1;
    my(%todo);
    my($tag);
    foreach $tag (keys(%$assoc)) {
	if($tag =~ /^_PATH(.*)_$/o) {
	    my($spec) = $1;
	    if($spec eq '' || $spec =~ /^\d+$/o) {
		$todo{'path'} = 1;
		$skip = 0;
	    } elsif($spec =~ /^FILE/o) {
		$todo{'pathfile'} = 1;
		$skip = 0;
	    } elsif($spec =~ /^TEXT/o) {
		$todo{'pathtext'} = 1;
		$skip = 0;
	    }
	}
    }

    #
    # Stop there if nothing to be done
    #
    return if($skip);

    my(@path);
    @path = $self->pathname_html_array() if($todo{'path'});
    my(@pathfile);
    @pathfile = $self->pathname_array() if($todo{'pathfile'});
    my(@pathtext);
    @pathtext = $self->path_text_array() if($todo{'pathtext'});

    foreach $tag (keys(%$assoc)) {
	if($tag =~ /^_PATH(.*)_$/) {
	    my($spec) = $1;
	    if($spec eq '') {
		template_set($assoc, $tag, join('', @path));
	    } elsif($spec =~ /^(\d+)$/) {
		my($index) = $1;
		template_set($assoc, $tag, $path[$index]) if(defined($path[$index]));
	    } elsif($spec =~ /^FILE$/) {
		template_set($assoc, $tag, join('_', @pathfile));
	    } elsif($spec =~ /^FILE(.*)$/) {
		my($index) = $1;
		if($index !~ /^\d+$/) {
		    $index =~ s/MINUS/-/g;
		    $index =~ s/DOTDOT/../g;
		    my(@list);
		    eval "\@list = \@pathfile[$index]";
		    croak("syntacticaly invalid range in $spec") if($@);
		    template_set($assoc, $tag, join('/', @list));
		} else {
		    template_set($assoc, $tag, $pathfile[$index]) if(defined($pathfile[$index]));
		}
	    } elsif($spec =~ /^TEXT$/) {
		template_set($assoc, $tag, join('/', @pathtext));
	    } elsif($spec =~ /^TEXT(.*)$/) {
		my($index) = $1;
		if($index !~ /^\d+$/) {
		    $index =~ s/MINUS/-/g;
		    $index =~ s/DOTDOT/../g;
		    my(@list);
		    eval "\@list = \@pathtext[$index]";
		    croak("syntacticaly invalid range in $spec") if($@);
		    template_set($assoc, $tag, join('/', @list));
		} else {
		    template_set($assoc, $tag, $pathtext[$index]) if(defined($pathtext[$index]));
		}
	    }
	}
    }
}

sub path_simplify_component {
    my($string) = @_;

    $string =~ s/[ \'\"]/_/og;
    return $string;
}

sub path_simplify_pathname {
    my($string) = @_;

    $string =~ s|[ \'\"/]|_|og;
    return $string;
}

1;
# Local Variables: ***
# mode: perl ***
# End: ***