module Paperclip::Storage::Fog

def self.extended base

def self.extended base
  begin
    require 'fog'
  rescue LoadError => e
    e.message << " (You may need to install the fog gem)"
    raise e
  end unless defined?(Fog)
  base.instance_eval do
    unless @options[:url].to_s.match(/\A:fog.*url\Z/)
      @options[:path]  = @options[:path].gsub(/:url/, @options[:url]).gsub(/\A:rails_root\/public\/system\//, '')
      @options[:url]   = ':fog_public_url'
    end
    Paperclip.interpolates(:fog_public_url) do |attachment, style|
      attachment.public_url(style)
    end unless Paperclip::Interpolations.respond_to? :fog_public_url
  end
end

def connection

def connection
  @connection ||= ::Fog::Storage.new(fog_credentials)
end

def convert_time(time)

def convert_time(time)
  if time.is_a?(Fixnum)
    time = Time.now + time
  end
  time
end

def copy_to_local_file(style, local_dest_path)

def copy_to_local_file(style, local_dest_path)
  log("copying #{path(style)} to local file #{local_dest_path}")
  ::File.open(local_dest_path, 'wb') do |local_file|
    file = directory.files.get(path(style))
    return false unless file
    local_file.write(file.body)
  end
rescue ::Fog::Errors::Error => e
  warn("#{e} - cannot copy #{path(style)} to local file #{local_dest_path}")
  false
end

def directory

def directory
  @directory ||= connection.directories.new(key: directory_name)
end

def directory_name

def directory_name
  if @options[:fog_directory].respond_to?(:call)
    @options[:fog_directory].call(self)
  else
    @options[:fog_directory]
  end
end

def dynamic_fog_host_for_style(style)

def dynamic_fog_host_for_style(style)
  if @options[:fog_host].respond_to?(:call)
    @options[:fog_host].call(self)
  else
    (@options[:fog_host] =~ /%d/) ? @options[:fog_host] % (path(style).hash % 4) : @options[:fog_host]
  end
end

def exists?(style = default_style)

def exists?(style = default_style)
  if original_filename
    !!directory.files.head(path(style))
  else
    false
  end
end

def expiring_url(time = (Time.now + 3600), style_name = default_style)

def expiring_url(time = (Time.now + 3600), style_name = default_style)
  time = convert_time(time)
  http_url_method = "get_#{scheme}_url"
  if path(style_name) && directory.files.respond_to?(http_url_method)
    expiring_url = directory.files.public_send(http_url_method, path(style_name), time)
    if @options[:fog_host]
      expiring_url.gsub!(/#{host_name_for_directory}/, dynamic_fog_host_for_style(style_name))
    end
  else
    expiring_url = url(style_name)
  end
  return expiring_url
end

def find_credentials(creds)

def find_credentials(creds)
  case creds
  when File
    YAML::load(ERB.new(File.read(creds.path)).result)
  when String, Pathname
    YAML::load(ERB.new(File.read(creds)).result)
  when Hash
    creds
  else
    if creds.respond_to?(:call)
      creds.call(self)
    else
      raise ArgumentError, "Credentials are not a path, file, hash or proc."
    end
  end
end

def flush_deletes

def flush_deletes
  for path in @queued_for_delete do
    log("deleting #{path}")
    directory.files.new(:key => path).destroy
  end
  @queued_for_delete = []
end

def flush_writes

def flush_writes
  for style, file in @queued_for_write do
    log("saving #{path(style)}")
    retried = false
    begin
      attributes = fog_file.merge(
        :body         => file,
        :key          => path(style),
        :public       => fog_public(style),
        :content_type => file.content_type
      )
      attributes.merge!(@options[:fog_options]) if @options[:fog_options]
      directory.files.create(attributes)
    rescue Excon::Errors::NotFound
      raise if retried
      retried = true
      directory.save
      retry
    ensure
      file.rewind
    end
  end
  after_flush_writes # allows attachment to clean up temp files
  @queued_for_write = {}
end

def fog_credentials

def fog_credentials
  @fog_credentials ||= parse_credentials(@options[:fog_credentials])
end

def fog_file

def fog_file
  @fog_file ||= begin
    value = @options[:fog_file]
    if !value
      {}
    elsif value.respond_to?(:call)
      value.call(self)
    else
      value
    end
  end
end

def fog_public(style = default_style)

def fog_public(style = default_style)
  if @options.has_key?(:fog_public)
    if @options[:fog_public].respond_to?(:has_key?) && @options[:fog_public].has_key?(style)
      @options[:fog_public][style]
    else
      @options[:fog_public]
    end
  else
    true
  end
end

def host_name_for_directory

def host_name_for_directory
  if directory_name.to_s =~ Fog::AWS_BUCKET_SUBDOMAIN_RESTRICTON_REGEX
    "#{directory_name}.s3.amazonaws.com"
  else
    "s3.amazonaws.com/#{directory_name}"
  end
end

def parse_credentials(creds)

def parse_credentials(creds)
  creds = find_credentials(creds).stringify_keys
  (creds[RailsEnvironment.get] || creds).symbolize_keys
end

def public_url(style = default_style)

def public_url(style = default_style)
  if @options[:fog_host]
    "#{dynamic_fog_host_for_style(style)}/#{path(style)}"
  else
    if fog_credentials[:provider] == 'AWS'
      "#{scheme}://#{host_name_for_directory}/#{path(style)}"
    else
      directory.files.new(:key => path(style)).public_url
    end
  end
end

def scheme

def scheme
  @scheme ||= fog_credentials[:scheme] || 'https'
end