require 'digest'

require_relative 'cache'

class FileCache < Cache

  def initialize
    super
  end

  # Initializes the cache store along with the keys store. Raises an exception if the store path is not supplied.
  def create_store
    @cache = Hash.new
    @keys = Hash.new
    if store == nil
      raise 'Store path is missing!'
    end
  end

  # Places an object inside the cache, and by extension, into the filesystem. Handles max size eviction. Raises an InvalidKey exception if the key is not formatted properly.
  # @param [String] key The key value used to identify an object in the cache
  # @param [Object] value The object to be placed in the cache
  def put(key, value)
    raise ArgumentError unless key.is_a? String
    raise ArgumentError unless key =~ /\A[a-zA-Z0-9_-]+\z/
    @keys[key] = @keys.size.to_s
    File.open(File.join(store, @keys[key]), 'w') do |f|
      f.write(Marshal.dump(value))
    end
    @cache[key] = value
    if expiry_time != nil
      @scheduler.in expiry_time, :blocking => true do
        invalidate key
      end
    end
    check_expiration(key)
  end

  # Gets the object that corresponds with the key that is read from the filesystem
  # @param [String] key The key value used to identify an object in the cache
  # @return [Object] The object that corresponds with the key
  def get(key)
    check_refresh(key)
    if(@keys[key]) == nil
      return nil
    end
    perform_post_get(key)
    return Marshal.load(File.read(File.join(store, @keys[key])))
  end

  # Deletes a key-value pair from the cache and store directory
  # @param [String] key The key value used to identify an object in the cache
  def invalidate(key)
    super
    File.delete(File.join(store, @keys[key]))
    @keys.delete key
  end

  # Clears all items in the cache and the cached files in the store directory
  def invalidate_all
    super
    Dir.foreach(store) do |f|
      File.delete(File.join(store, f)) if f != '.' && f != '..'
    end
  end

end