require 'rails/generators'
require 'rails/generators/migration'

module Humdrum
  module Generators
    class ResourceGenerator < Rails::Generators::Base
      
      include Rails::Generators::Migration
      
      def self.next_migration_number(path)
        @migration_number = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i.to_s
      end
      
      source_root File.expand_path('../templates', __FILE__)
      
      desc "Generates a controller, view and route entries for CRUD operations of a resource"
      
      argument :resource_name, :type=>:string
      argument :fields, :type=>:hash, :banner =>"Resource Fields."
      
      class_option :fluid, :type => :boolean, :default => true, :desc => "Pass true to create fluid layouts"
      class_option :debug, :type => :boolean, :default => false, :desc => "This will print the arguments for debugging"
      
      def debug_args
        print_args if options.debug?
      end
      
      def generate_controllers
        template "controllers/resource_controller.rb", "app/controllers/#{controller_path}_controller.rb"
      end
      
      def generate_views
        template "views/resource/_edit.html.erb", "app/views/#{controller_path}/_edit.html.erb"
        template "views/resource/_filters.html.erb", "app/views/#{controller_path}/_filters.html.erb"
        template "views/resource/_form.html.erb", "app/views/#{controller_path}/_form.html.erb"
        template "views/resource/_index.html.erb", "app/views/#{controller_path}/_index.html.erb"
        template "views/resource/_item.html.erb", "app/views/#{controller_path}/_item.html.erb"
        template "views/resource/_nav_filters.html.erb", "app/views/#{controller_path}/_nav_filters.html.erb"
        template "views/resource/_new.html.erb", "app/views/#{controller_path}/_new.html.erb"
        template "views/resource/_show.html.erb", "app/views/#{controller_path}/_show.html.erb"
        template "views/resource/_summary.html.erb", "app/views/#{controller_path}/_summary.html.erb"
        template "views/resource/create.js.erb", "app/views/#{controller_path}/create.js.erb"
        template "views/resource/destroy.js.erb", "app/views/#{controller_path}/destroy.js.erb"
        template "views/resource/edit.js.erb", "app/views/#{controller_path}/edit.js.erb"
        template "views/resource/index.js.erb", "app/views/#{controller_path}/index.js.erb"
        template "views/resource/new.js.erb", "app/views/#{controller_path}/new.js.erb"
        template "views/resource/show.js.erb", "app/views/#{controller_path}/show.js.erb"
        template "views/resource/update.js.erb", "app/views/#{controller_path}/update.js.erb"
        template "views/resource/index.html.erb", "app/views/#{controller_path}/index.html.erb"
      end
      
      def generate_models
        template "models/resource.rb", "app/models/#{model_path}.rb"
      end
      
      def generate_migrations
        migration_template "migrations/create_resources.rb", "db/migrate/create_#{instances_name}"
      end
      
      def generate_routes
        words = name_phrases
        resource = words.pop
        route words.reverse.inject("resources :#{resource.pluralize}") { |acc, phrase|
          "namespace(:#{phrase}){ #{acc} }"
        }
      end
      
      def generate_locales
        template "config/locales/humdrum.en.yml", "config/locales/humdrum.en.yml"
      end
      
      private
      
      def print_args
        puts ":fields: #{fields}"
        puts ":form_link_param: #{form_link_param}"
        puts "name_phrases: #{name_phrases}"
        puts "controller_path: #{controller_path}"
        puts "controller_class: #{controller_class}"
        puts "model_path: #{model_path}"
        puts "model_class: #{model_class}"
        puts "instance_name: #{instance_name}"
        puts "instances_name: #{instances_name}"
        puts "table_name: #{table_name}"
        
        puts "index path: #{resource_link}"
        puts "show path: #{resource_link('show')}"
        puts "new path: #{resource_link('new')}"
        puts "edit path: #{resource_link('edit')}"
        puts "create path: #{resource_link('create')}"
        puts "update path: #{resource_link('update')}"
        puts "destroy path: #{resource_link('destroy')}"
        
        puts "index url: #{resource_link('index','url')}"
        puts "show url: #{resource_link('show','url')}"
        puts "new url: #{resource_link('new','url')}"
        puts "edit url: #{resource_link('edit','url')}"
        puts "create url: #{resource_link('create','url')}"
        puts "update url: #{resource_link('update','url')}"
        puts "destroy url: #{resource_link('destroy','url')}"
      end
      
      def name_phrases
        if resource_name.include?('::')
          resource_name.split("::")
        elsif resource_name.include?('/')
          resource_name.split("/")
        else
          [resource_name]
        end
      end
      
      def controller_path
        words = name_phrases
        resource = words.pop
        if words.any?
          words.collect(&:downcase).join("/") + "/#{resource.pluralize}"
        else
          "#{resource.pluralize}"
        end
      end
      
      def controller_class
        words = name_phrases
        resource = words.pop
        if words.any?
          words.collect(&:camelize).join("::") + "::#{resource.camelize.pluralize}Controller"
        else
          "#{resource.camelize.pluralize}Controller"
        end
      end
      
      def model_path
        name_phrases.last.downcase
      end
      
      def model_class
        name_phrases.last.camelize
      end
      
      def instance_name
        name_phrases.last.underscore
      end
      
      def instances_name
        instance_name.pluralize
      end
      
      def table_name
        instances_name
      end
      
      def resource_link(actn='index', ltype='path')
        map = {
          'index' => '',
          'show' => '',
          'edit' => 'edit_',
          'new' => 'new_',
          'update' => '',
          'create' => '',
          'destroy' => '',
        }
        words = name_phrases
        resource = words.pop
        if actn == "index"
          map[actn] + (words.any? ? words.join("_" + "_") : "") + resource.pluralize + "_" + ltype
        else
          map[actn] + (words.any? ? words.join("_") + "_" : "") + resource + "_" + ltype
        end
      end 
      
      def form_link_param
        words = name_phrases
        resource = words.pop
        if words.any?
          # to print like this [:admin, :user, :location, @chakka]
          # in form.html.erb
          "[" + (words.map{|x| ":" + x.downcase} << "@" + resource.downcase).join(", ") + "]"
        else
          "@#{resource.downcase}"
        end
      end
      
      def input_type(name, type)
        if name.include?("email") && type == "string"
          return "email"
        elsif name.include?("password") && type == "string"
          return "password"
        elsif (name.include?("phone") || name.include?("mobile")) && type == "string"
          return "tel"
        else
          case type
          when "string"
            "text"
          when "text"
            "textarea"
          when "integer"
            "number"
          when "references"
            "type"
          when "date"
            "date"
          when "datetime"
            "datetime-local"
          when "timestamp", "time"
            "time"
          end
        end
      end
      
      ## List of all the string fields 
      def string_fields
        main_field = main_string_field
        fields.map{|name, type| name if name != main_field && type == "string" }.uniq.compact
      end
      
      ## The main string field like 'name'
      def main_string_field
        fields.map{|name, type| name if name.include?("name") && type == "string"}.uniq.compact || fields.keys.any? ? fields.keys.first : "id"
      end
      
      ## Text Fields like description or summary
      def text_fields
        fields.map{|name, type| name if type == "text"}.uniq.compact
      end
    	
      def container_class
        options.fluid? ? "container-fluid" : "container"
      end
      
      def row_class
        options.fluid? ? "row-fluid" : "row"
      end
      
    end
  end
end