/*
** Copyright (C) 2002 Robert Helgesson <rycee@home.se>
**
** 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 of the License, 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "httpd.h"
#include "http_config.h"
#include "http_protocol.h"
#include "ap_config.h"

#include <string.h>
#include <format.h>

#include "config.h"

module MODULE_VAR_EXPORT highlight_module;

typedef struct {
	int enabled;
	char *stylesheet;
} hl_conf;


static void *make_dir_config(pool *p, char *dir)
{
	hl_conf *cfg = (hl_conf *) ap_palloc(p, sizeof (hl_conf));

	cfg->enabled = 0;
	cfg->stylesheet = "";

	return (void *) cfg;
}

static void *merge_dir_config(pool *p, void *parent_cfg, void *subdir_cfg)
{
	hl_conf *p_cfg = (hl_conf *) parent_cfg;
	hl_conf *s_cfg = (hl_conf *) subdir_cfg;
	hl_conf *m_cfg = (hl_conf *) ap_palloc(p, sizeof (hl_conf));

	m_cfg->enabled = ( s_cfg->enabled ) ? s_cfg->enabled : p_cfg->enabled;

	if ( s_cfg->stylesheet[0] != '\0' )
		m_cfg->stylesheet = s_cfg->stylesheet;
	else if ( p_cfg->stylesheet[0] != '\0' )
		m_cfg->stylesheet = p_cfg->stylesheet;
	else
		m_cfg->stylesheet = "";

	return m_cfg;
}

static const char *highlight_enable_cmd(cmd_parms *cmd, void *dummy, int arg)
{
	hl_conf *cfg = (hl_conf *) dummy;

	cfg->enabled = arg;

	return NULL;
}

static const char *highlight_style_cmd(cmd_parms *cmd, void *dummy, char *arg)
{
	hl_conf *cfg = (hl_conf *) dummy;

	cfg->stylesheet = arg;

	return NULL;
}

static int highlight_handler(request_rec *r)
{
	const char *language = strchr(r->handler, '-') + 1;
	char *output = NULL;
	
	// ¿©±â¼­ºÎÅÍ ³»°¡ Ãß°¡ÇÑ º¯¼öµé..
	char *new_output = NULL;

	int i, j, count, pre;
	int length;
	int loop;
	
	int lineno = 1;
	int lineno_len;
	char lineno_buf[10];
	// ¿©±â±îÁö..
	
	const hl_conf *cfg = NULL;

	if ( r->finfo.st_mode == 0 )
		return NOT_FOUND;

	cfg = ap_get_module_config(r->per_dir_config, &highlight_module);

	if ( ! cfg->enabled || ! format_valid_lang(language) ) {
		return DECLINED;
	}

	if ( r->args != NULL ) {
		r->content_type = "text/plain";		/* whatever */
		return DECLINED;
	}

	r->content_type = "text/html";
	ap_send_http_header(r);

	if ( r->header_only ) {
		return OK;
	}

	output = format_file(r->filename, language);
	
	// ¿©±â¼­ºÎÅÍ ³»°¡ ¼öÁ¤ÇÑ ºÎºÐ..
	ap_rvputs(
			r,
			"<html><head>"
			"<title>", r->uri, "</title>\n"
			"<link rel=\"stylesheet\" type=\"text/css\" href=\"",
			cfg->stylesheet, "\" />\n"
			"<meta name=\"generator\" content=\"" PACKAGE_STRING
			"\" /></head>\n<body class=\"format_global\">\n"
			"<a href=\"", r->uri, "?t\">plain text</a>\n<hr />\n<tt>\n",
			NULL
	);

	count = 0;
	length = strlen( output );
	for( i = 0 ; i < length ; i++ ){

		if( *(output+i) == '\n' )
			count++;
	
	}
	sprintf( lineno_buf, "%d: ", count );
	lineno_len = strlen( lineno_buf );
	
	new_output = strtok( output, "\n" );
	
	while( new_output != NULL ){

		count = 0;
		pre = 0;
		
		sprintf( lineno_buf, "%d: ", lineno );
		length = strlen(new_output);
		
		ap_rputs( "<font class=\"lineno\">",r );
		loop = lineno_len - strlen( lineno_buf );
		for( i = 0 ; i < loop ; i++ )
			ap_rputs( "&nbsp;", r );
		
		ap_rvputs( r, lineno_buf, "&nbsp; </font>", NULL );
		lineno++;
		
		for( i = 0 ; i < length ; i++ ){

			if( *( new_output + i ) == ' ' )
				count+=2;

			else if( *( new_output + i ) == '\t' )
				count += 8;

			else break;

		}

		pre = i;

		for( i = 0 ; i < count ; i++ )
			ap_rputs("&nbsp;", r );

		ap_rputs( (new_output + pre) , r );
		ap_rputs( "<br>\n", r );

		for( i = 1; *(new_output+length+i ) == '\n'; i++ ){
		
			
			sprintf( lineno_buf, "%d: ", lineno );
			ap_rputs( "<font class=\"lineno\">",r );
			loop = lineno_len-strlen(lineno_buf);
			for( j = 0 ; j < loop ; j++ )
				ap_rputs( "&nbsp;", r );
			
			lineno++;

			ap_rvputs( r, lineno_buf, "</font><br>\n", NULL );

		}
		
		new_output = strtok( NULL , "\n" );

	}

	ap_rvputs(
			r,
			"\n</tt></body></html>",
			NULL
	);
	// ¿©±â±îÁö°¡ ³»°¡ ¼Õ´í ºÎºÐ..
	
	free(output);

	return OK;
}

static const command_rec highlight_cmds[] = {
	{ "Highlight", highlight_enable_cmd, NULL, OR_OPTIONS, FLAG,
		"whether to enable syntax highlighting or not" },
	{ "HighlightStyle", highlight_style_cmd, NULL, OR_OPTIONS, TAKE1,
		"which stylesheet to use" },
	{ NULL }
};

static const handler_rec highlight_handlers[] = {
	{ "source-*", highlight_handler },
	{ NULL }
};

/* Dispatch list for API hooks */
module MODULE_VAR_EXPORT highlight_module = {
	STANDARD_MODULE_STUFF,
	NULL,			/* module initializer			*/
	make_dir_config,	/* create per-dir    config structures	*/
	merge_dir_config,	/* merge  per-dir    config structures	*/
	NULL,			/* create per-server config structures	*/
	NULL,			/* merge  per-server config structures	*/
	highlight_cmds,		/* table of config file commands	*/
	highlight_handlers,	/* [#8] MIME-typed-dispatched handlers	*/
	NULL,			/* [#1] URI to filename translation	*/
	NULL,			/* [#4] validate user id from request	*/
	NULL,			/* [#5] check if the user is ok _here_	*/
	NULL,			/* [#3] check access by host address	*/
	NULL,			/* [#6] determine MIME type		*/
	NULL,			/* [#7] pre-run fixups			*/
	NULL,			/* [#9] log a transaction		*/
	NULL,			/* [#2] header parser			*/
	NULL,			/* child_init				*/
	NULL,			/* child_exit				*/
	NULL			/* [#0] post read-request		*/
};

/* vi:set ts=8 sw=8 noet: */

