#
#    Licensed to the Apache Software Foundation (ASF) under one or more
#    contributor license agreements.  See the NOTICE file distributed with
#    this work for additional information regarding copyright ownership.
#    The ASF licenses this file to You under the Apache License, Version 2.0
#    (the "License"); you may not use this file except in compliance with
#    the License.  You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS,
#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#    See the License for the specific language governing permissions and
#    limitations under the License.
#

SETTINGS = "#{File.expand_path('.buildr', ENV['HOME'])}/settings.rb"

module NativeDB
#
  if File.exist? SETTINGS
    require SETTINGS
    Java.classpath << REQUIRES
  end

  class << self

    def create_dbs(buildr, base, orm)
      if File.exist? SETTINGS
        require SETTINGS

        settings().each do |name, dbprops|
          if dbprops[:db] != "derby"
            buildr.build create_hib_db(name, "#{base}/target/#{name}"=>dbprops) if orm == :hib and dbprops[:dao].downcase.include? "hib"
            buildr.build create_jpa_db(base, name, "#{base}/target/#{name}"=>dbprops) if orm == :jpa and !dbprops[:dao].downcase.include? "hib"
          end
        end
      end
    end

    def create_hib_db(name, args)
      if File.exist? SETTINGS
        require SETTINGS
        db, dbprops = args.keys.first, args.values.first
        file(File.expand_path(db)) do |task|
          puts "Creating(preparing) database: #{db}."
          rm_rf task.name if File.exist?(task.name)
          Dir.mkdir(task.name)
          Buildr.ant(name) do |ant|
            create_tables_sql = "#{task.name}/ode_tables.sql"
            drop_tables_sql = "#{task.name}/drop_ode_tables.sql"
            ant.get :src=>"http://release.intalio.com/m2repo/ci-resources/ode-schema-5.2.x/package/#{dbprops[:db]}/ode_tables.sql",
                    :dest=> create_tables_sql
            sqls = prepare_sqls(task, ant, [], :hib, dbprops[:db], drop_tables_sql, create_tables_sql)

            # Apply the sql scripts to the database
            ant.sql :driver=>dbprops[:driver], :url=>dbprops[:url], :userid=>dbprops[:userid], :password=>dbprops[:password], :autocommit=>dbprops[:autocommit] do
              sqls.each { |sql| ant.transaction :src=>sql }
            end
            puts "Created(prepared) database: #{dbprops[:url]}."
          end
        end
      end
    end

    def create_jpa_db(base, name, args)
      if File.exist? SETTINGS
        require SETTINGS
        db, dbprops = args.keys.first, args.values.first
        file(File.expand_path(db)) do |task|
          puts "Creating(preparing) database: #{db}."
          rm_rf task.name if File.exist?(task.name)
          Dir.mkdir(task.name)
          Buildr.ant(name) do |ant|
            create_tables_sql = "#{base}/target/#{dbprops[:db]}.sql"
            drop_tables_sql = "#{task.name}/drop-#{dbprops[:db]}.sql"
            sqls = prepare_sqls(task, ant, [], :jpa, dbprops[:db], drop_tables_sql, create_tables_sql)

            # Apply the sql scripts to the database
            ant.sql :driver=>dbprops[:driver], :url=>dbprops[:url], :userid=>dbprops[:userid], :password=>dbprops[:password], :autocommit=>dbprops[:autocommit] do
              sqls.each { |sql| ant.transaction :src=>sql }
            end
            puts "Created(prepared) database: #{dbprops[:url]}."
          end
        end
      end
    end

    def prepare_configs(test, base)
      test.setup task("prepare_configs") do |task|
        if File.exist? SETTINGS
          require SETTINGS

          hibdbs = ""
          jpadbs = ""
          settings().each do |name, dbprops|
            dbs = (dbprops[:dao].downcase.include? "hib") ? hibdbs : jpadbs
            if dbprops[:db] == "derby"
              dbs <<= ", " if dbs.length > 0
              dbs <<= (dbs == jpadbs ? "<jpa>" : "<hib>")
            else
              test.with REQUIRES

              prepare_config(name, dbprops, "#{base}/target/conf.#{name}", "#{base}/src/test/webapp/WEB-INF/conf.template")
              dbs <<= ", " if dbs.length > 0
              dbs <<= "#{base}/target/conf.#{name}"
            end
          end
           test.options[:properties]["org.apache.ode.hibdbs"] = hibdbs
           test.options[:properties]["org.apache.ode.jpadbs"] =jpadbs
        end
      end
    end

    def prepare_config(name, dbprops, db, template)
      rm_rf db if File.exist?(db)
      Dir.mkdir(db)

      Buildr.ant(name) do |ant|
        ant.copy :todir=>db do
          ant.fileset :dir=>template
        end

        ant.replace :file=>"#{db}/ode-axis2.properties", :token=>"@connfactory@", :value=>dbprops[:dao]
        ant.replace :file=>"#{db}/ode-axis2.properties", :token=>"@driver@", :value=>dbprops[:driver]
        ant.replace :file=>"#{db}/ode-axis2.properties", :token=>"@url@", :value=>dbprops[:url]
        ant.replace :file=>"#{db}/ode-axis2.properties", :token=>"@userid@", :value=>dbprops[:userid]
        ant.replace :file=>"#{db}/ode-axis2.properties", :token=>"@password@", :value=>dbprops[:password]

        puts "Created config directory: #{db}."
      end
    end

    def prepare_sqls(task, ant, sql_files, orm, db, drop_tables_sql, create_tables_sql)
      # read the create table sql into a string
      create_tables = ""
      File.open(create_tables_sql, "r") do |f1|
        while line = f1.gets
          create_tables <<= line
        end
      end

      # create the drop table sql file from the create table sql
      if orm == :hib and db == "sqlserver"
        File.open(drop_tables_sql, "w") do |f2|
          create_tables.gsub(/CREATE TABLE (.*?)[\s\(].*?;/mi) { |match|
            f2.puts "IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE' AND TABLE_NAME='" << $1 << "') DROP TABLE " << $1 << ";\n"
          }
          # remove the 'go's in the sql
          f2.puts create_tables.gsub(/\ngo[\n$]/mi, "\n")
        end
        # add in the drop table sql file
        sql_files |= [drop_tables_sql]
      elsif orm == :jpa and db == "mysql"
        File.open(drop_tables_sql, "w") do |f2|
          create_tables.gsub(/CREATE TABLE (.*?)[\s\(].*?;/m) { |match|
            f2.puts "DROP TABLE IF EXISTS " << $1 << ";\n"
          }
        end
        # add in the drop table sql file
        sql_files |= [drop_tables_sql]
      end

      # add in the create table sql file
      if orm == :hib and db != "sqlserver"
        ant.copy :file=>create_tables_sql, :tofile=>"#{task.name}/#{db}.sql"
        sql_files |= ["#{task.name}/#{db}.sql"]
      elsif orm == :jpa
        ant.copy :file=>create_tables_sql, :tofile=>"#{task.name}/#{db}.sql"
        sql_files |= ["#{task.name}/#{db}.sql"]
      end

      sql_files
    end

  protected

    # This will download all the required artifacts before returning a classpath, and we want to do this only once.
    def requires()
      @requires ||= Buildr.artifacts(REQUIRES).each(&:invoke).map(&:to_s).join(File::PATH_SEPARATOR)
    end
  end
end
