package Type::Manager; ###### 
# 	$Id: Manager.pm,v 1.2 2003/05/09 19:32:14 steve Exp $
#	This file is part of Combo and is licensed under the GPL.
#	Copyright 2001-2002 by the authors.  See README and LICENSE
#	for more details or see http://penguinsong.org/.

### Type::Manager is the manager for Type:: packages.  It retrieves the 
#	appropriate Type package for a resource, doing lazy file loading
#	and caching if necessary.

use Context;
use Combo;
use Site::Config;
use Site::Util;
use LWP::MediaTypes;

use Type::Base;			# strictly speaking, we don't need Type::Base
				# but we preload it because all the Type
				# classes depend on it.  Get it over with early

use strict;

BEGIN {
    use vars qw($VERSION @ISA);
    
    $VERSION=1.00;
    @ISA = qw( );
}



#############################################################################
###
### Construction:
###

### Type::Manager->new($config)
#	Create new Type::Manager for the site Config.  Manager is a
#	singleton class.  Most (all?) of its methods could perfectly well
#	be static functions, but the syntax is cleaner when they're methods.	
#
#	Note that a Type depends _only_ on the Site::Config -- it has 
#	nothing to do with the query and user information.  In theory,
#	then, we could keep them around forever.  
#
sub new {
    my ($class, $config) = @_;

    # Cache a couple of useful constants.
    my $self = {'_doc_root'=>$config->getDocRoot,
	    };
    $self = bless $self, $class;

    return $self;
}




#############################################################################
###
### Getting a Type:: Implementation:
###


sub getContentType {
    my ($cxt, $realpath) = @_;

    my $filePath = $cxt->getDocRoot . $realpath;
    my $type = "text/html"  if $filePath =~ /\.ht$/;
    $type = "text/plain" if !$type && $filePath =~ /\.wt$/;
    $type = guess_media_type($filePath) unless $type;

    return $type;
}


### $mgr->getType($cxt, $realpath)
#	Returns the Type:: handler object for $realpath.
#	$realpath defaults to $cxt->getRealPath; we allow it to be passed
#	separately so that we can get a Type:: handler for a resource other
#	than the one directly requested.  This is especially useful inside
#	directories. 
sub getType {
    my ($self, $cxt, $realpath) = @_;
    my $cfg = $cxt->getConfig;
    $realpath = $cxt->getRealPath unless $realpath;

    # === not clear what to do if we don't have a path.  Assume root?
    $realpath = '/' unless $realpath;

    if ($realpath =~ m|/$| || -d $cxt->getDocRoot . $realpath) {
	# directory
	require Type::Dir;
	return Type::Dir->new($cfg);
    }

    # Not a directory:  find Type based on extension
    $realpath =~ m|\.([^\./]+)$|;
    my $ext = $1;

    # === fake things for now.
    # === We really don't have to create a new one each time: 
    #	  what we really need to do is cache them in a hash.
    #	  This means that eventually the Site::Config will point to
    #	  an instance of Type::Manager.
    
    if ($ext =~ m/ht[itx]?$/) {
	require Type::ProcHT;
	return Type::ProcHT->new($cfg);
    } elsif ($ext =~ m/wt[i]?/) {
	require Type::ProcWiki;
	return Type::ProcWiki->new($cfg);
    } elsif ($ext =~ m/cf/) {
	require Type::ConfigFile;
	return Type::ConfigFile->new($cfg);
    } 

    # Can't find directory:  guess the MIME type		     
    my $mimetype = getContentType($cxt, $realpath);

    if ($mimetype =~ m|^text/html|i) {
	require Type::Html; 
	return Type::Html->new($cfg);
    } elsif ($mimetype =~ m|^text/|i) {
	require Type::Text; 
	return Type::Text->new($cfg);
    } else {
	require Type::Base;
	return Type::Base->new($cfg);
    }
}


#############################################################################
1;
