package Graph::Layout::Aesthetic::Include;
use 5.006001;
use strict;
use warnings;
use Carp;
use File::Path qw(mkpath);

our $VERSION = '0.01';
our %includes;

sub list {
    return keys %includes;
}

sub write_file {
    my $file = shift;
    exists $includes{$file} || croak "Include file $file is unknown";
    croak "$file is absolute" if $file =~ m!\A/!;
    my $dir = $file;
    $dir =~ s!/*[^/]*\z!!;
    mkpath($dir) if $dir ne "";
    my $work = $file;
    $work =~ s/\.\w+\z|\z/.tmp/;
    {
        open(my $ofh, ">", $work) || croak "Could not create $work: $!";
        eval {
            local $\;
            print($ofh $includes{$file}) || croak "Error writing to $work: $!";
            close($ofh) || croak "Error closing $work: $!";
            rename($work, $file) ||
                croak "Could not rename $work to $file: $!";
        };
    }
    if ($@) {
        unlink($work) || croak "Could not unlink $work: $! after $@";
        croak $@;
    }
}

sub write_files {
    write_file($_) for keys %includes;
}

%includes = (
	# START GEN_INCLUDE
	# Section autogenerated using gen_include on Mon Sep 27 19:58:31 2004
	'include/aesth.h' => <<'GEN_INCLUDE',
/* declarations for aesths */
/* $Id: aesth.h,v 1.1 1993/05/26 23:22:27 coleman Exp $ */

#if !aesth_h
#define aesth_h 1

#include "aglo.h"
#include "defines.h"
#include "point.h"

#define declare_aesth(AESTHETIC_NAME) \
	aglo_aesth_gradient_fx ae_##AESTHETIC_NAME; \
	aglo_aesth_setup_fx ae_setup_##AESTHETIC_NAME;
	

#define define_aesth(AESTHETIC_NAME) \
	void ae_##AESTHETIC_NAME(aglo_state state,		\
				 aglo_gradient gradient,	\
                                 void *private)

#define define_setup(AESTHETIC_NAME) \
	void *ae_setup_##AESTHETIC_NAME(SV *force_sv,			\
					SV *state_sv,			\
					aglo_state state)

#define define_cleanup(AESTHETIC_NAME) \
	void ae_cleanup_##AESTHETIC_NAME(aglo_state state, void *private)

#define PRIVATE	((struct private *) private)

#endif
GEN_INCLUDE
	'include/aglo.h' => <<'GEN_INCLUDE',
#if !aglo_h
#define aglo_h 1

typedef UV aglo_unsigned;
typedef IV aglo_signed;
typedef double aglo_real;

typedef enum aglo_boolean { 
    false=0, 
    true=!false
} aglo_boolean;

typedef aglo_unsigned aglo_vertex;

typedef struct aglo_edge_record {
    aglo_vertex	 tail;		/* edge: head -> tail */
    aglo_boolean forward;	/* not tail -> head */
    struct aglo_edge_record *next;
} *aglo_edge_record;

typedef struct aglo_graph {
    aglo_boolean	done;
    aglo_vertex		vertices;
    aglo_signed		level_sequence;	/* abused as a boolean currently, 
                                           later drop finish test and do a real
                                           sequence number check */
    aglo_vertex		nr_levels;
    aglo_signed	       *at_level;
    aglo_vertex	       *level_sorted_vertex;
    aglo_vertex       **level2nodes;
    aglo_edge_record	edge_table[1];
} *aglo_graph;

typedef aglo_real  *aglo_point;
typedef const aglo_real *aglo_const_point;
typedef aglo_real *aglo_gradient;

typedef struct aglo_state {
    aglo_graph graph;		/* Topology */
    SV *graph_sv;		/* perl object reference for graph */
    struct use_force *forces;
    aglo_real		temperature;
    aglo_real		end_temperature;
    aglo_unsigned	iterations;
    aglo_unsigned	dimensions;	/* e.g. 2 means 2-dimensional space */
    aglo_signed		sequence;	/* bumped when state changed */
    aglo_signed		centroid_sequence;
    aglo_gradient	gradient, force_gradient;
    aglo_boolean	paused;
    aglo_point cached_centroid;
    aglo_point point[1];	/* State vector */
} *aglo_state;

typedef void aglo_aesth_gradient_fx(aglo_state state,
                                    aglo_gradient gradient, void *private);
typedef aglo_aesth_gradient_fx *aglo_aesth_gradient;
typedef void *aglo_aesth_setup_fx(SV *force_sv, SV *state_sv, 
                                  aglo_state state);
typedef aglo_aesth_setup_fx *aglo_aesth_setup;
typedef void aglo_aesth_cleanup_fx(aglo_state state, 
                                   void *private);
typedef aglo_aesth_cleanup_fx *aglo_aesth_cleanup;

typedef struct aglo_force {
    aglo_aesth_gradient	aesth_gradient;
    aglo_aesth_setup	aesth_setup;
    aglo_aesth_cleanup	aesth_cleanup;
    void	       *private_data;
    void	       *user_data;
} *aglo_force;

typedef struct use_force {
    aglo_real		weight;
    aglo_force		force;
    SV		       *force_sv;
    void               *private;
    struct use_force    *next;
} *use_force;

extern void aglo_frame_coordinates(aglo_state state,
                                   aglo_point min_frame, 
                                   aglo_point max_frame);
extern void aglo_iso_frame_coordinates(aglo_state state,
                                       aglo_point min_frame, 
                                       aglo_point max_frame);
extern void aglo_normalize_state(aglo_state state);
extern void aglo_randomize(pTHX_ aglo_state state, aglo_real size);
#endif
GEN_INCLUDE
	'include/at_centroid.h' => <<'GEN_INCLUDE',
/* attribute 'centroid' - centroid of current state */
/* $Id: at_centroid.h,v 1.1 1993/05/26 23:22:27 coleman Exp $ */

#if !at_centroid_h
#define at_centroid_h 1

#include "aglo.h"

aglo_const_point at_centroid(aglo_state state); 

#endif
GEN_INCLUDE
	'include/at_node_level.h' => <<'GEN_INCLUDE',
/* attribute 'node_level' - level of node (from root) */
/* $Id: at_node_level.h,v 1.1 1992/10/29 04:35:01 coleman Exp $ */

#if !at_node_level_h
#define at_node_level_h 1

#include "aglo.h"

void at_setup_node_level(aglo_graph graph);

#endif
GEN_INCLUDE
	'include/at_sample.h' => <<'GEN_INCLUDE',
/* attribute 'sample' - doesn't do anything */
/* $Id: at_sample.h,v 1.1 1993/05/26 23:22:27 coleman Exp $ */

#if !at_sample_h
#define at_sample_h 1

#include <aglo.h>

/* Something like this should be at the top. */

void at_sample(aglo_graph graph);

#endif
GEN_INCLUDE
	'include/defines.h' => <<'GEN_INCLUDE',
/* generally useful macros and inlines */
/* $Id: defines.h,v 1.1 1993/05/26 23:22:27 coleman Exp $ */

#ifndef defines_h
#define defines_h

#ifdef NDEBUG
# define INLINE inline
#else
# define INLINE /* */
#endif

#define max(X,Y) ((X) < (Y) ? (Y) : (X))
#define min(X,Y) ((X) > (Y) ? (Y) : (X))

static INLINE aglo_real sqr(aglo_real d) {
	return d*d;
}

static INLINE double fmax(aglo_real d1, aglo_real d2) {
	return (d1 < d2) ? d2 : d1;
}

static INLINE aglo_real fmin(aglo_real d1, aglo_real d2) {
	return (d1 > d2) ? d2 : d1;
}

#endif
GEN_INCLUDE
	'include/point.h' => <<'GEN_INCLUDE',
/* point manipulation routines */
/* $Id: point.h,v 1.1 1993/05/26 23:22:27 coleman Exp $ */

#ifndef point_h
#define point_h

#include "aglo.h"

void aglo_point_add(aglo_unsigned d, aglo_point result, aglo_const_point arg1, aglo_const_point arg2);
void aglo_point_sub(aglo_unsigned d, aglo_point result, aglo_const_point arg1, aglo_const_point arg2);
void aglo_point_inc(aglo_unsigned d, aglo_point result, aglo_const_point arg);
void aglo_point_dec(aglo_unsigned d, aglo_point result, aglo_const_point arg);
aglo_real aglo_point_mag(aglo_unsigned d,  aglo_const_point arg);
aglo_real aglo_point_mag2(aglo_unsigned d, aglo_const_point arg);
void aglo_point_midpoint(aglo_unsigned d, aglo_point result, aglo_const_point arg1, aglo_const_point arg2);
void aglo_point_iso_frame(aglo_unsigned d, aglo_point min_iso_frame, aglo_point max_iso_frame,
                          aglo_const_point min_frame, aglo_const_point max_frame);
void aglo_point_scalar_mult(aglo_unsigned d, aglo_point result, aglo_real scalar_arg,
                            aglo_const_point point_arg);
aglo_real aglo_point_dot_product(aglo_unsigned d, 
                                 aglo_const_point arg1,
                                 aglo_const_point arg2);
void aglo_point_assign(aglo_unsigned d, aglo_point result, aglo_const_point arg);
void aglo_point_zero(aglo_unsigned d, aglo_point result);

#endif
GEN_INCLUDE
	'typemap' => <<'GEN_INCLUDE',
TYPEMAP
aglo_graph		T_PTROBJ_TOPOLOGY
aglo_state		T_PTROBJ_GRAPH
aglo_force		T_PTROBJ_FORCE
aglo_real		T_DOUBLE
aglo_boolean		T_BOOL
aglo_unsigned		T_UV
aglo_vertex		T_UV
aglo_signed		T_IV

INPUT
T_PTROBJ_TOPOLOGY
        if (!SvOK($arg)) croak(\"$var is undefined\");
	if (sv_derived_from($arg, \"Graph::Layout::Aesthetic::Topology\")) {
	    IV tmp = SvIV((SV*)SvRV($arg));
	    $var = INT2PTR($type, tmp);
	} else croak(\"$var is not of type Graph::Layout::Aesthetic::Topology\")
T_PTROBJ_GRAPH
        if (!SvOK($arg)) croak(\"$var is undefined\");
	if (sv_derived_from($arg, \"Graph::Layout::Aesthetic\")) {
	    IV tmp = SvIV((SV*)SvRV($arg));
	    $var = INT2PTR($type, tmp);
	} else croak(\"$var is not of type Graph::Layout::Aesthetic\")
T_PTROBJ_FORCE
        if (!SvOK($arg)) croak(\"$var is undefined\");
	if (sv_derived_from($arg, \"Graph::Layout::Aesthetic::Force\")) {
	    IV tmp = SvIV((SV*)SvRV($arg));
	    $var = INT2PTR($type, tmp);
	} else croak(\"$var is not of type Graph::Layout::Aesthetic::Force\")

OUTPUT
T_PTROBJ_TOPOLOGY
	sv_setref_pv($arg, \"Graph::Layout::Aesthetic::Topology\", (void*)$var);
T_PTROBJ_GRAPH
	sv_setref_pv($arg, \"Graph::Layout::Aesthetic\", (void*)$var);
T_PTROBJ_FORCE
	sv_setref_pv($arg, \"Graph::Layout::Aesthetic::Force\", (void*)$var);
GEN_INCLUDE
	# STOP GEN_INCLUDE
);
1;
__END__

=head1 NAME

Graph::Layout::Aesthetic::Include - Include files that were used to build Graph::Layout::Aesthetic

=head1 SYNOPSIS

  # This module is normally used as base class for particular force modules:
  use Graph::Layout::Aesthetic::Includes;
  @list = Graph::Layout::Aesthetic::Include::list;
  Graph::Layout::Aesthetic::Include::write_file($name);
  Graph::Layout::Aesthetic::Include::write_files;

=head1 DESCRIPTION

This modules contains the include files and typemap that were used to compile
Graph::Layout::Aesthetic. It's not supposed to be used in user program, but
is meant for people writing new derived classes (in particualr new
L<Graph::Layout::Aesthetic::Force|Graph::Layout::Aesthetic::Force> classes).
These people will need to compile C-code and link with the existing libraries,
which means they should use the same assumptions about data structures as the
original code.

The files inside this module are put there by the gen_include program.

=head1 METHODS

=over

=item X<list>@list = Graph::Layout::Aesthetic::Include::list

Returns the list of all filenames available in this module. Filenames will
be relative, but may contain directory parts. A typical example would be
F<include/aglo.h>.

=item X<write_file>Graph::Layout::Aesthetic::Include::write_file($name)

Creates and writes the proper contents of the file $name relative to the
current directory. Any non-existing but needed subdirectories are created
first. $name must be one of the names returned by L<list|"list">. Throws
an exception in case of error.

=item X<write_files>Graph::Layout::Aesthetic::Include::write_files

Writes out all files available in this module. Basically equal to:

    Graph::Layout::Aesthetic::Include::write_file($_) for
        Graph::Layout::Aesthetic::Include::list;

=back

=head1 EXPORT

None by default.

=head1 SEE ALSO

L<Graph::Layout::Aesthetic>,
L<Graph::Layout::Aesthetic::Force>,

=head1 AUTHOR

Ton Hospel, E<lt>Graph::Layout::Aesthetic@ton.iguana.be<gt>

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2004 by Ton Hospel

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.6.1 or,
at your option, any later version of Perl 5 you may have available.

=cut
