/* 
 * adium-plugin-blahtex, Copyright (C) Hagen Fritsch, 2006
 * based upon AdiumLatexPlugin by Adium Developers
 * 
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

// User must have a working blahtex installation, otherwise this will fail :/

#import <Adium/AIContentControllerProtocol.h>
#import "AIBlahtexPlugin.h"
#import <Adium/AITextAttachmentExtension.h>
#include <Python.h>
#define CODE "import os, sys, re\n\
os.environ['PATH']+=':/sw/bin' #for blahtex and fink-tex-stuff\n\
def render(tex):\n\
        #print \"rendering\", tex\n\
        (w,r) = os.popen2('blahtex --png')\n\
        w.write(tex)\n\
        w.close()\n\
        data = r.read()\n\
        r.close()\n\
        match = re.compile(r'<md5>(.+?)</md5>').search(data)\n\
        if match:\n\
            data = open(match.group(1)+'.png').read()\n\
            os.unlink(match.group(1)+'.png')\n\
            return (1, data)\n\
        else: return (0, data)\n\
"
static PyObject *pFunc;

/*!
 * @class AIBlahtexPlugin
 * @brief Filter plugin which converts $$xxx$$, where xxx is a LaTeX expression, to a blahtex-generated image-representation
 */
@implementation AIBlahtexPlugin

- (void)installPlugin
{
	//[[adium contentController] registerContentFilter:self ofType:AIFilterContent direction:AIFilterOutgoing];
	[[adium contentController] registerContentFilter:self ofType:AIFilterMessageDisplay direction:AIFilterOutgoing];
	[[adium contentController] registerContentFilter:self ofType:AIFilterMessageDisplay direction:AIFilterIncoming];
	//[[adium contentController] registerContentFilter:self ofType:AIFilterDisplay direction:AIFilterIncoming];
}
static int py_initialized = 0;
void py_init() {
	PyObject * pMod, *pDict;
	Py_Initialize();
	pMod = PyImport_AddModule("__main__");
	PyRun_SimpleString(CODE);
	pDict = PyModule_GetDict(pMod);
	pFunc = PyDict_GetItemString(pDict, "render");
	py_initialized = 1;
}
- (void)uninstallPlugin
{
	if(py_initialized) Py_Finalize();
	[[adium contentController] unregisterContentFilter:self];
}
int renderTex(const char * tex, char ** filename) {
	PyObject  *pArgs, *pRet;
	int ret;
	pArgs = PyTuple_New(1);
	PyTuple_SetItem(pArgs, 0, PyString_FromString(tex));
	pRet = PyObject_CallObject(pFunc, pArgs);
	Py_DECREF(pArgs);
	ret = PyInt_AsLong(PySequence_GetItem(pRet, 0));
	pArgs = PySequence_GetItem(pRet, 1);
	size_t size = PyString_Size(pArgs);
	*filename = malloc(size+1);
	memcpy(*filename, PyString_AsString(pArgs), size);
	(*filename)[size] = 0;
	if(ret)
		ret = size;
	Py_DECREF(pRet);
	return ret;
}
const char * getString(NSString * str) {
    return [str cStringUsingEncoding:NSUTF8StringEncoding];
}

- (NSAttributedString *)filterAttributedString:(NSAttributedString *)inAttributedString context:(id)context
{
    NSMutableAttributedString       *newMessage = nil;
    #define DELILEN 2
	#define DELI "$$"
    if (inAttributedString && 
		([[inAttributedString string] rangeOfString:@DELI options:NSLiteralSearch].location != NSNotFound)) {
		NSScanner       *stringScanner;
		NSString        *innerLaTeX;
		int				i, removedChars = 0; 
		if(!py_initialized) py_init();
		
		stringScanner = [[NSScanner alloc] initWithString:[inAttributedString string]];
        [stringScanner setCharactersToBeSkipped:[[[NSCharacterSet alloc] init] autorelease]];
		
		while ([stringScanner isAtEnd] == NO) {
			[stringScanner scanUpToString:@DELI intoString:nil];
			[stringScanner scanString:@DELI intoString:nil];
			
			i = [stringScanner scanLocation];
			if ([stringScanner scanUpToString:@DELI intoString:&innerLaTeX] && ![stringScanner isAtEnd]) {
				[stringScanner setScanLocation:([stringScanner scanLocation]+DELILEN)];
				NSString                    *fullLaTeX;
				NSMutableAttributedString   *replacement;
				
				//AITextAttachmentExtension   *attachment;
				fullLaTeX = [NSString stringWithFormat:@DELI"%@"DELI, innerLaTeX];
				char * filename;
				size_t size = renderTex(getString(innerLaTeX), &filename);
				if(size == 0) {
					/* error */
					replacement = [[[NSMutableAttributedString alloc] initWithString:[NSString stringWithCString:filename encoding:NSUTF8StringEncoding]] autorelease];
				} else {
					AITextAttachmentExtension   *blahtexAtt = [[[AITextAttachmentExtension alloc] init] autorelease];
					NSData * data = [[[NSData alloc] initWithBytesNoCopy:(void*)filename length:size] autorelease];
					[blahtexAtt setImage:[[[NSImage alloc] initWithData:data] autorelease]];
					[blahtexAtt setHasAlternate:YES];
					[blahtexAtt setImageClass:@"blahtex"];
					[blahtexAtt setString:fullLaTeX];
					replacement = [[NSMutableAttributedString alloc] initWithAttributedString:[NSAttributedString attributedStringWithAttachment:blahtexAtt]];
				}
				//[replacement insertAttributedString:img atIndex:0];
				// grab the original attributes, to ensure that the background is not lost in a message consisting only of LaTeX
				[replacement addAttributes:[inAttributedString attributesAtIndex:i effectiveRange:nil]
										 range:NSMakeRange(0,[replacement length])];
				if(size==0) //mark errors red
					[replacement addAttribute:NSForegroundColorAttributeName value:[NSColor redColor] range:NSMakeRange(0,[replacement length])];
				// insert the image
				if (!newMessage) // only create the copy if needed
					newMessage = [[inAttributedString mutableCopy] autorelease];
				[newMessage replaceCharactersInRange:NSMakeRange(i-DELILEN-removedChars, [fullLaTeX length]) 
									withAttributedString:replacement];
				removedChars += [fullLaTeX length]-[replacement length];
			}
		}

		[stringScanner release];
    }

    return (newMessage ? newMessage : inAttributedString);
}

- (float)filterPriority
{
	return DEFAULT_FILTER_PRIORITY;
}

@end
