require 'rbbt/rest/common/locate'
require 'rbbt/rest/common/resources'
require 'rbbt/rest/common/users'
require 'rbbt/rest/common/misc'
require 'ruby-prof'

require 'sinatra/base'
require 'sinatra/cross_origin'
require "sinatra/multi_route"
require "sinatra/cookies"
require 'sinatra/streaming'
require 'json'

require 'nakayoshi_fork'

module Sinatra
  module RbbtRESTMain

    def self.add_resource_path(path, priority_templates = false)
      Log.low "Adding resource path: #{Misc.fingerprint path}"
      KnowledgeBaseRESTHelpers.association_resources.unshift path

      if priority_templates
        EntityRESTHelpers.entity_resources.unshift path if defined? EntityRESTHelpers
        RbbtRESTHelpers.template_resources.unshift path 
      else
        EntityRESTHelpers.entity_resources.push path if defined? EntityRESTHelpers
        RbbtRESTHelpers.template_resources.push path 
      end

      RbbtRESTHelpers.add_sass_load_path path.compass if path.compass.exists?

      RbbtRESTHelpers.javascript_resources.unshift path.public.js if path.public.js.exists? 
      RbbtRESTHelpers.css_resources.unshift path.public.css if path.public.css.exists? 
      RbbtRESTHelpers.javascript_resources.unshift path.public.plugins if path.public.plugins.exists? 
      RbbtRESTHelpers.css_resources.unshift path.public.plugins if path.public.plugins.exists? 
      RbbtRESTHelpers.sass_resources.unshift path.compass if path.compass.exists?
    end

    def add_sass_load_path(path)
      path = path.find if Path === path
      Sass::Engine::DEFAULT_OPTIONS[:load_paths].unshift path if File.exists? path
    end

    def self.registered(base)
      base.module_eval do
        register Sinatra::MultiRoute

        helpers RbbtRESTHelpers
        register Sinatra::RbbtAuth
        helpers Sinatra::Cookies
        helpers Sinatra::Streaming

        add_sass_load_path Rbbt.share.views.compass.find(:lib)

        set :public_folder, Rbbt.share.views.public.find 

        set :environment, ENV["RACK_ENV"].to_sym if ENV["RACK_ENV"]

        attr_accessor :ajax, :layout, :format, :size, :update, :cache_type, :_, :profile


        enable :cross_origin
        set :allow_origin, :any
        set :allow_methods, [:get, :post, :options]
        set :allow_credentials, true
        set :max_age, "1728000"
        set :allow_headers, ['URI']

        if production?
          set :haml, { :ugly => true }
          set :clean_trace, true
          set :static_cache_control , [:public, {:max_age => 360_000}]
        else
          set :static_cache_control , [:public, {:max_age => 0}]
        end

        before do
          method = request.request_method
          method_color = case method
                         when "GET"
                           :cyan
                         when "POST"
                           :yellow
                         end

          Log.medium{ "#{Log.color method_color, method} #{Log.color(:blue, request.ip)}: " << request.path_info.gsub('/', Log.color(:blue, "/")) << ". Params: " << Log.color(:blue, Misc.fingerprint(params))}
          process_common_parameters

          headers 'Access-Control-Allow-Origin' => '*'

          if profile
            RubyProf.start 
          end
        end

        after do
          method = request.request_method

          method_color = case method
                         when "GET"
                           :cyan
                         when "POST"
                           :green
                         end

          status = response.status.to_s
          case status.to_i
          when 200
            color = :green
          when 202
            color = :yellow
          when 404,500
            color = :red
          else
            color = nil
          end
          Log.medium{ "#{Log.color method_color, method} #{Log.color :blue, request.ip}: " << request.path_info.gsub('/', Log.color(:blue, "/")) << ". Status: " << Log.color(color, status) }

          if profile
            result = RubyProf.stop
            printer = RubyProf::MultiPrinter.new(result)
            dir = TmpFile.tmp_file
            dir = settings.file_dir
            FileUtils.mkdir_p dir unless File.exists? dir
            printer.print(:path => dir, :profile => 'profile')
            Log.info{ "Profile saved at #{ dir }: #{request.env["REQUEST_URI"]}" }
          end

          response.header["URI"] = request.env["REQUEST_URI"]
        end

        add_sass_load_path Rbbt.views.compass.find

        get '/robots.txt' do
          send_file locate_file('public/robots.txt')
        end

        get '/files/:filename' do
          cache_control :public, :max_age => 360000 if production?
          file = settings.file_dir[params[:filename]].find
          send_file file
        end

        get %r{/js-find/(.*)(.js)?} do
          name = consume_parameter(:captures).first

          script_file = locate_javascript(name)

          content_type 'text/javascript', :charset => 'utf-8' if script_file =~ /\.js$/
          cache_control :public, :max_age => 360000 if production?
          send_file script_file
        end

        get %r{/css-find/(.*)(.css)?} do
          name = consume_parameter(:captures).first

          script_file = locate_css(name)

          content_type 'text/css', :charset => 'utf-8' if script_file =~ /\.js$/
          cache_control :public, :max_age => 360000 if production?
          send_file script_file
        end


        get '/stylesheets/*' do
          name = consume_parameter :splat

          file = locate_sass((name*"/").sub(/.css$/,''))

          content_type 'text/css', :charset => 'utf-8'
          cache_control :public, :max_age => 360000 if production?

          cache("css: #{File.basename(file)}", :_template_file => file, :_send_file => true, :cache_type => production? ? :synchronous : :none) do
            Log.debug{ "Rendering stylesheet: #{ file }" }
            render_sass(file)
          end
        end

        get '/' do
          template_render('main', params, 'main', :cache_type => :asynchronous)
        end

        get '/main/*' do |file|
          template = File.join 'main', file
          name = template.gsub(/\//,' - ')
          template_render(template, params, name, :cache_type => :asynchronous)
        end

        get '/help/?:section?' do
          if params[:section]
            section = params[:section]
            template_render('help/' << section, params, section, :cache_type => :asynchronous)
          else
            template_render('help', params, 'help', :cache_type => :asynchronous)
          end
        end

        get '/permalink/:id' do
          content_type "text/html"
          layout_file = locate_template('layout')
          Haml::Engine.new(Open.read(layout_file), :filename => layout_file).render(self) do
            settings.permalink_dir[params[:id]].read
          end
        end

        error RbbtRESTHelpers::TemplateMissing do |e|
          halt 404, e.message
        end

        error RemoteServerError do |e|
          raise e unless @format == :html

          content_type "text"
          halt 503, [e.class.to_s, e.message] * " => " << "\n\n" << (e.backtrace * "\n").gsub('`',"'")
        end

        error Exception do |e|
          raise e unless @format == :html

          content_type "text"
          halt 500, [e.class.to_s, e.message] * " => " << "\n\n" << (e.backtrace * "\n").gsub('`',"'")
        end

        get '/fonts/*' do
          filename = params[:splat].first
          file = File.join(settings.public_folder, 'fonts', filename)
          send_file file
        end

        get '/opt/*' do
          filename = params[:splat].first
          file = locate_file(Path.setup('public/opt')[filename])
          send_file file.find
        end

        get '/images/*' do
          filename = params[:splat].first
          file = locate_file(Path.setup('public/images')[filename])
          send_file file.find
        end

        get '/file/*' do
          filename = params[:splat].first
          file = locate_file(Path.setup('public')[filename])
          send_file file.find
        end

        require 'rbbt/rest/monitor'

        register Sinatra::RbbtRESTMonitor
      end
    end

  end
end