module Tim
  class ProviderImage < Tim::Base
    belongs_to :target_image, :inverse_of => :provider_images
    belongs_to :provider_account, :class_name => Tim.provider_account_class

    accepts_nested_attributes_for :target_image

    attr_accessible :target_image_attributes
    attr_accessible :external_image_id, :if => :imported?
    attr_accessible :status, :status_detail, :progress #, :as => :image_factory
    attr_accessible :provider
    attr_writer :credentials
    attr_protected :id

    validates_presence_of :target_image
    validates_presence_of :external_image_id, :if => :imported?

    after_create :create_factory_provider_image, :unless => :imported?
    after_create :create_import, :if => :imported?

    def imported?
      target_image.imported?
    end

    private
    def factory_provider_credentials
      @credentials
    end

    def factory_provider
      self.provider
    end

    def create_factory_provider_image
      begin
        provider_image = ImageFactory::ProviderImage.new(:credentials => factory_provider_credentials,
                                                          # TODO Remove this when upgrading to 3.2
                                                          # target conflicts with rails 3.0.10
                                                          # ActiveRecord::Associations::Association#target
                                                          :target => target_image.target,
                                                          :parameters => "")
        provider_image.provider = factory_provider
        # TODO There is a bug in ARes 3.0.10 that will add map name twice when setting in mass assign.  So we set
        # parameters separately.
        # Setting parameters at mass assign results in json => {"target_image":"parameters":{"parameters":{"..."}}}"
        # This should be tested and removed if fixed in 3.2
        provider_image.parameters = { :callbacks => ["#{ImageFactory::ProviderImage.callback_url}/#{self.id}"] }
        if target_image.snapshot?
          provider_image.parameters[:snapshot] = true
          provider_image.template = self.target_image.template.xml
        else
          provider_image.target_image_id = self.target_image.factory_id
        end

        provider_image.save!
        populate_factory_fields(provider_image)
        self.save
      rescue Errno::ECONNREFUSED
        raise Tim::Error::ImagefactoryConnectionRefused.new("Unable to connect"\
         " to Imagefactory server @ #{Tim::ImageFactory::Base.site}")
      rescue => e
        # TODO Add proper error handling
        raise e
      end
    end

    def populate_factory_fields(factory_provider_image)
      self.status = factory_provider_image.status
      self.factory_id = factory_provider_image.id
      self.status_detail = factory_provider_image.status_detail.activity
      self.progress = factory_provider_image.percent_complete
      self.provider = factory_provider_image.provider
      self.external_image_id = factory_provider_image.identifier_on_provider
      self.factory_provider_account_id = factory_provider_image.provider_account_identifier
    end

    # TODO At the moment this method simply sets fields to import defaults.
    # We should investigate whether we can check the image exists and if the
    # user can access it.  Deltacloud?
    def create_import
      self.status = "COMPLETE"
      self.progress = "COMPLETE"
      self.status_detail = "Imported Image"
      self.save
    end
  end
end