#!/usr/bin/env python
#
# $Id: make_interfaces.py,v 1.2 2000/11/21 04:54:32 mrnolta Exp $
#
gnu_licence = """\
# Copyright (C) 2000 Mike Nolta <mrnolta@users.sourceforge.net>
#
# 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.
#
"""

import os, re, string, sys

LIBPLOT_VER = sys.argv[1]
LIBPLOT_H = "plot-%s.h"	% LIBPLOT_VER	# library header file (input)
LIBPLOT_I = "_libplot.i"		# swig interface (output)
LIBPLOT_PY = "libplot.py"		# python interface (output)

NAME_CMODULE = "_libplot"
NAME_PYMODULE = "libplot"

###############################################################################

HEADER_I = """\
%module """ + NAME_CMODULE + """
%{
#include <plot.h>
%}

/* allows us to pass Python file objects to pl_newpl_r */
%typemap(python,in) FILE * {
	if ( $source == Py_None )
	{
		$target = NULL;
	}
	else if ( PyFile_Check( $source ) )
	{
		$target = PyFile_AsFile( $source );
	}
	else
	{
		PyErr_SetString( PyExc_TypeError, "not a file" );
		return NULL;
	}
}

/* we assume you only pass strings to pl_setplparam */
%typemap(python,in) void *value {
	if ( !PyString_Check( $source ) )
	{
		PyErr_SetString( PyExc_TypeError, "not a string" );
		return NULL;
	}
	$target = (void *) PyString_AsString( $source );
}

/* Marker symbols */

enum 
{ M_NONE, M_DOT, M_PLUS, M_ASTERISK, M_CIRCLE, M_CROSS, 
  M_SQUARE, M_TRIANGLE, M_DIAMOND, M_STAR, M_INVERTED_TRIANGLE, 
  M_STARBURST, M_FANCY_PLUS, M_FANCY_CROSS, M_FANCY_SQUARE, 
  M_FANCY_DIAMOND, M_FILLED_CIRCLE, M_FILLED_SQUARE, M_FILLED_TRIANGLE, 
  M_FILLED_DIAMOND, M_FILLED_INVERTED_TRIANGLE, M_FILLED_FANCY_SQUARE,
  M_FILLED_FANCY_DIAMOND, M_HALF_FILLED_CIRCLE, M_HALF_FILLED_SQUARE,
  M_HALF_FILLED_TRIANGLE, M_HALF_FILLED_DIAMOND,
  M_HALF_FILLED_INVERTED_TRIANGLE, M_HALF_FILLED_FANCY_SQUARE,
  M_HALF_FILLED_FANCY_DIAMOND, M_OCTAGON, M_FILLED_OCTAGON 
};

/* PlotterParams */

extern plPlotterParams * pl_newplparams (void);
extern int pl_deleteplparams (plPlotterParams *plotter_params);
extern plPlotterParams * pl_copyplparams (const plPlotterParams *plotter_params);
extern int pl_setplparam (plPlotterParams *plotter_params, const char *parameter, void *value);

/* Plotter */

extern plPlotter * pl_newpl_r (const char *type, FILE *infile, FILE *outfile, FILE *errfile, const plPlotterParams *plotter_params);
extern int pl_deletepl_r (plPlotter *plotter);

/* Plotter member functions */
"""

###############################################################################

HEADER_PY = """\
#
# libplot.py
#
""" + gnu_licence + """\

from """ + NAME_CMODULE + """ import *

class LibplotError( Exception ):
	pass

class Plotter:
	def __init__( self, type="X", params=None,
			outfile=None, infile=None, errfile=None ):

		self.plparams = pl_newplparams()
		if params:
			for key,value in params.items():
				pl_setplparam( self.plparams, key, value )

		self.this = pl_newpl_r( type, infile, outfile, errfile, self.plparams )
		if self.this < 0:
			raise LibplotError( "could not create plotter" )

	def __del__( self ):
		pl_deletepl_r( self.this )
		pl_deleteplparams( self.plparams )
"""

###############################################################################

re_pl_name = re.compile( r"pl_(\w+)_r" )
re_pl_cdef = re.compile( r"(.+)\((.+)\)" )

ignore_functions_list = [ "deletepl", "outfile" ]

def is_plotter_method( cdef ):
	word = string.split( cdef )
	if len(word) > 2 and (word[0] == "int" or word[0] == "double"):
		m = re_pl_name.match( word[1] )
		if m:
			return m.group(1) not in ignore_functions_list
	return 0 # false

def swig_def( cdef ):
	return "extern " + cdef

def last_word( str ):
	return string.split( str )[-1]

def python_def( cdef ):
	m = re_pl_cdef.match( cdef )

	cname = last_word( m.group(1) )
	pyname = re_pl_name.match( cname ).group(1)

	args = []
	for x in string.split( m.group(2), "," ):
		args.append( last_word(x) )
	args = args[1:] # strip off *plotter

	pyargs = string.join( ["self"] + args, "," )
	cargs = string.join( ["self.this"] + args, "," )

	pyargs = string.replace( pyargs, "*", "" )
	cargs = string.replace( cargs, "*", "" )

	return """
	def %s(%s):
		return %s(%s)
""" % (pyname, pyargs, cname, cargs)

###############################################################################

def preprocessed( file ):
	return os.popen( "gcc -E " + file )

if __name__ == '__main__':

	fi = open( LIBPLOT_I, 'w' )
	fpy = open( LIBPLOT_PY, 'w' )

	fi.write( HEADER_I )
	fpy.write( HEADER_PY )

	fh = preprocessed( LIBPLOT_H )

	for line in fh.readlines():
		if is_plotter_method( line ):
			fi.write( swig_def(line) )
			fpy.write( python_def(line) )

	fh.close()

	fi.close()
	fpy.close()
