#!/usr/bin/perl
use strict;
use FindBin qw($Bin);
use lib $Bin;
use onserver;
use Tie::File;
use Cwd;

setup();

sub make_db {
    my($type) = @_;
    print "\nCreating $type SQL database for $sname...\n";
    open GETPWD, '-|', "/mit/scripts/sql/bin$scriptsdev/get-password";
    ($sqlhost, $sqluser, $sqlpass) = split(/\s/, <GETPWD>);
    close GETPWD;
    open SQLDB, '-|', "/mit/scripts/sql/bin$scriptsdev/get-next-database", "${addrlast}_${type}";
    $sqldb = <SQLDB>;
    close SQLDB;
    open SQLDB, '-|', "/mit/scripts/sql/bin$scriptsdev/create-database", $sqldb;
    $sqldb = <SQLDB>;
    close SQLDB;
    if($sqldb eq "") {
        print "\nERROR:\n";
        print "Your SQL account failed to create a SQL database.\n";
        print "You should log in at http://sql.mit.edu to check whether\n";
        print "your SQL account is at its database limit or its storage limit.\n";
        print "If you cannot determine the cause of the problem, please\n";
        print "feel free to contact sql\@mit.edu for assistance.\n";
        exit 1;
    }
    return $sqldb;
}

my $dev_db = make_db("development");
my $test_db = make_db("test");
my $prod_db = make_db("production");

my $cwd = getcwd;
system("rails", "new", $cwd ,"-d", "mysql");
my $appdir = `basename $cwd`;
chomp $appdir;

open APPLICATION_RB, "config/application.rb";
my $appclass;
while(<APPLICATION_RB>) {
    if (/module (\w+)\n/) {
	$appclass = $1;
	last;
    }
}
close APPLICATION_RB;
if (!$appclass) {
    die "Couldn't find application class name - plase email scripts\@mit.edu with the names of your locker and the application you tried to create. Sorry!";
}

open PUBLIC_HTACCESS, ">public/.htaccess";
print PUBLIC_HTACCESS <<EOF;
# General Apache options
Options +FollowSymLinks +ExecCGI

# If you don't want Rails to look in certain directories,
# use the following rewrite rules so that Apache won't rewrite certain requests
#
# Example:
#   RewriteCond %{REQUEST_URI} ^/notrails.*
#   RewriteRule .* - [L]

# Redirect all requests not available on the filesystem to Rails
# By default the cgi dispatcher is used which is very slow
#
# For better performance replace the dispatcher with the fastcgi one
#
# Example:
#   RewriteRule ^(.*)\$ dispatch.fcgi [QSA,L]
RewriteEngine On

# If your Rails application is accessed via an Alias directive,
# then you MUST also set the RewriteBase in this htaccess file.
#
# Example:
#   Alias /myrailsapp /path/to/myrailsapp/public
#   RewriteBase /myrailsapp

RewriteCond index.html -f
RewriteRule ^\$ index.html [QSA]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)\$ dispatch.fcgi/\$1 [QSA,L]

# In case Rails experiences terminal errors
# Instead of displaying this message you can supply a file here which will be rendered instead
#
# Example:
#   ErrorDocument 500 /500.html

EOF

open HTACCESS, ">.htaccess";
print HTACCESS <<EOF;
RewriteEngine On
RewriteRule ^(.*)\$ public/\$1 [QSA,L]

EOF

tie my @railsenv, 'Tie::File', 'config/environment.rb';
unshift @railsenv, "# ENV['RAILS_ENV'] ||= 'production'";
unshift @railsenv, "# Uncomment below to put Rails into production mode";
unshift @railsenv, "";
untie @railsenv;

tie my @railsdb, 'Tie::File', 'config/database.yml';
for (@railsdb) {
    s/username:.*$/username: $sqluser/;
    s/password:.*$/password: $sqlpass/;
    s/host:.*$/host: $sqlhost/;
    s/database:.*_development.*/database: $dev_db/;
    s/database:.*_test.*/database: $test_db/;
    s/database:.*_production.*/database: $prod_db/;
}
untie @railsdb;

tie my @railswelcome, 'Tie::File', 'public/index.html';
for (@railswelcome) {
    s/Create your database/Sync your database/;
    s/to create your database\..*/to create tables in your database.<\/p>/;
}
untie @railswelcome;

# set config.action_controller.asset_host for all environments,
# so urls to static assets are generated correctly
# regardless of how the app is accessed
my $rails_assethost = "  config.action_controller.asset_host = \"//$USER.scripts.mit.edu/$appdir/public\"";
my @environments = ('development', 'production', 'test');

for my $environment (@environments) {
    tie my @envfile, 'Tie::File', "config/environments/$environment.rb";
    my $i = 0;
    for (@envfile) {
	if (/^end$/) {
	    last;
	}
	++$i;
    }
    splice @envfile, $i, 1, ($rails_assethost, 'end');
    untie @envfile;
}


tie my @railsfcgi, 'Tie::File', 'public/dispatch.fcgi';
for (@railsfcgi) {
    s/^[^#]*RailsFCGIHandler/## Commented out by scripts.mit.edu autoinstaller\n## RailsFCGIHandler/;
}
untie @railsfcgi;
open RAILSFCGI, ">>public/dispatch.fcgi";
print RAILSFCGI "#!/usr/bin/ruby\n";
print RAILSFCGI <<EOF;
require File.join(File.dirname(__FILE__), '../config/environment')       
require 'rack'

## Added by scripts.mit.edu autoinstaller to reload when app code changes
Thread.abort_on_exception = true

# Strip public/dispatch.fcgi out of SCRIPT_NAME so Rails generates nicer URLs
class ScriptNameRewriter
  
  def initialize(app)
    \@app = app
  end

  def call(env)
    if env['SCRIPT_NAME'] =~ /dispatch\.fcgi/
      env['SCRIPT_NAME'].gsub!(/public\\/dispatch\.fcgi/,'')
    end
    \@app.call(env)
  end
end


t1 = Thread.new do
  dispatch_logger = Logger.new(File.join(Rails.root,'log/dispatcher.log'))

  begin
    Rack::Handler::FastCGI.run ScriptNameRewriter.new(Rack::URLMap.new("/" => ${appclass}::Application))
  rescue => e
   dispatch_logger.error(e)
   raise e
  end
end
t2 = Thread.new do
   # List of directories to watch for changes before reload.
   # You may want to also watch public or vendor, depending on your needs.
   Thread.current[:watched_dirs] = ['app', 'config', 'db', 'lib']

   # List of specific files to watch for changes.
   Thread.current[:watched_files] = ['public/dispatch.fcgi',
                                     'public/.htaccess']
   # Sample filter: /(\.rb|\.erb)\$/.  Default filter: watch all files
   Thread.current[:watched_extensions] = //
   # Iterations since last reload
   Thread.current[:iterations] = 0

   def modified(file)
     begin
       mtime = File.stat(file).mtime
     rescue
       false
     else
       if Thread.current[:iterations] == 0
         Thread.current[:modifications][file] = mtime
       end
       Thread.current[:modifications][file] != mtime
     end
   end

   # Don't symlink yourself into a loop.  Please.  Things will still work
   # (Linux limits your symlink depth) but you will be sad
   def modified_dir(dir)
     Dir.new(dir).each do |file|
       absfile = File.join(dir, file)
       if FileTest.directory? absfile
         next if file == '.' or file == '..'
         return true if modified_dir(absfile)
       else
         return true if Thread.current[:watched_extensions] =~ absfile &&
           modified(absfile)
       end
     end
     false
   end

   def reload
     Thread.current[:modifications] = {}
     Thread.current[:iterations] = 0
     # This is a kludge, but at the same time it works.
     # Will kill the current FCGI process so that it is reloaded
     # at next request.
     raise RuntimeError
   end

   Thread.current[:modifications] = {}
   # Wait until the modify time changes, then reload.
   while true
     dir_modified = Thread.current[:watched_dirs].inject(false) {|z, dir| z || modified_dir(File.join(File.dirname(__FILE__), '..', dir))}
     file_modified = Thread.current[:watched_files].inject(false) {|z, file| z || modified(File.join(File.dirname(__FILE__), '..', file))}
     reload if dir_modified || file_modified
     Thread.current[:iterations] += 1
     sleep 1
   end
end

t1.join
t2.join
## End of scripts.mit.edu autoinstaller additions
EOF
chmod 0755,'public/dispatch.fcgi';

# static-cat doesn't whitelist .txt files
chmod 0777, 'public/robots.txt'; 

# have to explicitly take a dependency on fcgi
# ruby1.9 means we need to take a dependency on minitest 
# for rails console to work
open GEMFILE, ">>Gemfile";
print GEMFILE "gem 'fcgi'\n";
print GEMFILE "gem 'minitest'\n";
close GEMFILE;

print "Your application is located in:\n";
print "  /mit/$USER/web_scripts/$addrend/\n";
print "To run programs like rake or rails generate, run\n";
print "  'ssh -k $USER\@scripts' and cd to the above directory.\n\n";
press_enter;

exit 0;
