# == Schema Information
#
# Table name: wired_configs
#
#  id                    :integer          not null, primary key
#  name                  :string(255)
#  mode                  :string(255)      default("0")
#  nat                   :string(255)      default("1")
#  is_enabled            :boolean          default(TRUE)
#  location_network_id   :integer
#  acl_mac               :string(255)
#  mac_filter_policy     :string(255)
#  acl_mac_list          :text
#  captive_portal        :string(255)
#  splash_url            :text
#  wallgarden            :string(255)
#  walled_garden_range   :text
#  overwrite_success_url :string(255)      default("false")
#  success_url           :text
#  dhcp_range_start      :string(255)
#  dhcp_range_end        :string(255)
#  dhcp_relay_server     :string(255)
#  dhcp_lease_time       :string(255)
#  auth_radius_id        :string(255)
#  acc_radius_id         :string(255)
#  acc_radius_enabled    :string(255)
#  ip_address            :string(255)
#  subnet_mask           :string(255)
#  ssid_qos              :string(255)
#  enable_ssid_qos       :boolean
#  per_user_qos          :string(255)
#  max_association       :integer          default(0)
#  created_at            :datetime
#  updated_at            :datetime
#  dns_mode              :string(255)      default("1")
#  dns_primary           :string(255)
#  dns_secondary         :string(255)
#  wna                   :string(255)      default("0")
#  dhcp_mappings         :text(2147483647)
#  default_interim_time  :string(255)      default("300")
#  default_idle_timeout  :string(255)      default("1800")
#

class WiredConfig < ActiveRecord::Base
  include AssociatedResource #ConfigMapping Association and its methods (app/models/concerns/associated_resource.rb)
  include RedisWrapper
  include PublicActivity::Model

  tracked owner: ->(controller, model) { controller && controller.tracked_current_user },params: { :attributes  => proc {|controller, model_instance| { "wired_config(#{model_instance.name})" => model_instance.changes}}},organisation_id: ->(controller, model) { controller && controller.tracked_current_user.try(: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}

  serialize :dhcp_mappings, Array
  serialize :dhcp_ranges, Array
  serialize :port_configs, Array
  belongs_to :location_network
  belongs_to :v_lan
  has_and_belongs_to_many :v_lans, join_table: :wired_configs_v_lans
  accepts_nested_attributes_for :v_lans, allow_destroy: true
  validates :check_firmware_version,presence: true

  after_update do |ssid|
    ssid.update_redis
  end

  after_create do |x|
    x.update_redis
  end

  after_destroy do |x|
    if x.location_network.is_openwifi?
      x.update_redis
      redis_del "wc#{x.id}"
    else
      wired_config = x.router_inventories.map{|inv| inv.device_wired_config(inv.location_network)}
      ln = x.location_network
      unless ln.wired_configs.any?
        ClientCommunication.where("firewall_config_id in (?) and (source_interface = ? or destination_interface = ?)", ln.firewall_configs.pluck(:id),'-1','-1').each(&:destroy)
      end
      redis_del "wc#{x.id}"
      unless location_network.blank?
        location_network.router_inventories.each(&:update_redis)
      end
    end
  end

  before_save do |ssid|
    ssid.acl_mac_list = ssid.acl_mac_list.try(:upcase)
    (self.dhcp_mappings || []).each_with_index{|a,index| self.dhcp_mappings.delete_at(index) if (a['IPADDR'] == '' || a['MAC'] == '')}
  end

  before_save do |x|
    x.port_configs.each do |pc|
      pc["TAG"] = pc["TAG"].to_i if pc["TAG"].present?
      pc["VID"] = [pc['PVID']] if pc["VID"].blank?
      pc["DISABLE"] = pc["DIS"].to_i unless pc["DIS"].blank?
    end
    x.v_lan_ids = x.get_configured_vlans
  end 

  # before_save do |check_firmware|

  # end  

  def applied_router_inventories
    ris = self.router_inventories
    lns = self.location_networks
    routers = RouterInventory.where(location_network_id: lns.pluck(:id)) + ris

    routers
  end

  def update_redis
    redis_set "wc#{self.id}", redis_config
    ris = self.router_inventories
    lns = self.location_networks
    routers = RouterInventory.where(location_network_id: lns.pluck(:id)) + ris
    #remove previous config association
    cms = ConfigMapping.arel_table
    ConfigMapping.where( configurable_type: "WiredConfig", resourceable_type: 'RouterInventory', resourceable_id: ris.pluck(:id) ).where(cms[:configurable_id].not_eq(self.id)).each(&:destroy)
    ConfigMapping.where( configurable_type: "WiredConfig", resourceable_type: 'LocationNetwork', resourceable_id: lns.pluck(:id) ).where(cms[:configurable_id].not_eq(self.id)).each(&:destroy)

    (routers.uniq || []).each { |y| y.update_redis }
  end

  def redis_config
    vlan = self.v_lans.first || self
    radius_auth_server = RadiusConfiguration.find_by_id(vlan.auth_radius_id)
    radius = {}
    unless radius_auth_server.blank?
      radius["AUTH_SERVER"] = radius_auth_server.radius_ip
      radius["AUTH_PORT"] = radius_auth_server.radius_port
      radius["AUTH_SECRET"] = radius_auth_server.radius_secret
    end
    radius_auth_server = RadiusConfiguration.find_by_id(vlan.acc_radius_id)
    unless radius_auth_server.blank?
      radius["ACCT_SERVER"] = radius_auth_server.radius_ip
      radius["ACCT_PORT"] = radius_auth_server.radius_port
      radius["ACCT_SECRET"] = radius_auth_server.radius_secret
    end
    return {"WIRED_UNIQ_ID" => self.uniq_identifier,
            "NAT" => vlan.nat.to_i,
            "WNA" => vlan.wna.to_i,
            "NAME" => self.name,
            "PROTO" => "static",
            "IPADDR" => vlan.ip_address,
            "NETMASK" => vlan.is_a?(VLan) ? vlan.net_mask : vlan.subnet_mask,
            "QOS" => {"BW_ENABLE" => self.enable_ssid_qos? ? 1 : 0,
                      "BW"=> "#{self.ssid_qos.to_i}"},
            "SECURITY" => radius,
            "DHCP" => { "LEASE_TIME" => vlan.dhcp_lease_time,
                        "DHCP_ENABLE"=> vlan.dhcp_relay_server,
                        "RANGE_START" => (["1","3"].include?vlan.dhcp_relay_server) ? "" : vlan.dhcp_ranges.blank? ? "" : vlan.dhcp_ranges.first['START'],
                        "RANGE_END" => vlan.dhcp_ranges.blank? ? "" : vlan.dhcp_ranges.first['END'],
                        "MAPPINGS" => vlan.dhcp_mappings,
                        "RANGES" => vlan.dhcp_ranges},
            "CAPTIVE_PORTAL" => { "PORTAL_ENABLE" => (vlan.captive_portal).to_i,
                                  "PORTAL_REDIR_URL" => vlan.splash_url,
                                  "MAC_AUTH" => vlan.is_a?(VLan) ? vlan.mac_auth : 0,
                                  "WL_ENABLE" => (vlan.wallgarden).to_i,
                                  "WL_CONFIG" => (vlan.walled_garden_range.blank? ? [] : vlan.walled_garden_range.split(",")),
                                  "QOS" => {"BW_ENABLE" => vlan.per_user_qos.to_i == 0 ? 0 : 1,
                                            "BW"=> "#{vlan.per_user_qos.to_i}"},
                                            "DEF_INT_UPDATE_INTV" => vlan.default_interim_time,"DEF_IDLE_TO" => vlan.default_idle_timeout
                                            },
            "DNS" => {"MODE" => vlan.dns_mode, "PRI_DNS" => (vlan.is_a?(VLan) ? vlan.dns1.to_s : vlan.dns_primary), "SEC_DNS" => (vlan.is_a?(VLan) ? vlan.dns2.to_s : vlan.dns_secondary)}}.to_json
  end

  def apply_to_network?
    config_mappings.where(resourceable: location_network).any?
  end

  def self.grouped_collection_of_ap_and_tags network, wired_config=nil
    hash = {}
    ris = network.router_inventories
    #Dont show ap/network in collection if is has wired config already
    ris_config = ConfigMapping.where( configurable_type: "WiredConfig", resourceable_type: 'RouterInventory', resourceable_id: ris.map(&:id) ).pluck(:resourceable_id)
    ris_config -= wired_config.router_inventories.pluck(:id) unless wired_config.blank?
    hash["Router Inventory"] = (ris.uniq - RouterInventory.find_all_by_id(ris_config)).map {|ri| ["#{ri.name.present? ? (ri.name + " (#{ri.mac_id.last(8)})") : ri.mac_id}", "AP:#{ri.id}"]}
    network_wired_config = nil
    network_wired_config = wired_config.location_networks unless wired_config.blank?
    hash["Router Inventory"] += [["All", "network:#{network.id}"]] if network_wired_config.present? || network.associated_wired_config.blank?
    hash
  end

  def self.default_wired_config
    {"WIRED_UNIQ_ID"=>0.to_s,"NAT"=>"0".to_i,"WNA" => 0,"NAME"=>"PCC Wired","PROTO"=>"dhcp","IPADDR"=>nil,"NETMASK"=>nil,"SECURITY"=>{"AUTH_SERVER"=>"","AUTH_PORT"=>"","AUTH_SECRET"=>""},"DHCP"=>{"LEASE_TIME"=>0,"RELAY_ENABLE"=>0,"RANGE_START"=>"","RANGE_END"=>"","GATEWAY"=>""},"CAPTIVE_PORTAL"=>{"PORTAL_ENABLE"=>0,"PORTAL_REDIR_URL"=>"", "QOS" => {"BW_ENABLE" => 0, "BW"=> "0"}}, "BAND" => "1", "DNS" => {"MODE" => "1", "PRI_DNS" => nil, "SEC_DNS" => nil}}
  end

  def json_build
    {:id => self.id, :name => self.name, :enable_ssid_qos => self.enable_ssid_qos, :ssid_qos => self.ssid_qos,:custom_port => self.custom_port,:v_lan_ids => self.location_network.v_lans.where(id: self.v_lan_ids).map(&:v_lan_id),:associated_resources => self.associated_resources,:port_configs => self.custom_port == '1' ? [] : self.port_configs}
  end

  def uniq_identifier
    return 'L' + self.id.to_s
  end
  
  def get_configured_vlans
    vlan_ids = Set.new
    self.port_configs.map {|c| vlan_ids += (c["VID"] || []); (vlan_ids << c["PVID"] if c["PVID"].present?) }
    self.location_network.v_lans.where(v_lan_id: vlan_ids.to_a).pluck(:id)
  end

  def check_firmware_version
    if self.custom_port == "3" && !self.location_network.is_openwifi?
      mac_ids = Set.new
      self.config_mappings.each do |r| 
        re = r.resourceable
        mac_ids += (re.is_a?(RouterInventory) ? [re.mac_id] : re.router_inventories.pluck(:mac_id))
      end
      puts "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"
      puts mac_ids.inspect

      mac_ids.each do |mac|
        
        puts '###################################@@@@@@@@@@@@@@@@@######'
        firmware = $redis.hget "AP:#{mac}" ,"version"
        if firmware.present?
          firmware_split = firmware.gsub(".","")
          
          if firmware_split.to_i < "20223".to_i
            puts '###################################@@@@@@@@@@@@############'
            errors.add("firmware_conflict", "For the Custom switch Only the AP having firmware version 2.0.2.23 and greater will work in this functionality")
            return false

          end
        end
      end  
    end    

  end  
end

