#!/bin/perl
#-------------------------------------------------------------------------------
# liest eine DDL aus $1 und schreibt ein POJO (DO) nach $2
#
# Parameter:
# $1: Inputdatei mit CREATE Statement
# $2: Outputdatei mit POJO
#
# Es werden folgende Regeln angewendet:
# 1) führende Kleinbuchstanben werden als Präfixe interpretiert
# 2) folgende Präfixe werden berücksichtig:
#    - id: technischer Schlüssel der Entität
#    - fi: Fremdschlüssel
#    - ds: String-Attribut
#    - dd: Datums-Attribut
#    - df: float-Attribut
#    - db: boolean-Attribut
#    - di: integer-Attribut
#-------------------------------------------------------------------------------

use strict;

###########################################################
sub processDDL
###########################################################
# liest die DDL-Datei ein und ruft für jede
# Nicht-Kommentar-Zeile die Bearbeitung auf
{
    # Parameter
    my( $FileName ) = @_;

    # lokale Variablen
    my $DdlLine = "";

    open (DDL_FILE, "$FileName") || die "Datei $FileName nicht gefunden \n";

    foreach $DdlLine ( <DDL_FILE> )
    {
        # discard blanks
        chomp( $DdlLine );
        $DdlLine =~ s/^ *//;

        # skip comment
        if (    $DdlLine =~ /^#/
             or $DdlLine =~ /^--/ )
        {
            ; #do nothing
        } else {
            # bearbeite Zeile
            workLine( $DdlLine );
        }
    }
}

###########################################################
sub workLine
###########################################################
# bearbeitung einer Zeile aus der DDL-Datei
# Achtung: Prozedur ist zustandsbehaftet!
{
    # Parameter
    my( $line ) = @_;

    # Globale Variable
    our $State;

    #print( "$State : $line\n" );

    if ($State eq "START")
    {
        if ( $line =~ "^CREATE TABLE" )
        {
            $State = "CREATE";
            #print( "State = $State\n" );
        }
    }
    elsif ( $State eq "CREATE" )
    {
        if ( $line =~ "^CONSTRAINT" )
        {
            $State = "START";
            #print( "State = $State\n" );
        }
        else
        {
            $line =~ s/\s*\[//;
            $line =~ s/\].*//;
            print( "Attribut = $line\n" );
            processAttribute( $line );
        }
    }
}

###########################################################
sub processAttribute
###########################################################
# bearbeitet ein Attribut
#    - id: technischer Schlüssel der Entität
#    - fi: Fremdschlüssel
#    - ds: String-Attribut
#    - dd: Datums-Attribut
#    - df: float-Attribut
#    - db: boolean-Attribut
#    - di: integer-Attribut
{
    # Parameter
    my( $attr ) = @_;

    # lokale Variablen
    my $attType = "";
    my $attName = "";

    if ( $attr =~ /^id/ )
    {
        # technischer Schlüssel der Entität
        # wird automatisch generiert.
        ;
    }
    elsif ( $attr =~ /^fi/ )
    {
        # Fremdschlüssel
        $attType = $attr;
        $attType =~ s/^fi//;
        $attName = $attType;
        $attName = lc( $attType );
        print OUT_FILE <<FREMDSCHLUSSEL;
    /** $attType */
    private $attType $attName;
    public $attType get$attType(){
    	return this.$attName;
    }
    public void set$attType($attType $attName){
    	this.$attName = $attName;
    }

FREMDSCHLUSSEL
		our $package;
        print XML_FILE <<XMLFREMDSCHLUSSEL;
		<many-to-one name="$attName" column="$attr" class="$package.$attType" fetch="join"
			not-null="true" />
XMLFREMDSCHLUSSEL
    }
    elsif ( $attr =~ /^ds/ )
    {
        # Stringattribut
        $attType = $attr;
        $attType =~ s/^ds//;
        $attName = lc( $attType );
        print OUT_FILE <<STRING;
    /** $attType */
    private String $attName;
    public String get$attType(){
    	return this.$attName;
    }
    public void set$attType(String $attName){
    	this.$attName = $attName;
    }

STRING
        print XML_FILE <<XMLSTRING;
		<property name="$attName" column="$attr" type="java.lang.String" not-null="true" />
XMLSTRING
    }
    elsif ( $attr =~ /^dd/ )
    {
        # Datumsattribut
        $attType = $attr;
        $attType =~ s/^dd//;
        $attName = lc( $attType );
        print OUT_FILE <<DATUM;
    /** $attType */
    private Date $attName;
    public Date get$attType(){
    	return this.$attName;
    }
    public void set$attType(Date $attName){
    	this.$attName = $attName;
    }

DATUM
        print XML_FILE <<XMLDATUM;
		<property name="$attName" column="$attr" type="java.lang.Date" not-null="true" />
XMLDATUM
    }
    else {
    	print( "$attr cannot be mapped\n" );
    }
}

###########################################################
sub schreibeRumpf
###########################################################
# schreibt den Dateirumpf
{
    # Parameter
    my( $Class ) = @_;

    print OUT_FILE <<RUMPF;
package company;

import java.io.Serializable;

public class $Class implements Serializable {

	/** ID for serialisation */
	private static final long serialVersionUID = 1L;

    /** identifier field */
    private Long oid;
    public Long getOid() {
       return this.oid;
    }
    public void setOid(Long oid) {
       this.oid = oid;
    }

    /** version number for optimistic locking */
    private Integer version;
    public Integer getVersion() {
        return this.version;
     }
     public void setVersion(Integer version) {
        this.version = version;
     }

RUMPF
	our $package;
    print XML_FILE <<XMLRUMPF;
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="$package">
	<class name="$Class" table="tkey$Class">

		<id name="id" type="java.lang.Long" column="ID">
			<generator class="native" />
		</id>

		<version name="version" column="VERSION"/>

XMLRUMPF
}

###########################################################
# main
###########################################################
# globale Variablen
# Deklaration des Status der Subroutine
our $State = "START";

# lokale Variablen
my $class = "";

print( ">dd2DO\n" );

# Parameter-check
if (!$ARGV[0])
{
    die "usage: ddl2DO.pl DDL-File"
}

# Ermittlung des Klassennamen
$class = $ARGV[0];
$class =~ s/\..*//;
our $package = "uid.company";
print( "bearbeite $class\n" );

# öffne OUT-Datei
open (OUT_FILE, ">$class.java") || die "Datei $class.java kann nicht geöffnet werden \n";
open (XML_FILE, ">$class.hbm.xml") || die "Datei $class.hbm.xml kann nicht geöffnet werden \n";

# Rumpf der Java-Datei
schreibeRumpf( $class );

processDDL($ARGV[0]);

# close file
print OUT_FILE "}\n";
close OUT_FILE;
print XML_FILE "    </class>\n</hibernate-mapping>\n";
close XML_FILE;
