#!/usr/bin/perl -w
#
# gen_class.pl, part of GObject
# Copyright (C) 2001 Joshua Nathaniel Pritikin
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General
# Public License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
# Boston, MA 02111-1307, USA.

use strict;

die "usage: gen_class.pl GtkWindow AppFormEntryScreen\n"
  if @ARGV < 2;

my ($super, $class) = @ARGV;

$super ||= 'GtkWindow';
$class ||= 'AppFormEntryScreen';

sub underscore {
  my @up = split /([A-Z])/, $_[0];
  shift @up;
  my @words;
  while (@up) {
    push @words, join('', splice @up,0,2);
  }
  join '_', @words;
}

sub columns {
  my @lines = @_;

  my @col;
  for my $l (@lines) {
    for (my $c=0; $c < @$l; $c++) {
      push @{ $col[$c] }, $l->[$c];
    }
  }

  my @width;
  for (my $c=0; $c < @col; $c++) {
    my $C = $col[$c];
    my $w = -1;
    for (@$C) {
      if ($w < length)
	{ $w = length; }
    }
    $width[$c] = $w;
  }

  for my $l (@lines) {
    for (my $c=0; $c < @$l; $c++) {
      print $l->[$c];
      print ' 'x($width[$c] - length($l->[$c]) + 2)
	if $c < @$l - 1;
    }
    print "\n";
  }
}

my $incl = lc "${class}.h";

my $usuper = lc underscore $super;
my $uclass = lc underscore $class;
my $Usuper = uc $usuper;
my $Uclass = uc $uclass;

my $ctype = $Uclass . "_TYPE";
my $isclass = "IS_" . $Uclass;

print "
#ifndef _${Uclass}_H_
#define _${Uclass}_H_
\n";

columns
  ["typedef struct _${class}Class", "${class}Class;"],
  ["typedef struct _$class", "$class;"];

print "\n";

columns
  ["#define ${ctype}", "(${uclass}_get_type(void))"],
  ["#define ${Uclass}(obj)", "(G_TYPE_CHECK_INSTANCE_CAST((obj), $ctype, $class))"],
  ["#define ${isclass}(obj)",	"(G_TYPE_CHECK_INSTANCE_TYPE((obj), $ctype))"],
  ["#define ${Uclass}_GET_CLASS(obj)", "(G_TYPE_INSTANCE_GET_CLASS((obj), $ctype, ${class}Class))"],
  ["#define ${Uclass}_CLASS(klass)", "(G_TYPE_CHECK_CLASS_CAST((klass), $ctype, ${class}Class))"],
  ["#define ${isclass}_CLASS(klass)", "(G_TYPE_CHECK_CLASS_TYPE((klass), $ctype))"];

print "
struct _${class}Class {
  ${super}Class parent_class;

  // signal implementations here
};

struct _${class} {
  $super parent_instance;

  // instance variables here
};

";

# prototypes
columns
  ["GType", "${uclass}_get_type", '(void);'],
  ["$class *", "${uclass}_new", "(void);"];

print "
#endif

";

print(('-'x20) . " snip snip snip " . ('-'x20) . "\n");

print "
#include \"$incl\"

enum {
  PROP_ZERO,

  // properties here
};

enum {
  // signals here

  LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };

$class *
${uclass}_new (void)
{ return ($class *) g_object_new (${ctype}, 0); }

static void
";

columns
  ["${uclass}_set_property", "(GObject *", "object,"],
  ['', ' guint', 'prop_id,'],
  ['', ' const GValue *', 'value,'],
  ['', ' GParamSpec *', 'pspec)'];

print "{
  $class *self = $Uclass (object);

  switch (prop_id) {
  // properties here

  default:
    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
    break;
  }
}

static void
";

columns
  ["${uclass}_set_property", "(GObject *", "object,"],
  ['', ' guint', 'prop_id,'],
  ['', ' const GValue *', 'value,'],
  ['', ' GParamSpec *', 'pspec)'];

print "{
  $class *self = $Uclass (object);

  switch (prop_id) {
  // properties here

  default:
    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
    break;
  }
}

static GObjectClass *parent_class;

static void
${uclass}_finalize (GObject *object)
{
  $class *self = $Uclass (object);

  // free memory

  (* G_OBJECT_CLASS (parent_class)->finalize) (object);
}

static void
${uclass}_class_init (${class}Class *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

  parent_class = g_type_class_peek_parent (klass);

  object_class->set_property = ${uclass}_set_property;
  object_class->get_property = ${uclass}_get_property;

  object_class->finalize = ${uclass}_finalize;

  // register properties & signals
}

GType ${uclass}_get_type (void)
{
  static GType our_type = 0;

  if (our_type == 0) {
    static const GTypeInfo our_info = {
";
my $i = ' 'x6;
columns
  ["$i", "sizeof(${class}Class),"],
  ["$i(GBaseInitFunc)", 'NULL,'],
  ["$i(GBaseFinalizeFunc)", 'NULL,'],
  ["$i(GClassInitFunc)", "${uclass}_class_init,"],
  ["$i/* class_finalize */", 'NULL,'],
  ["$i/* class_data */", 'NULL,'],
  ['', "sizeof ($class),"],
  ["$i/* n_preallocs */", '0,'],
  ["$i(GInstanceInitFunc)", "${uclass}_init,"];
print "${i}NULL
    };

    our_type = g_type_register_static ($Usuper,
				       \"$class\",
				       &our_info,
				       0);
  }
  return our_type;
}

";
