#!/usr/bin/perl -w
#The MIT License
#Copyright (c) 2007 Gonéri LE BOUDER 
#Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
# This script creates the models of a MySQL database for CakePHP 1.1
# The DB needs to respect the CakePHP convention
# http://manual.cakephp.org/appendix/conventions
my $dbhost = "127.0.0.1";
my $login = "root";
my $pw = "";
my $dbname = "databasename";
######################### 
use strict;
use DBI;
use Data::Dumper;

my $dbh = DBI->connect("DBI:mysql:database=$dbname;host=$dbhost", $login, $pw);

sub classNameFromtableName {
    my $tablename = shift;
    my $classname;
    foreach (split /_/,$tablename) {
	s/s$//;
	$classname .= ucfirst($_);
    }

    return $classname;
}

sub fileNameFromtableName {
    my $tablename = shift;
    my $filename = $tablename;

    $filename =~ s/(.*)s$/$1.php/;

    return $filename;
}

sub classNameFromIndexName {
    my $index = shift;
    my $classname;
    my $tmp = $index;
    $tmp =~ s/_id$//;
    foreach (split /_/,$tmp) {
	s/s$//;
	$classname .= ucfirst($_);
    }

    return $classname;
}

my $sth = $dbh->prepare("SHOW TABLES");
$sth->execute();
my %h;
while (my $ref = $sth->fetchrow_arrayref()) {
    $h{$ref->[0]}{hasMany} = {};
    $h{$ref->[0]}{hasOne} = {};
    $h{$ref->[0]}{belongsTo} = {};
}


foreach my $table (keys %h) {
    $sth = $dbh->prepare("SHOW CREATE TABLE $table");
    $sth->execute();
    while (my $ref = $sth->fetchrow_arrayref()) {
	foreach (split /\n/,$ref->[1]) {
	    if (/CONSTRAINT `\S+` FOREIGN KEY \(`(\S+)`\) REFERENCES `(\S+)`/) {
		my $foreign_key = $1;
		my $dest = $2;

		my $t = $foreign_key;
		$t =~ s/_id//;

		my $p = "(^$t"."_|_$t"."s\$)";
		my $islinkedonitself = 0;
		if ($table eq $dest) { # table linked on itself
		    $islinkedonitself = 1;
		    $t = $table 
		}
		
		if ($table =~ /$p/) { # linking table
		    $h{$table}{belongsTo}{$t} = { foreign_key => $foreign_key, dest => $dest, islinkedonitself => $islinkedonitself };
		    $h{$t.'s'}{hasMany}{$table} = { foreign_key => $foreign_key, dest => $dest, islinkedonitself => $islinkedonitself };
		} else { # hasMany

		    $h{$table}{belongsTo}{$dest} = { foreign_key => $foreign_key, dest => $dest, islinkedonitself => $islinkedonitself };
		    $h{$t.'s'}{hasMany}{$table} = { foreign_key => $foreign_key, dest => $dest, islinkedonitself => $islinkedonitself };
		}
	    }
	}
    }
}

foreach my $table (keys %h) {


    my $classname = classNameFromtableName($table);
    my $filename = fileNameFromtableName($table);


    if (-f $filename) {
	print STDERR "Please remove $filename first.\n";
	exit 1;
    }

    open FILE, ">$filename" or die;
    print "Writing $filename\n";

print FILE <<EOF;
<?
/**
 \@file $filename
  This file has been generated by cakephp_create_model.pl 
*/
class $classname extends AppModel {
    /*! \@class $classname 
     */
    var \$name = '$classname';
    var \$validate = array();

EOF

foreach my $relationType (qw/hasMany belongsTo hasOne/) {
    if (keys %{$h{$table}{$relationType}}) {
	my $t;
	print FILE "    var \$$relationType = array(";
	foreach (keys %{$h{$table}{$relationType}}) {
	    print FILE ", " if $t;
	    $t++;
	    my $relationName;
	    if ($h{$table}{$relationType}{$_}{islinkedonitself}) {
		$relationName = classNameFromIndexName($h{$table}{$relationType}{$_}{foreign_key});
		print FILE "'".$relationName."' => array('className' => '".classNameFromtableName($h{$table}{$relationType}{$_}{dest})."', 'foreignKey' => '".$h{$table}{$relationType}{$_}{foreign_key}."')";
	    } else {
		$relationName = classNameFromtableName($_);
		print FILE "'".$relationName."'";
	    }
	}
	print FILE ");\n";
    }
}


print FILE <<EOF;

}
?>
EOF
close FILE;

}
