# Serializers can be swapped out on a per worker basis and set globally to a default via the config file.
# 
# The default serializer is Marshal to maintain backward compatibility with existing apps. Three serializers
# are available out of the box, Marshal, JSON & YAML.  
# 
# To change the default serializer, add a key [serializer] to the config file with a value of %w{marshal json yaml} or your 
# own custom serializer.
# 
# You may also write your own custom serializer classes by extending SweatShop::Serializer.  
# 
# You can give your serializers an arbitrary class name, but the default pattern is to name it <somename>Serializer.  Notice
# you can specify the Marshal, JSON or YAML serializer with the name :marshal, :json, or :yaml.  This default short name
# is generated by underscoring the class name and removing the "Serializer" from the end of the class name, i.e. 
# SweatShop::Serializers::JsonSerializer becomes :json and My::Custom::EncryptedSerializer would become :encrypted.  You can
# override this default generated name by using the declaration in the top of your class:
#   serializer_name :foo 
#   
# Where :foo is what you want to register the serializer as.
# 
# This is a complete example of how to write a custom serializer:
# 
#    class MyCustomSerializer < SweatShop::Serializer
#       serializer_name :foo # overrides the generated default name of :my_custom based on the above rules
# 
#       def self.serialize(data)
#         ... # custom serialize the data
#       end
#       
#       def self.deserialize(data)
#         ... # custom deserialize the data
#       end
#    end

module SweatShop
  class Serializer
    
    def Serializer.inherited(subklass)
      register(subklass.get_name, subklass)
    end
    
    def Serializer.serializers
      @serializers ||= {}
    end

    def Serializer.default
      @default_serializer ||= begin
        if s = config['serializer']
          unless serializers.has_key?(s.to_sym)
            raise RuntimeError, "Unknown serializer [#{s}]"
          end
          log("Using [:#{s}] as the Default Serializer")
          serializers[s.to_sym]
        else
          log("No Default Serializer specified.  Using [:marshal]")
          serializers[:marshal]
        end
      end
    end
    
    def Serializer.default=(serializer_name)
      @default_serializer = serializers[serializer_name.to_sym]
    end

    def self.serializer_name(name)
      @serializer_name = name
      register(name, self)
    end
    
    def self.get_name
      @serializer_name || generate_serializer_name(self.to_s)
    end

    def self.log(msg)
      SweatShop.log(msg)
    end
    
    private
    
    def Serializer.register(name, klass)
      # classes get inherited before the name is set - update it by removing first
      Serializer.serializers.delete(generate_serializer_name(klass.to_s)) 
      Serializer.serializers[name] = klass
    end
    
    def self.config
      SweatShop.config
    end
    
    
    def self.generate_serializer_name(name)
      underscore(name.to_s.gsub(/Serializer$/, "")).split("/").last.to_sym    
    end

    # Taken straight out of the rails Inflector module
    def self.underscore(camel_cased_word)
      camel_cased_word.to_s.gsub(/::/, '/').
      gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
      gsub(/([a-z\d])([A-Z])/,'\1_\2').
      tr("-", "_").
      downcase
    end
  end
end


require File.dirname(__FILE__) +  '/marshal_serializer'
require File.dirname(__FILE__) +  '/json_serializer'
require File.dirname(__FILE__) +  '/yaml_serializer'