class SiteConstruct
  include Mongoid::Document
  include Mongoid::Timestamps
  def self.server_types
    SiteServer.all.map{|s| s.server_name}
  end
  SITE_TYPES = ["School","Gravity"]
  field :rails_env, type: String, :default => "development"
  field :server_type
  field :site_name
  field :domain_name
  field :nginx_file
  field :db_name
  field :port, type: Array, :default => ["80"]
  field :path
  field :site_type
  field :school_name
  field :user_id
  field :constructed, type: Boolean, :default => false
  field :status, type: String, :default => ""
  field :infos, type: Array, :default => []
  field :hidden, type: Boolean, :default  => false
  field :copy_id
  field :only_copy_installed_module, type: Boolean, :default  => false
  field :cert_ver_added_text
  field :cert_ver_file_content
  field :cert_ver_location_path
  belongs_to :site_cert
  after_initialize do |record|
    unless record.new_record?
      save_flag = false
      if record.status.nil?
        record.status = ""
        save_flag = true
      end
      if record.infos.nil?
        record.infos = []
        save_flag = true
      end
      if record.nginx_file.nil?
        record.nginx_file = "/etc/nginx/orbit_sites/"+record.site_name.to_s
        save_flag = true
      end
      if record.path.nil?
        dir_path = ((record.site_type == "School" && !record.school_name.blank?) ? "school_sites/#{record.school_name}" : "orbit_sites")
        record.path = "/home/rulingcom/#{dir_path}"
        save_flag = true
      end
      if record["port"].class == String
        record["port"] = Array(record["port"])
        save_flag = true
      end
      if save_flag && !@skip_callback
        @skip_callback = true
        record.save(:validate=>false)
      end
      @skip_callback = false
    end
  end
  def generate_nginx_text(old_nginx_text="")
    sock_text = 'upstream '+self.get_site_name+'_sock {\n'+
              '  server unix:'+self.full_site_path+'/tmp/unicorn.sock;\n'+
              '}\n'
    all_ports = self.port.uniq
    server_blocks = []
    if old_nginx_text.present?
      all_blocks = parse_nginx_text_to_server_blocks(old_nginx_text,true)
      server_blocks = all_blocks.select{|s| s.match(/\A[\s\r\n]*server\s*{/)}
      upstream_block = all_blocks.select{|s| s.match(/\A[\s\r\n]*upstream/)}.first rescue nil
      if upstream_block.present?
        sock_text = upstream_block + '\n'
      end
    end
    nginx_text = sock_text + all_ports.map.with_index{|port,i|
      if server_blocks[i].present?
        generate_server_block(port,server_blocks[i])
      else
        generate_server_block(port,server_blocks[0])
      end
    }.join('\n')
  end
  def parse_nginx_text_to_server_blocks(nginx_text,get_all_blocks=false)
    num = 1
    nginx_text_tmp = nginx_text.gsub(/({|})/m){|ff| res = ff;((ff == '{') ? (res = ff * num;num = num + 1) : (num = num - 1;res = ff * num;)); res}
    end_indices = nginx_text_tmp.enum_for(:scan,/^(?:}+\s?)+/m).map { Regexp.last_match.offset(0).first + 1 }
    start_index = 0
    all_blocks = end_indices.map{|i| res = nginx_text_tmp[start_index..i];start_index = i + 1;res}
    all_blocks = all_blocks.map{|s| s.gsub(/[{}]+/){|ff| ff[0]}.strip}
    server_blocks = all_blocks.select{|s| s.match(/\A[\s\r\n]*server\s*{/)}
    if get_all_blocks
      all_blocks
    else
      server_blocks
    end
  end
  def generate_server_block(port,old_server_block="")
    if port.blank?
      port = "80"
    else
      port = port.to_s
    end
    port_text = port
    if port.to_i == 443
      if self.site_cert.nil?
        return ""
      end
      port_text += " ssl"
    end
    if old_server_block.present?   
      new_server_block = old_server_block.gsub(/(listen\s+)[^;]+/){|ff| "#{$1}#{port_text}"}
      domain_name = self.domain_name
      new_server_block = new_server_block.gsub(/(server_name\s+)[^;]+/m){|ff| "#{$1}#{domain_name}"}
      new_server_block = new_server_block.gsub(/\s*ssl_certificate[^;]+;/,'')
      if port == "443"
        new_server_block = new_server_block.gsub(/(listen\s+)[^;]+;/){|ff| ff + "\n\n  ssl_certificate #{self.cert_file_remote_store_path};\\n\\n  ssl_certificate_key #{self.private_key_remote_store_path};\\n\\n"}
      end
      new_server_block = new_server_block.gsub(/\n{3,}/,'\n\n')
    else
      'server {\n'+
        '  listen '+port_text+';\n\n'+
        (port == "443" ? "  ssl_certificate #{self.cert_file_remote_store_path};\\n\\n  ssl_certificate_key #{self.private_key_remote_store_path};\\n\\n" : '')+
        '  root '+self.full_site_path+'/public;\n\n'+
        '  server_name '+self.domain_name+';\n\n'+
        '  client_max_body_size 500m;\n\n'+
        '  location / {\n'+
        '    try_files \$uri \$uri/index.html \$uri.html @app;\n'+
        '  }\n\n'+
        '  location @app {\n'+
        '    proxy_redirect     off;\n'+
        '    proxy_set_header   X-Forwarded-For \$proxy_add_x_forwarded_for;\n'+
        '    proxy_set_header   Host  \$http_host;\n'+
        '    proxy_connect_timeout   360;\n'+
        '    proxy_pass http://'+self.get_site_name+'_sock;\n'+
        '  }\n'+
        '}'
    end
  end
  def display_port
    self.port.map{|port| "#{port}"}.join("
").html_safe
  end
  def get_host_with_port(port)
    self.domain_name.split().first
  end
  def get_port(idx=0)
    self.port[idx] rescue "80"
  end
  def full_site_path
    return "#{self.get_path}/#{self.get_site_name}"
  end
  def cert_file_remote_store_path
    site_cert = self.site_cert
    "#{self.full_site_path}/ssl_certs/#{site_cert.id}/#{site_cert["cert_file"]}"
  end
  def private_key_remote_store_path
    site_cert = self.site_cert
    "#{self.full_site_path}/ssl_certs/#{site_cert.id}/#{site_cert["private_key"]}"
  end
  def get_path
    return self.path.to_s.gsub(" ","\\ ")
  end
  def get_site_name
    return self.site_name.to_s.gsub(" ","\\ ")
  end
  def get_domain_name(port=nil)
    scheme = ""
    extra_port = ""
    port = self.get_port if port.nil?
    if port == "443"
      scheme = "https://"
    else
      scheme = "http://"
      if port != "80"
        extra_port = ":#{port}"
      end
    end
    return (scheme + self.domain_name.split(" ").first + extra_port)
  end
  def site_server
    SiteServer.where(server_name: self.server_type).first
  end
end