# == Schema Information
#
# Table name: acl_groups
#
#  id                  :integer          not null, primary key
#  group_name          :string(255)
#  organisation_id     :integer
#  router_inventory_id :integer
#  location_network_id :integer
#  created_at          :datetime
#  updated_at          :datetime
#  tagging_lists       :text
#

class AclGroup < ActiveRecord::Base
  resourcify
  include AssociatedResource
  include RedisWrapper
  include PublicActivity::Model
  LOGGING_TYPE = {'1' => 'Log All the ACLs','2' => 'Log Only Deny ACLs', '3' => 'Log Only Accept ACLs', '4' => 'Log as per ACL logging', '5' => 'Log Disabled'}
  tracked owner: ->(controller, model) { controller && controller.tracked_current_user },params:
  { :attributes => proc {|controller, model_instance| { "acl_group(#{model_instance.group_name})" => model_instance.changes}}},organisation_id: ->(controller, model) { controller && controller.tracked_current_user.organisation_id },:location_network_id => proc {|controller, model_instance|model_instance.location_network_id}

  tracked assumed_by: proc {|controller, model| controller.user_assumed_by if controller}
  validates :group_name, presence: true
  has_many :access_control_lists
  belongs_to :organisation
  belongs_to :location_network
  accepts_nested_attributes_for :access_control_lists, :allow_destroy => true
  has_many :acl_inventories, :dependent => :destroy
  has_many :router_inventories_old, :through => :acl_inventories
  has_many :access_control_list_layer_nines
  accepts_nested_attributes_for :access_control_list_layer_nines, :allow_destroy => true  
  # after_save :update_tagging_lists

  # def update_tagging_lists
  #   self.tagging_lists =
  # end
  def update_redis
    unless self.blank?
      set_redis
      lns = self.location_networks
      tags = self.tags.map(&:name)
      routers =  RouterInventory.where(location_network_id: lns.pluck(:id)) + RouterInventory.tagged_with(tags)  + self.router_inventories
      (routers.uniq || []).each{|x| x.update_redis}
    end
  end

  def set_log_level rule
     return 1 if self.logging == "1"
     return (rule.policy.to_i == 0) ? 1 : 0 if self.logging == "2"
     return (rule.policy.to_i == 1) ? 1 : 0 if self.logging == "3"
     return  rule.log ? 1 : 0 if self.logging == "4"
     return  0 if self.logging == "5"
     return rule.log.eql?(true) ? 1 : 0
  end

  def set_redis
    return if  self.access_control_lists.blank? && self.access_control_list_layer_nines.blank?
    acl = []
    self.access_control_lists.each do |x|
        next if x.is_enabled.eql?(false)
        if ((x.protocol) == "TCP and UDP")
          protocols_arr = ["TCP","UDP"]
          protocols_arr.each do |protocol|
            acl << {"PROTO"=> protocol,"SRC_IPADDR"=>x.src_ip.try(:split,",").try(:first).try(:strip),"SRC_BITMASK"=>x.scr_bitmask,"SRC_PORT"=>x.src_port,"SRC_LIST"=>x.src_ip,"SRC_MAC"=>x.src_mac,"DST_LIST"=>x.dst_ip,"DST_IPADDR"=>x.dst_ip.try(:split,",").try(:first).try(:strip),"DST_BITMASK"=>x.dst_bitmask,"DST_PORT"=>x.dst_port,"POLICY"=>x.policy.to_i,"SRC_UL_MODE" => AccessControlList::SRC_INTERFACE_TYPES_ARR.index(x.src_uplink_type).to_s,"DST_UL_MODE" => AccessControlList::SRC_INTERFACE_TYPES_ARR.index(x.dst_uplink_type).to_s, "LOG" => self.set_log_level(x)}.to_json
          end
        else
          acl << {"PROTO"=> x.protocol,"SRC_IPADDR"=>x.src_ip.try(:split,",").try(:first).try(:strip),"SRC_BITMASK"=>x.scr_bitmask,"SRC_PORT"=>x.src_port,"SRC_LIST"=>x.src_ip,"SRC_MAC"=>x.src_mac,"DST_LIST"=>x.dst_ip,"DST_IPADDR"=>x.dst_ip.try(:split,",").try(:first).try(:strip),"DST_BITMASK"=>x.dst_bitmask,"DST_PORT"=>x.dst_port,"POLICY"=>x.policy.to_i,"SRC_UL_MODE" => AccessControlList::SRC_INTERFACE_TYPES_ARR.index(x.src_uplink_type).to_s,"DST_UL_MODE" => AccessControlList::SRC_INTERFACE_TYPES_ARR.index(x.dst_uplink_type).to_s, "LOG" => self.set_log_level(x)}.to_json
        end
    end
    acll7 =[]
    self.access_control_list_layer_nines.each do |x|
      if x.application == "All"
        app = "0"
      else
        if x.application_value == "All"
          arr = []
          val = AccessControlList::APP_HSH[x.application]
          if val.present?
            val = val.reject{|i| i == "All"}
            val.each { |i| arr << AccessControlList::ACL[i] }
            res = arr.join('_')
            app = res
          end
        else
          app = AccessControlList::ACL[x.application_value].to_s
        end
      end
      acll7 << {"POLICY"=>x.policy_ly7.to_i,"SRC_IPADDR"=>x.src_ip.try(:split,",").try(:first).try(:strip),"SRC_BITMASK"=>x.src_bitmaskly7,"SRC_DOMAIN"=>x.src_domainly7, "DST_UL_MODE" => AccessControlList::SRC_INTERFACE_TYPES_ARR.index(x.src_uplink_typely7).to_s,"APPLICATION" => app}.to_json
    end     
    redis_set "acl#{self.id}", acl.to_json unless acl.blank?
    redis_set "acll7:#{self.id}", acll7.to_json unless acll7.blank?
  end

  after_create do |x|
    x.update_redis
  end

  after_update do |x|
    x.update_redis
  end

  after_destroy do |x|
    redis_del "acl#{x.id}"
    redis_del "acll7:#{x.id}"
  end

  def json_build
    acls = []
    access_control_lists.each do |a|
      acls << a.json_build
    end
    {id: self.id, group_name: self.group_name, organisation_id: self.organisation_id, associated_resources: self.associated_resources, access_control_lists: acls}
  end

  def self.aps_inventory_tags(org)
    aps = self.inventory(org)
    networks = org.location_networks.where('network_name IS NOT NULL') rescue []
    tag_list = []; network_list = []; ap_list = []
    (aps || []).each do |x|
      next if x.mac_id.blank?
      ap_list << {"id"=>x.id.to_s+"--inventory", "name"=>x.mac_id}
      x.tag_list.each {|y| tag_list << {"id"=>y+"--tag_list", "name"=>y} }
    end
    (networks || []).each do |y|
      next if y.network_name.blank?
      network_list << {"id"=>y.id.to_s+"--network_name", "name"=>y.network_name}
    end
    return tag_list.flatten.uniq+network_list+ap_list
  end

  def self.inventory(org)
    org.router_inventories.where('mac_id IS NOT NULL') rescue []
  end

  def self.get_inventories(org)
    aps = self.inventory(org)
    return self.aps_lists(aps,false)
  end

  def self.aps_lists(aps,allow_tags)
    ap_list =[]
    (aps || []).each do |x|
      next if x.mac_id.blank?
      if allow_tags
        (x.tag_list || []).each { |tag| ap_list << {"id"=>tag+"--tag", "name"=>tag} }
        ap_list << {"id"=>x.id.to_s+"--inventory", "name"=>x.mac_id} if x.tag_list.blank?
      else
        ap_list << {"id"=>x.id.to_s+"--inventory", "name"=>x.mac_id}
      end
    end
    ap_list.uniq
  end

  def self.get_all_aps(current_network)
    ap_list =[]
    aps = current_network.router_inventories.where('mac_id IS NOT NULL') rescue []
    (aps || []).each do |x|
      next if x.mac_id.blank?
      (x.tag_list || []).each { |tag| ap_list << {"id"=>tag+"--tag", "name"=>tag} }
      ap_list << {"id"=>x.id.to_s+"--inventory", "name"=>x.mac_id}
    end
    ap_list.uniq
  end
  def self.get_routers(current_network)
    aps = current_network.router_inventories.where('mac_id IS NOT NULL') rescue []
    return self.aps_lists(aps,true)
  end

end
