require 'aws-sdk'
require 'active_support/all'
require 'openssl'

module JamRuby

  class S3Manager

    @@def_opts = { :expires => 3600 * 24, :secure => true } # 24 hours from now

    S3_PREFIX = 's3://'

    def initialize(aws_bucket, aws_key, aws_secret)
      @aws_bucket = aws_bucket
      @s3 = AWS::S3.new(:access_key_id => aws_key, :secret_access_key => aws_secret)
      @aws_key = aws_key
      @aws_secret = aws_secret
    end

    def s3_url(filename)
      "#{S3_PREFIX}#{@aws_bucket}/#{filename}"
    end

    def s3_url?(filename)
      filename.start_with? S3_PREFIX
    end

    def url(filename, options = @@def_opts)
      "http#{options[:secure] ? "s" : ""}://s3.amazonaws.com/#{@aws_bucket}/#{filename}"
    end

    # XXX: the client can not support HTTPS atm!!! AGH  Change the :url to => https://s3.jamkazam.com when client supports https
    # is_native_client check?
    def upload_sign(filename, content_md5, part_number, upload_id)
      hdt = http_date_time
      str_to_sign = "PUT\n#{content_md5}\n#{content_type}\n#{hdt}\n/#{@aws_bucket}/#{filename}?partNumber=#{part_number}&uploadId=#{upload_id}"
      signature = Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha1'), @aws_secret, str_to_sign)).chomp
      { :datetime => hdt,
        :md5 => content_md5,
        :url => "http://s3.amazonaws.com/#{@aws_bucket}/#{filename}?partNumber=#{part_number}&uploadId=#{upload_id}",
        :authorization => "AWS #{@aws_key}:#{signature}"
      }
    end

    def sign_url(key, options = @@def_opts, operation = :read)
      s3_bucket.objects[key].url_for(operation, options).to_s
    end

    def public_url(key, options = @@def_opts)
      s3_bucket.objects[key].public_url(options).to_s
    end

    def presigned_post(key, options = @@def_opts)
      s3_bucket.objects[key].presigned_post(options)
    end

    def multipart_upload_start(upload_filename)
      s3_bucket.objects[upload_filename].multipart_upload.id
    end

    def multipart_upload_complete(upload_filename, upload_id)
      s3_bucket.objects[upload_filename].multipart_uploads[upload_id].complete(:remote_parts)
    end

    def multipart_upload_abort(upload_filename, upload_id)
      s3_bucket.objects[upload_filename].multipart_uploads[upload_id].abort
    end

    def multiple_upload_find_part(upload_filename, upload_id, part)
      s3_bucket.objects[upload_filename].multipart_uploads[upload_id].parts[part]
    end

    def exists?(filename)
      s3_bucket.objects[filename].exists?
    end

    def delete(filename)
      s3_bucket.objects[filename].delete
    end

    def upload(key, filename, options={})
      options[:file] = filename
      s3_bucket.objects[key].write(options)
    end

    def cached_upload(key, filename, options={})
      options[:file] = filename
      options.merge({expires: 5.years.from_now})
      s3_bucket.objects[key].write(filename,  options)
    end

    def delete_folder(folder)
      s3_bucket.objects.with_prefix(folder).delete_all
    end

    def download(key, filename)
      File.open(filename, "wb") do |f|
        s3_bucket.objects[key].read do |data|
          f.write(data)
        end
      end
    end

    def read_all(key)
      s = StringIO.new
      s3_bucket.objects[key].read do |data|
        s.write(data)
      end
      s.string
    end

    def list_files(prefix)
      tree = s3_bucket.as_tree(prefix: prefix)
      tree.children.select(&:leaf?).collect(&:key)
    end

    def list_directories(prefix = nil)
      tree = s3_bucket.as_tree(prefix: prefix)
      tree.children.select(&:branch?).collect(&:prefix)
    end

    def exists?(filename)
      s3_bucket.objects[filename].exists?
    end

    def object(filename)
      s3_bucket.objects[filename]
    end

    def length(filename)
      s3_bucket.objects[filename].content_length
    end

    private
    
    def s3_bucket
      @s3.buckets[@aws_bucket]
    end

    def content_type
      "audio/ogg"
    end

    def http_date_time
      Time.now.strftime("%a, %d %b %Y %H:%M:%S %z")
    end


  end
end