#require 'ruby-rets'
require "rets/version"
require "rets/exceptions"
require "rets/client"
require "rets/http"
require "rets/stream_http"
require "rets/base/core"
require "rets/base/sax_search"
require "rets/base/sax_metadata"

require 'httparty'
require 'json'

# http://rets.solidearth.com/ClientHome.aspx

class CabooseRets::RetsImporter # < ActiveRecord::Base

  @@rets_client = nil   
  @@config = nil

  def self.config
    return @@config
  end

  def self.get_config
    @@config = {
      'url'                 => nil, # URL to the RETS login
      'username'            => nil,
      'password'            => nil,
      'temp_path'           => nil,
      'log_file'            => nil,
      'media_base_url'      => nil
    }
    config = YAML::load(File.open("#{Rails.root}/config/rets_importer.yml"))    
    config = config[Rails.env]
    config.each { |key,val| @@config[key] = val }
  end

  def self.client
    self.get_config if @@config.nil? || @@config['url'].nil?
    if @@rets_client.nil?
      @@rets_client = RETS::Client.login(
        :url      => @@config['url'],
        :username => @@config['username'],
        :password => @@config['password']
      )
    end
    return @@rets_client
  end

  def self.meta(class_type)
    case class_type
      when 'Office'    then Caboose::StdClass.new({ :search_type => 'Office'    , :remote_key_field => 'OfficeMlsId' , :local_key_field => 'lo_mls_id'    , :local_table => 'rets_offices'      , :date_modified_field => 'ModificationTimestamp'})
      when 'Member'    then Caboose::StdClass.new({ :search_type => 'Member'    , :remote_key_field => 'MemberMlsId' , :local_key_field => 'mls_id'    , :local_table => 'rets_agents'       , :date_modified_field => 'ModificationTimestamp'})
      when 'OpenHouse' then Caboose::StdClass.new({ :search_type => 'OpenHouse' , :remote_key_field => 'OpenHouseKey' , :local_key_field => 'matrix_unique_id'    , :local_table => 'rets_open_houses'  , :date_modified_field => 'ModificationTimestamp'})
      when 'Property'  then Caboose::StdClass.new({ :search_type => 'Property'  , :remote_key_field => 'ListingId' , :local_key_field => 'mls_number'    , :local_table => 'rets_properties'   , :date_modified_field => 'ModificationTimestamp'})
      when 'Media'     then Caboose::StdClass.new({ :search_type => 'Media'     , :remote_key_field => 'MediaObjectID'         , :local_key_field => 'media_id'            , :local_table => 'rets_media'        , :date_modified_field => 'ModificationTimestamp'   })
      end
  end

  #=============================================================================
  # Import method
  #=============================================================================

  def self.import(class_type, query)
    m = self.meta(class_type)
    self.log3(class_type,nil,"Importing #{m.search_type}:#{class_type} with query #{query}...") 
    self.get_config if @@config.nil? || @@config['url'].nil?
    params = {
      :search_type => m.search_type,
      :class => class_type,
      :query => query,
    #  :limit => 3,
      :timeout => -1
    }
    obj = nil

    begin
      self.client.search(params) do |data|
        obj = self.get_instance_with_id(class_type, data)
        if obj.nil?
          self.log3(class_type,nil,"Error: object is nil")
          self.log3(class_type,nil,data.inspect)
          next
        end
        obj.parse(data)
        obj.save
      end
    rescue RETS::HTTPError => err
      self.log3(class_type,nil,"Import error for #{class_type}: #{query}")
      self.log3(class_type,nil,err.message)
    end
  end

  def self.get_instance_with_id(class_type, data)
    obj = nil
    self.log "Getting instance of #{class_type}..."
    m = case class_type
      when 'Property'  then CabooseRets::Property
      when 'OpenHouse' then CabooseRets::OpenHouse
      when 'Member'    then CabooseRets::Agent
      when 'Office'    then CabooseRets::Office
      when 'Media'     then CabooseRets::Media
    end  
    obj  = case class_type
      when 'Property'  then m.where(:mls_number => data['ListingId']).exists? ? m.where(:mls_number => data['ListingId']).first : m.create(:mls_number => data['ListingId'])
      when 'OpenHouse' then m.where(:matrix_unique_id => data['OpenHouseKey']).exists? ? m.where(:matrix_unique_id => data['OpenHouseKey']).first : m.create(:matrix_unique_id => data['OpenHouseKey'])
      when 'Member'    then m.where(:mls_id => data['MemberMlsId']).exists? ? m.where(:mls_id => data['MemberMlsId']).first : m.create(:mls_id => data['MemberMlsId'])
      when 'Office'    then m.where(:lo_mls_id => data['OfficeMlsId']).exists? ? m.where(:lo_mls_id => data['OfficeMlsId']).first : m.create(:lo_mls_id => data['OfficeMlsId'])
      when 'Media'     then m.where(:media_id => data['MediaObjectID']      ).exists? ? m.where(:media_id => data['MediaObjectID']      ).first : m.create(:media_id => data['MediaObjectID']      )
    end
    self.log "Found matching object ID #{obj.id}"
    return obj
  end

  #=============================================================================
  # Main updater
  #=============================================================================

  def self.update_after(date_modified, save_images = true)
    si = save_images ? 'saving images' : 'not saving images'
    self.log3(nil,nil,"Updating after #{date_modified} and #{si}")
    self.delay(:priority => 10, :queue => 'rets').update_helper('Property' , date_modified, save_images)
    self.delay(:priority => 10, :queue => 'rets').update_helper('Office'   , date_modified, false)
    self.delay(:priority => 10, :queue => 'rets').update_helper('Member'   , date_modified, false)
    self.delay(:priority => 10, :queue => 'rets').update_helper('OpenHouse', date_modified, false)
  end

  def self.update_helper(class_type, date_modified, save_images = true)
    #self.log3(class_type,nil,"In update helper for #{class_type}")
    self.log3(class_type,nil,"Updating everything modified after #{date_modified}")
    m = self.meta(class_type)
    k = m.remote_key_field
    d = date_modified.in_time_zone(CabooseRets::timezone).strftime("%FT%T")

    quer = "(#{m.date_modified_field}=#{d}+)"
    quer += "OR(PhotosChangeTimestamp=#{d}+)" if class_type == 'Property'

    params = {
      :search_type => m.search_type,
      :class => class_type,
      :select => [m.remote_key_field],
      :querytype => 'DMQL2',
      :query => quer,
      :standard_names_only => true,
      :timeout => -1
    }    
    self.log3(class_type,nil,"Searching with params: " + params.to_s)
    self.client.search(params) do |data|
      self.log3(class_type,nil,"Resulting data: " + data.to_s)
      case class_type
        when 'Property'  then self.delay(:priority => 10, :queue => 'rets').import_properties(data[k], save_images)
        when 'Office'    then self.delay(:priority => 10, :queue => 'rets').import_office(    data[k], false)
        when 'Member'    then self.delay(:priority => 10, :queue => 'rets').import_agent(     data[k], false)
        when 'OpenHouse' then self.delay(:priority => 10, :queue => 'rets').import_open_house(data[k], false)
      end
    end
  end

  #=============================================================================
  # Single model import methods (called from a worker dyno)
  #=============================================================================

  # def self.import_property(mui, save_images = true)
  #   self.import('Listing', "(Matrix_Unique_ID=#{mui})")
  #   p = CabooseRets::Property.where(:matrix_unique_id => mui.to_s).first
  #   if p != nil
  #     self.download_property_images(p)
  #     self.update_coords(p)
  #   else
  #     self.log("No Property associated with #{mui}")
  #   end
  # end

  def self.import_properties(mls_id, save_images = true)
    si = save_images ? 'saving images' : 'not saving images'
    self.log3('Property',mls_id,"Importing Property #{mls_id} and #{si}...")
    self.import('Property', "(ListingId=#{mls_id})")
    p = CabooseRets::Property.where(:mls_number => mls_id.to_s).first
    if p != nil
      self.download_property_images(p) if save_images
      self.update_coords(p)
    else
      self.log3(nil,nil,"No Property associated with #{mls_id}")
    end
  end

  def self.import_office(mls_id, save_images = true)
    self.log3('Office',mls_id,"Importing Office #{mls_id}...")
    self.import('Office', "(OfficeMlsId=#{mls_id})")
    office = CabooseRets::Office.where(:matrix_unique_id => mls_id.to_s).first
  end

  def self.import_agent(mls_id, save_images = true)
    self.log3('Agent',mls_id,"Importing Agent #{mls_id}...")
    self.import('Member', "(MemberMlsId=#{mls_id})")
    a = CabooseRets::Agent.where(:mls_id => mls_id.to_s).first
  end

  def self.import_open_house(oh_id, save_images = true)
    self.log3('OpenHouse',oh_id,"Importing Open House #{oh_id}...")
    self.import('OpenHouse', "(OpenHouseKey=#{oh_id})")
  end

  def self.import_media(id, save_images = true)
    self.log3('Media',id,"Importing Media #{id}...")
    self.import('Media', "((MediaObjectID=#{id}+),(MediaObjectID=#{id}-))")
  end

  #=============================================================================
  # Images
  #=============================================================================

  # def self.download_property_images(p, save_images = true)
  #   return if save_images == false

  #   self.log("- Downloading GFX records for #{p.matrix_unique_id}...")
  #   params = {
  #     :search_type => 'Media',
  #     :class => 'Photo',
  #     :type => 'Photo',
  #     :resource => 'Property',
  #     :query => "(ID=*#{p.matrix_unique_id}:1*)",
  #     :limit => 1000,
  #     :timeout => -1
  #   }
  #   ids = []
  #   self.client.search(params) do |data|
  #     puts data
  #     ids << data['MEDIA_ID']
  #     m = CabooseRets::Media.where(:media_id => data['MEDIA_ID']).first
  #     m = CabooseRets::Media.new if m.nil?
  #     data.MEDIA_MUI = p.matrix_unique_id
  #     m.parse(data)
  #     m.save
  #   end

  #   if ids.count > 0
  #     # Delete any records in the local database that shouldn't be there
  #     self.log("- Deleting GFX records for MLS ##{p.matrix_unique_id} in the local database that are not in the remote database...")
  #     query = "select media_id from rets_media where matrix_unique_id = '#{p.matrix_unique_id}'"
  #     rows = ActiveRecord::Base.connection.select_all(ActiveRecord::Base.send(:sanitize_sql_array, query))
  #     local_ids = rows.collect{ |row| row['media_id'] }
  #     ids_to_remove = local_ids - ids
  #     if ids_to_remove && ids_to_remove.count > 0
  #       query = ["delete from rets_media where media_id in (?)", ids_to_remove]
  #       ActiveRecord::Base.connection.execute(ActiveRecord::Base.send(:sanitize_sql_array, query))
  #     end
  #   end
  # end

  def self.download_property_images(p)
    self.log3('Property',p.mls_number,"Downloading images for #{p.mls_number}...")
    begin
      # Get first image
      self.client.get_object(:resource => 'Property', :type => 'Photo', :location=> false, :id => "#{p.matrix_unique_id}:0") do |headers, content|
        m = CabooseRets::Media.where(:media_mui => headers['content-id'], :media_order => 0).first
        m = CabooseRets::Media.new if m.nil?
        tmp_path = "#{Rails.root}/tmp/rets_media_#{headers['content-id']}:0.jpeg"
        File.open(tmp_path, "wb") do |f|
          f.write(content)
        end
        m.media_mui     = headers['content-id']
        m.media_order   = 0
        m.media_type    = 'Photo'
        cm               = Caboose::Media.new
        cm.image         = File.open(tmp_path)
        cm.name          = "rets_media_#{headers['content-id']}_0"
        cm.original_name = "rets_media_#{headers['content-id']}_0.jpeg"
        cm.processed     = true
        cm.save
        m.media_id = cm.id
        m.save
        `rm #{tmp_path}`
        self.log("Image rets_media_#{headers['content-id']}_0 saved")
      end
      # Get rest of images
      self.client.get_object(:resource => 'Property', :type => 'Photo', :location=> false, :id => "#{p.matrix_unique_id}:*") do |headers, content|
        m = CabooseRets::Media.where(:media_mui => headers['content-id'], :media_order => headers['orderhint']).first
        m = CabooseRets::Media.new if m.nil?
        tmp_path = "#{Rails.root}/tmp/rets_media_#{headers['content-id']}:#{headers['object-id']}.jpeg"
        File.open(tmp_path, "wb") do |f|
          f.write(content)
        end
        m.media_mui     = headers['content-id']
        m.media_order   = headers['orderhint']
        m.media_type    = 'Photo'
        cm               = Caboose::Media.new
        cm.image         = File.open(tmp_path)
        cm.name          = "rets_media_#{headers['content-id']}_#{headers['object-id']}"
        cm.original_name = "rets_media_#{headers['content-id']}_#{headers['object-id']}.jpeg"
        cm.processed     = true
        cm.save
        m.media_id = cm.id
        m.save
        `rm #{tmp_path}`
        self.log("Image rets_media_#{headers['content-id']}_#{headers['object-id']} saved")
      end
    rescue RETS::APIError => err
      self.log "No image for #{p.mls_number}."
      self.log err
    end
  end

  def self.download_missing_images
    self.log3("Property",nil,"Downloading all missing images...")
    CabooseRets::Property.where("photo_count = ? OR photo_count is null", '').all.each do |p|
      self.delay(:priority => 10, :queue => 'rets').import_properties(p.mls_number, true)
    end
  end

  def self.download_agent_image(agent)
    # self.log "Saving image  for #{agent.first_name} #{agent.last_name}..."
    # begin
    #   self.client.get_object(:resource => :Member, :type => :Photo, :location => true, :id => property.list_agent_mls_id) do |headers, content|
    #     agent.verify_meta_exists
    #     agent.meta.image_location = headers['location']
    #     agent.meta.save
    #   end
    # rescue RETS::APIError => err
    #   self.log "No image for #{agent.first_name} #{agent.last_name}."
    #   self.log err
    # end
  end

  def self.download_office_image(office)
    #self.log "Saving image for #{agent.first_name} #{agent.last_name}..."
    #begin
    #  self.client.get_object(:resource => :Agent, :type => :Photo, :location => true, :id => agent.la_code) do |headers, content|
    #    agent.verify_meta_exists
    #    agent.meta.image_location = headers['location']
    #    agent.meta.save
    #  end
    #rescue RETS::APIError => err
    #  self.log "No image for #{agent.first_name} #{agent.last_name}."
    #  self.log err
    #end
  end

  #=============================================================================
  # GPS
  #=============================================================================

  def self.update_coords(p = nil)
    if p.nil?
      model = CabooseRets::Property      
      i = 0      
        self.log3('Property',nil,"Updating coords properties...")
        model.where(:latitude => nil).reorder(:mls_number).each do |p1|
          self.delay(:priority => 10, :queue => 'rets').update_coords(p1)
        end
      return
    end

    self.log3('Property',p.mls_number,"Getting coords for MLS # #{p.mls_number}...")
    coords = self.coords_from_address(CGI::escape "#{p.street_number} #{p.street_name}, #{p.city}, #{p.state_or_province} #{p.postal_code}")
    if coords.nil? || coords == false
      self.log3('Property',nil,"Can't set coords for MLS # #{p.mls_number}...")
      return
    end

    p.latitude = coords['lat']
    p.longitude = coords['lng']
    p.save
  end

  def self.coords_from_address(address)
    begin
      uri = "https://maps.googleapis.com/maps/api/geocode/json?key=AIzaSyBD34Da5DhRH5wkq3sROsE7-jv90-f1v6o&address=#{address}"
      uri.gsub!(" ", "+")
      resp = HTTParty.get(uri)
      json = JSON.parse(resp.body)
      return json['results'][0]['geometry']['location']
    rescue
      self.log "Error: #{uri}"
      sleep(2)
      return false
    end
  end

  #=============================================================================
  # Purging
  #=============================================================================

  def self.purge
    self.log3(nil,nil,'purging')
    self.purge_properties
    self.purge_offices
    self.purge_agents
    self.purge_open_houses
  end  
  
  def self.purge_properties()   self.delay(:priority => 10, :queue => 'rets').purge_helper('Property', '2012-01-01') end
  def self.purge_offices()      self.delay(:priority => 10, :queue => 'rets').purge_helper('Office', '2012-01-01') end
  def self.purge_agents()       self.delay(:priority => 10, :queue => 'rets').purge_helper('Member', '2012-01-01') end
  def self.purge_open_houses()  self.delay(:priority => 10, :queue => 'rets').purge_helper('OpenHouse', '2012-01-01') end
  

  def self.purge_helper(class_type, date_modified)    
    m = self.meta(class_type)    
    self.log(m.search_type)

    self.log3(class_type,nil,"Purging #{class_type}...")

    # Get the total number of records
    self.log3(class_type,nil,"Getting total number of records for #{class_type}...")

    statusquery = ""

    case class_type
      when 'Property'  then statusquery = "MlsStatus=Active"
      when 'Office'    then statusquery = "OfficeStatus=Active"
      when 'Member'    then statusquery = "MemberStatus=Active"
      when 'OpenHouse' then statusquery = "OpenHouseKeyNumeric=0+"
    end

    params = {
      :search_type => m.search_type,
      :class => class_type,
      :query => "(#{m.date_modified_field}=#{date_modified}T00:00:01+)AND(#{statusquery})",
      :standard_names_only => true,
      :timeout => -1
    }
    count = 0
    self.client.search(params.merge({ :count => 1})) do |data| end        
    count = self.client.rets_data[:code] == "20201" ? 0 : self.client.rets_data[:count]    
    batch_count = (count.to_f/5000.0).ceil

    ids = []
    k = m.remote_key_field
    (0...batch_count).each do |i|
      self.log3(class_type,nil,"Getting ids for #{class_type} (batch #{i+1} of #{batch_count})...")
      self.client.search(params.merge({ :select => [k], :limit => 5000, :offset => 5000*i })) do |data|
        ids << (class_type == 'OpenHouse' ? data[k].to_i : data[k])
      end
    end

    # Only do stuff if we got a real response from the server
    if ids.count > 0

      self.log3(class_type,nil,"Remote IDs found: #{ids.to_s}")

      # Delete any records in the local database that shouldn't be there
      self.log3(class_type,nil,"Finding #{class_type} records in the local database that are not in the remote database...")
      t = m.local_table
      k = m.local_key_field
      query = "select distinct #{k} from #{t}"
      rows = ActiveRecord::Base.connection.select_all(ActiveRecord::Base.send(:sanitize_sql_array, query))
      local_ids = rows.collect{ |row| row[k] }
      self.log3(class_type,nil,"Local IDs found: #{local_ids.to_s}")
      ids_to_remove = local_ids - ids
      self.log3(class_type,nil,"Found #{ids_to_remove.count} #{class_type} records in the local database that are not in the remote database.")
      self.log3(class_type,nil,"Deleting #{class_type} records in the local database that shouldn't be there...")
      query = ["delete from #{t} where #{k} in (?)", ids_to_remove]
      ActiveRecord::Base.connection.execute(ActiveRecord::Base.send(:sanitize_sql_array, query))

      # Find any ids in the remote database that should be in the local database
      self.log3(class_type,nil,"- Finding #{class_type} records in the remote database that should be in the local database...")
      query = "select distinct #{k} from #{t}"
      rows = ActiveRecord::Base.connection.select_all(ActiveRecord::Base.send(:sanitize_sql_array, query))
      local_ids = rows.collect{ |row| row[k] }
      self.log3(class_type,nil,"Local IDs found: #{local_ids.to_s}")
      ids_to_add = ids - local_ids
      ids_to_add = ids_to_add.sort.reverse
      self.log3(class_type,nil,"Found #{ids_to_add.count} #{class_type} records in the remote database that we need to add to the local database.")
      ids_to_add.each do |id|
        self.log3(class_type,nil,"Importing #{id}...")
        case class_type
          when "Property"   then self.delay(:priority => 10, :queue => 'rets').import_properties(id, true)
          when "Office"    then self.delay(:priority => 10, :queue => 'rets').import_office(id, false)
          when "Member"     then self.delay(:priority => 10, :queue => 'rets').import_agent(id, false)
          when "OpenHouse" then self.delay(:priority => 10, :queue => 'rets').import_open_house(id, false)
        end
      end
    end
  end

  # def self.get_media_urls
  #   m = self.meta(class_type)

  #   # Get the total number of records
  #   params = {
  #     :search_type => m.search_type,
  #     :class => class_type,
  #     :query => "(#{m.matrix_modified_dt}=#{date_modified}T00:00:01+)",
  #     :standard_names_only => true,
  #     :timeout => -1
  #   }
  #   self.client.search(params.merge({ :count => 1 }))
  #   count = self.client.rets_data[:code] == "20201" ? 0 : self.client.rets_data[:count]
  #   batch_count = (count.to_f/5000.0).ceil

  #   ids = []
  #   k = m.remote_key_field
  #   (0...batch_count).each do |i|
  #     self.client.search(params.merge({ :select => [k], :limit => 5000, :offset => 5000*i })) do |data|
  #       ids << data[k]
  #     end
  #   end

  #   if ids.count > 0
  #     # Delete any records in the local database that shouldn't be there
  #     t = m.local_table
  #     k = m.local_key_field
  #     query = ["delete from #{t} where #{k} not in (?)", ids]
  #     ActiveRecord::Base.connection.execute(ActiveRecord::Base.send(:sanitize_sql_array, query))

  #     # Find any ids in the remote database that should be in the local database
  #     query = "select distinct #{k} from #{t}"      
  #     rows = ActiveRecord::Base.connection.select_all(ActiveRecord::Base.send(:sanitize_sql_array, query))
  #     local_ids = rows.collect{ |row| row[k] }
  #     ids_to_add = ids - local_ids
  #     ids_to_add.each do |id|
  #       self.log("Importing #{id}...")
  #       case class_type
  #         when "Property"  then self.delay(:priority => 10, :queue => 'rets').import_properties(id, true)
  #         when "Office"    then self.delay(:priority => 10, :queue => 'rets').import_office(id, false)
  #         when "Member"    then self.delay(:priority => 10, :queue => 'rets').import_agent(id, false)
  #         when "OpenHouse" then self.delay(:priority => 10, :queue => 'rets').import_open_house(id, false)
  #       end
  #     end
  #   end

  # end

  #=============================================================================
  # Logging
  #=============================================================================

  def self.log(msg)
    puts "[rets_importer] #{msg}"
  end

  def self.log2(msg)
    puts "======================================================================"
    puts "[rets_importer] #{msg}"
    puts "======================================================================"
  end

  def self.log3(class_name, object_id, text)
    self.log2(text)
    log = CabooseRets::Log.new
    log.class_name = class_name
    log.object_id = object_id
    log.text = text
    log.timestamp = DateTime.now
    log.save
  end

  #=============================================================================
  # Locking update task
  #=============================================================================

  def self.update_rets
    self.log3(nil,nil,"Updating rets...")
    if self.task_is_locked
      self.log2("Task is locked, aborting.")
      return
    end
    self.log2("Locking task...")
    task_started = self.lock_task

    begin
      overlap = 2.hours
      if (DateTime.now - self.last_purged).to_f >= 0.5
        self.purge
        self.save_last_purged(task_started)
        overlap = 1.week
      end
      self.update_after(self.last_updated - overlap)
      self.download_missing_images
      self.log3(nil,nil,"Saving the timestamp for when we updated to #{task_started.to_s}...")
		  self.save_last_updated(task_started)
		  self.log2("Unlocking the task...")
		  self.unlock_task
		rescue Exception => err
		  puts err
		  raise
		ensure
		  self.log2("Unlocking task if last updated...")
		  self.unlock_task_if_last_updated(task_started)
    end

		# Start the same update process in 20 minutes
		self.log3(nil,nil,"Adding the update rets task for 20 minutes from now...")
		q = "handler like '%update_rets%'"
		count = Delayed::Job.where(q).count
		if count == 0 || (count == 1 && Delayed::Job.where(q).first.locked_at)
		  self.delay(:run_at => 20.minutes.from_now, :priority => 10, :queue => 'rets').update_rets
		end
    # Delete old logs
    CabooseRets::Log.where("timestamp < ?",(DateTime.now - 30.days)).destroy_all
  end

  def self.last_updated
    if !Caboose::Setting.exists?(:name => 'rets_last_updated')
      Caboose::Setting.create(:name => 'rets_last_updated', :value => '2013-08-06T00:00:01')
    end
    s = Caboose::Setting.where(:name => 'rets_last_updated').first
    return DateTime.parse(s.value)
  end

  def self.last_purged
    if !Caboose::Setting.exists?(:name => 'rets_last_purged')
      Caboose::Setting.create(:name => 'rets_last_purged', :value => '2013-08-06T00:00:01')
    end
    s = Caboose::Setting.where(:name => 'rets_last_purged').first
    return DateTime.parse(s.value)
  end

  def self.save_last_updated(d)
    s = Caboose::Setting.where(:name => 'rets_last_updated').first
    s.value = d.in_time_zone(CabooseRets::timezone).strftime("%FT%T%:z")
    s.save
  end

  def self.save_last_purged(d)
    s = Caboose::Setting.where(:name => 'rets_last_purged').first
    s.value = d.in_time_zone(CabooseRets::timezone).strftime("%FT%T%:z")
    s.save
  end

  def self.task_is_locked
    return Caboose::Setting.exists?(:name => 'rets_update_running')
  end

  def self.lock_task
    d = DateTime.now.utc.in_time_zone(CabooseRets::timezone)
    Caboose::Setting.create(:name => 'rets_update_running', :value => d.strftime("%FT%T%:z"))
    return d
  end

  def self.unlock_task
    Caboose::Setting.where(:name => 'rets_update_running').first.destroy
  end

  def self.unlock_task_if_last_updated(d)
    setting = Caboose::Setting.where(:name => 'rets_update_running').first
    self.unlock_task if setting && d.in_time_zone.strftime("%FT%T%:z") == setting.value
  end

end