require 'sinatra/base'
require File.dirname(__FILE__) + '/config'
require File.dirname(__FILE__) + '/utils'
require File.dirname(__FILE__) + '/db_session'

module Taps
class Server < Sinatra::Default
	use Rack::Auth::Basic do |login, password|
		login == Taps::Config.login && password == Taps::Config.password
	end

	error do
		"Application error"
	end

	before do
		major, minor, patch = request.env['HTTP_TAPS_VERSION'].split('.') rescue []
		unless "#{major}.#{minor}" == Taps.compatible_version
			halt 417, "Taps v#{Taps.compatible_version}.x is required for this server"
		end
	end

	get '/' do
		"hello"
	end

	post '/sessions' do
		key = rand(9999999999).to_s
		database_url = Taps::Config.database_url || request.body.string

		DbSession.create(:key => key, :database_url => database_url, :started_at => Time.now, :last_access => Time.now)

		"/sessions/#{key}"
	end

	post '/sessions/:key/tables/:table' do
		session = DbSession.filter(:key => params[:key]).first
		halt 404 unless session

		gzip_data = request.body.read
		halt 412 unless Taps::Utils.valid_data?(gzip_data, request.env['HTTP_TAPS_CHECKSUM'])

		rows = Marshal.load(Taps::Utils.gunzip(gzip_data))

		db = session.connection
		table = db[params[:table].to_sym]
		table.multi_insert(rows[:header], rows[:data])

		"#{rows[:data].size}"
	end

	post '/sessions/:key/reset_sequences' do
		session = DbSession.filter(:key => params[:key]).first
		halt 404 unless session

		schema_app = File.dirname(__FILE__) + '/../../bin/schema'
		`#{schema_app} reset_db_sequences #{session.database_url}`
	end

	post '/sessions/:key/schema' do
		session = DbSession.filter(:key => params[:key]).first
		halt 404 unless session

		schema_data = request.body.read
		Taps::Utils.load_schema(session.database_url, schema_data)
	end

	post '/sessions/:key/indexes' do
		session = DbSession.filter(:key => params[:key]).first
		halt 404 unless session

		index_data = request.body.read
		Taps::Utils.load_indexes(session.database_url, index_data)
	end

	get '/sessions/:key/schema' do
		session = DbSession.filter(:key => params[:key]).first
		halt 404 unless session

		schema_app = File.dirname(__FILE__) + '/../../bin/schema'
		`#{schema_app} dump #{session.database_url}`
	end

	get '/sessions/:key/indexes' do
		session = DbSession.filter(:key => params[:key]).first
		halt 404 unless session

		schema_app = File.dirname(__FILE__) + '/../../bin/schema'
		`#{schema_app} indexes #{session.database_url}`
	end

	get '/sessions/:key/tables' do
		session = DbSession.filter(:key => params[:key]).first
		halt 404 unless session

		db = session.connection
		tables = db.tables

		tables_with_counts = tables.inject({}) do |accum, table|
			accum[table] = db[table].count
			accum
		end

		Marshal.dump(tables_with_counts)
	end

	get '/sessions/:key/tables/:table/:chunk' do
		session = DbSession.filter(:key => params[:key]).first
		halt 404 unless session

		chunk = params[:chunk].to_i
		chunk = 500 if chunk < 1

		offset = params[:offset].to_i
		offset = 0 if offset < 0

		db = session.connection
		table = db[params[:table].to_sym]
		columns = table.columns
		order = columns.include?(:id) ? :id : columns.first
		raw_data = Marshal.dump(Taps::Utils.format_data(table.order(order).limit(chunk, offset).all))
		gzip_data = Taps::Utils.gzip(raw_data)
		response['Taps-Checksum'] = Taps::Utils.checksum(gzip_data).to_s
		response['Content-Type'] = "application/octet-stream"
		gzip_data
	end

	delete '/sessions/:key' do
		session = DbSession.filter(:key => params[:key]).first
		halt 404 unless session

		session.disconnect
		session.destroy

		"ok"
	end

end
end