use FindBin;
use lib "$FindBin::Bin/../lib";

my $classname = shift;
die "no calssname given!\n" unless $classname;

#create pmc file with autogen.pl
#this is *nix specific, and you might not
#even want this program to create a .pmc file
#comment this out if you don't want it, and 
#if enough people agree, this can come out all together

`perl genclass.pl $classname  > @{[lc ${classname}]}.pmc`;


#add enum entry in pmc.h

open PMC_H, "$FindBin::Bin/../include/parrot/pmc.h" or die;

for (<PMC_H>) {
    if (/enum_class_max\s*=/) {
        push @file, "    enum_class_${classname},\n";
        push @file, $_;
    }
    else {
        push @file, $_;
        $count++ if /enum_class_(?!max)/;
    }
}

open PMC_H, ">$FindBin::Bin/../include/parrot/pmc.h" or die;
print PMC_H @file;
close PMC_H;
undef @file;
#add prototype definition in global_setup.h

open GSU_H,"$FindBin::Bin/../include/parrot/global_setup.h" or die;
for (<GSU_H>) {
    if (/init_world\(void\)/) {
        pop @file; #get rid of newline
        push @file, "void Parrot_${classname}_class_init(INTVAL);\n\n";
        push @file, $_;
    }
    else {
        push @file, $_;
    }
}

open GSU_H, ">$FindBin::Bin/../include/parrot/global_setup.h";
print GSU_H @file;
close GSU_H;
undef @file;

#add function call and vtable setup global_setup.c

open GSU_C, "$FindBin::Bin/../global_setup.c";
for (<GSU_C>) {
    if (/Parrot_([^_]+)_class_init\(enum_class_\1\)\;/) {
        $temp = 1;
        push @file,$_;
    }
    elsif ($temp) {
        push @file, "    Parrot_${classname}_class_init(enum_class_${classname});\n";
        $temp = 0;
    }
    elsif (/, enum_class_$1\)\;/) {
        push @file, $_;
        push @file, "\n\n    MAKE_KEY_STRING(key, Parrot_base_vtables[enum_class_${classname}].na\
me(NULL,NULL));\n";
        push @file, "    Parrot_base_classname_hash->vtable->set_integer_keyed(NULL, Parrot_base_\
classname_hash, &key, enum_class_${classname});\n";
    }
    else {
        push @file, $_;
    }
}

open GSU_C, ">$FindBin::Bin/../global_setup.c";
print GSU_C @file;
close GSU_C;
undef @file;

#add to Makefile
open MAKE, "$FindBin::Bin/../Makefile";
for (<MAKE>) {
    if (/CLASS_O_FILES\s*=/) {
        chop;
        $_ .= " classes/@{[lc $classname]}\$(O)\n";
        push @file,$_;
    }
    else {
        push @file, $_;
    }
}

open MAKE, ">$FindBin::Bin/../Makefile";
print MAKE @file;
close MAKE;
undef @file;

#add to classes/Makefile

open MAKE, "$FindBin::Bin/../classes/Makefile";
for (<MAKE>) {
    if (/O_FILES\s*=/) {
        chop;
        $_ .= " @{[lc $classname]}\$(O)\n";
        push @file, $_;
    }
    elsif (/clean:/) {
        pop @file; #get rid of newline
        push @file, <<EOT;
@{[lc $classname]}.c @{[lc $classname]}.h: default.pmc @{[lc $classname]}.pmc
\t\$(PMC2C) @{[lc $classname]}.pmc\n\n@{[lc $classname]}\$(O): \$(H_FILES)

EOT
        push @file,$_;
    }
    else {
        push @file, $_;
    }
}

open MAKE, ">$FindBin::Bin/../classes/Makefile";
print MAKE @file;
close MAKE;
undef @file;

#add to assemble.pl


open ASM,"$FindBin::Bin/../assemble.pl";
for (<ASM>) {
    if (/\$self->{constants}{\w+}\s*=/) {
      $temp = 1;
      push @file,$_;
    }
    elsif ($temp) {
        push @file, "  \$self->{constants}{$classname} = $count;\n";
        push @file, $_;
        $temp = 0;
    }
    else {
        push @file, $_;
    }
}

open ASM,">$FindBin::Bin/../assemble.pl";
print ASM @file;
close ASM;
undef @file;

print "\nAdded $classname succesfully\n";