/* $Id$
 *
 * Copyright © 2004 Keith Packard
 *
 * This library is free software; you can redistribute it and/or
 * modify it either under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation
 * (the "LGPL") or, at your option, under the terms of the Mozilla
 * Public License Version 1.1 (the "MPL"). If you do not alter this
 * notice, a recipient may use your version of this file under either
 * the MPL or the LGPL.
 *
 * You should have received a copy of the LGPL along with this library
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * You should have received a copy of the MPL along with this library
 * in the file COPYING-MPL-1.1
 *
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
 * the specific language governing rights and limitations.
 *
 * The Original Code is the cairo graphics library.
 *
 * The Initial Developer of the Original Code is Keith Packard
 *
 * Contributor(s):
 *      Keith Packard <keithp@keithp.com>
 */

autoload Cairo;

namespace Graph {
    import Cairo;

    public typedef enum { linear, log } scale_kind_t;
    
    public typedef struct {
	scale_kind_t	kind;
	real		low, high;
	real		len;
    } scale_t;

    real scale (scale_t scale, real value)
    {
	if (scale.kind == scale_kind_t.log)
	{
	    value = log(value);
	    scale.low = log (scale.low);
	    scale.high = log (scale.high);
	}
        return scale.len * (value - scale.low) / (scale.high - scale.low);
    }

    public typedef struct {
	&scale_t    scale;
	real	    major;
	real	    minor;
    } axis_t;
    
    public typedef struct {
	cairo_t	cr;
	axis_t	left;
	axis_t	bottom;
    } graph_t;

    void axis_draw (cairo_t cr, axis_t axis)
    {
	move_to (cr, scale (axis.scale,axis.scale.low), 0);
	line_to (cr, scale (axis.scale,axis.scale.high), 0);
	for (real minor = axis.scale.low; 
	     minor <= axis.scale.high; 
	     minor += axis.minor)
	{
	    if ((minor - axis.scale.low) % axis.major != 0)
	    {
		move_to (cr, scale (axis.scale, minor), 0);
		rel_line_to (cr, 0, 5);
	    }
	}
	for (real major = axis.scale.low; major <= axis.scale.high; major += axis.major)
	{
	    move_to (cr, scale (axis.scale, major), 0);
	    rel_line_to (cr, 0, 10);
	}
	stroke (cr);
        font_extents_t  f = font_extents (cr);
	printf ("font extents: %v\n", f);
	for (real major = axis.scale.low; major <= axis.scale.high; major += axis.major)
	{
	    string	    text = sprintf ("%g", major);
	    text_extents_t  e = text_extents (cr, text);
	    
	    move_to (cr, scale (axis.scale, major) - e.x_advance / 2, 
		     -abs(f.height) * 1.2);
	    show_text (cr, text);
	}
    }

    public void axes_draw (cairo_t cr, graph_t g)
    {
	save (cr);
	axis_draw (cr, g.bottom);
	restore (cr);
	save (cr);
	set_font_matrix (cr, (matrix_t) {
	    xx = 1, yx = 0,
	    xy = 0, yy = -1,
	    x0 = 0, y0 = 0 });
	set_matrix (cr, Matrix::multiply ((matrix_t) { 
	    xx = 0, yx = 1,
	    xy = 1, yy = 0,
	    x0 = 0, y0 = 0 }, get_matrix (cr)));
				  
	axis_draw (cr, g.left);
	restore (cr);
    }
        
    public graph_t new (cairo_t cr) {
	set_font (cr, "sans-12");
	set_font_matrix (cr, (matrix_t) {
	    xx = 1, yx = 0,
	    xy = 0, yy = -1,
	    x0 = 0, y0 = 0 });
	translate (cr, 0, height(cr));
	Cairo::scale (cr, 1, -1);
	
	set_line_cap (cr, line_cap_t.SQUARE);
	translate (cr, width(cr) * .1, height(cr) * .1);
	return (graph_t) {
	    cr = cr,
	    left = { 
		scale = &(scale_t) {
		    kind = scale_kind_t.linear,
		    len = height(cr) * .8,
		    low = 0,
		    high = 10
		},
		major = 1,
		minor = 0.25
	    },
	    bottom = {
		scale = &(scale_t) {
		    kind = scale_kind_t.linear,
		    len = width(cr) * .8,
		    low = 0,
		    high = 10
		},
		major = 1,
		minor = 0.25
	    } 
	};
    }
    public void test ()
    {
	cairo_t cr = Cairo::new (500, 500);
	graph_t gr = new (cr);
	axes_draw (cr, gr);
    }
    
}

Graph::test ();
for (;;) sleep (1000);
