class SiteServerDbBackup
  include Mongoid::Document
  include Mongoid::Timestamps
  PeriodsTypes=['day','week','month']
  belongs_to :site_server
  field :disable, type: Boolean, default: false
  field :backup_time, type: String, default: '03:00'
  field :path , type: String ,default: '/home/backup/db'
  field :period, type: Integer, default: 0 # 0 => daily , 1 => weekly , 2 => monthly
  field :retain_count, type: Integer, default: 7
  field :need_rewrite, type: Boolean, default: true
  
  before_save do
    unless @skip_callback
      if self.changed?
        self.need_rewrite = true
      end
    end
  end
  def to_crontab_script(return_string=true)
    # minute , hour, day(of month, 1~31), month(1~12), day(of week,0~6)
    crontab_time = ['*', '*', '*', '*', '*']
    hour, minute = self.backup_time.split(':').map{|s| s.to_i}
    crontab_time[0] = minute.to_s rescue '0'
    crontab_time[1] = hour.to_s rescue '0'
    if self.period == 1 #weekly
      crontab_time[4] = '0' #every Sunday
    elsif self.period == 2 #monthly
      crontab_time[2] = '1' #day 1 of every month
    end
    if self.retain_count
      retain_text = "1 week ago"
      if self.period != 0 || self.retain_count != 7 
        retain_text = "#{self.retain_count} #{PeriodsTypes[self.period]} ago"
      end
      scripts = ["#{crontab_time.join(' ')} mongodump -o #{self.path}/`date \"+\\%Y\\%m\\%d\"`_db"]
      if hour < 23
        next_hour = hour + 1
        crontab_time[1] = next_hour.to_s
      else
        crontab_time[1] = ((hour + 1) % 24).to_s
        if self.period == 1 #weekly
          crontab_time[4] = '1' #every Sunday + 1 = Monday
        elsif self.period == 2 #monthly
          crontab_time[2] = '2' #day 1 of every month + 1 = 2
        end
        retain_text += " 1 day ago"
      end
      scripts << "#{crontab_time.join(' ')} rm -fr #{self.path}/`date --date=\"#{retain_text}\" \"+\\%Y\\%m\\%d\"`_db"
    end
    if return_string
      scripts.join("\n")
    else
      scripts
    end
  end
  def self.read_from_crontab_line(crontab_line, crontab_lines)
    if crontab_line.include?('mongodump')
      tmp = crontab_line.split(/\s+[^\s]*mongodump\s+/) # ex: ["0 3 * * *", "-o /home/backup/db/`date \"+\\%Y\\%m\\%d\"`_db"]
      if tmp.count == 2
        crontab_time = tmp[0].split(/\s+/)
        path = File.dirname(tmp[1].split('-o')[1].strip) rescue nil
        if path
          if crontab_time[4] != '*' #weekly
            period = 1
            period_unit = 1.week
          elsif crontab_time[2] != '*' #monthly
            period = 2
            period_unit = 1.month
          else #daily
            period = 0
            period_unit = 1.day
          end
          time = "#{crontab_time[1].rjust(2, "0")}:#{crontab_time[0].rjust(2, "0")}"
          regex_path = /\s+#{::Regexp.escape(path)}\//
          match_line = crontab_lines.select{|l| l.match(/\s+(|\/usr\/bin\/)rm/) && l.match(regex_path)}.first
          if match_line.nil?
            retain_count = nil
          else
            retain_text = match_line.scan(/`\s*date\s+\-\-date=[\'\"]([^\'\"]+)[\'\"]/).flatten.first
            tmp_retain_count, tmp_period = retain_text.sub(/\s+ago/, '').split(/\s+/)
            tmp_retain_count = tmp_retain_count.to_i
            retain_count = (tmp_retain_count.send(tmp_period) / period_unit rescue nil)
          end
          return [time, path, period, retain_count]
        else
          return nil
        end
      else
        return nil
      end
    else
      return nil
    end
  end
  def self.clean_crontab_setting(crontab_lines_str)
    crontab_lines = crontab_lines_str.split("\n")
    related_path = []
    crontab_lines.each do |crontab_line|
      if crontab_line.include?('mongodump')
        tmp = crontab_line.split(/\s+[^\s]*mongodump\s+/) # ex: ["0 3 * * *", "-o /home/backup/db/`date \"+\\%Y\\%m\\%d\"`_db"] 
        output_dir = File.dirname(tmp[1].split('-o')[1].strip) rescue nil
        if output_dir
          related_path << output_dir
        end
      end
    end
    related_path_reg = Regexp.union(related_path.map{|s| /\s+#{::Regexp.escape(s)}\//})
    crontab_lines_str = crontab_lines.map do |crontab_line|
      if crontab_line.match(related_path_reg)
        nil
      else
        crontab_line
      end
    end.compact.join("\n")
  end
  def self.write_crontab_setting(site_server, crontab_lines_str)
    new_crontab_lines = self.where(:site_server_id=> site_server.id, :disable=>false).map{|db_backup| db_backup.to_crontab_script(false)}
    crontab_lines = crontab_lines_str.split("\n")
    exists_indices = new_crontab_lines.map do |sub_crontab_lines|
      match_reg = ::Regexp.new(sub_crontab_lines[0].gsub(/\s+/, '\s+'))
      crontab_lines.index{|l| l.match(match_reg)}
    end
    removed_related_path = []
    crontab_lines.each_with_index do |crontab_line, i|
      if crontab_line.include?('mongodump') && exists_indices.exclude?(i)
        tmp = crontab_line.split(/\s+[^\s]*mongodump\s+/) # ex: ["0 3 * * *", "-o /home/backup/db/`date \"+\\%Y\\%m\\%d\"`_db"] 
        output_dir = File.dirname(tmp[1].split('-o')[1].strip) rescue nil
        if output_dir
          removed_related_path << output_dir
        end
      end
    end
    removed_related_path.each_with_index do |path|
      regex_path = /\s+#{::Regexp.escape(path)}\//
      crontab_lines = crontab_lines.select{|l| l.match(regex_path).nil?}
    end
    exists_indices.each_with_index do |idx, i|
      if idx.nil?
        crontab_lines << new_crontab_lines[i]
      end
    end
    crontab_lines_str = crontab_lines.compact.join("\n")
  end
end