# (C) Fractal Industries, Inc. 2016
# (C) Datadog, Inc. 2010-2016
# All rights reserved
# Licensed under Simplified BSD License (see LICENSE)

# std
from collections import defaultdict
from functools import wraps

# 3rd party
from pysnmp.entity.rfc3413.oneliner import cmdgen
import pysnmp.proto.rfc1902 as snmp_type
from pysnmp.smi import builder
from pysnmp.smi.exval import noSuchInstance, noSuchObject
from pysnmp.error import PySnmpError

# project
from checks.network_checks import NetworkCheck, Status
from config import _is_affirmative



# Additional types that are not part of the SNMP protocol. cf RFC 2856
(CounterBasedGauge64, ZeroBasedCounter64) = builder.MibBuilder().importSymbols(
    "HCNUM-TC",
    "CounterBasedGauge64",
    "ZeroBasedCounter64")

# Metric type that we support
SNMP_COUNTERS = frozenset([
    snmp_type.Counter32.__name__,
    snmp_type.Counter64.__name__,
    ZeroBasedCounter64.__name__])

SNMP_GAUGES = frozenset([
    snmp_type.Gauge32.__name__,
    snmp_type.Unsigned32.__name__,
    CounterBasedGauge64.__name__,
    snmp_type.Integer.__name__,
    snmp_type.Integer32.__name__])

DEFAULT_OID_BATCH_SIZE = 10


def reply_invalid(oid):
    return noSuchInstance.isSameTypeWith(oid) or \
        noSuchObject.isSameTypeWith(oid)


class SnmpCheck(NetworkCheck):

    SOURCE_TYPE_NAME = 'system'
    # pysnmp default values
    DEFAULT_RETRIES = 5
    DEFAULT_TIMEOUT = 1
    SC_STATUS = 'snmp.can_check'

    def __init__(self, name, init_config, agentConfig, instances):
        for instance in instances:
            if 'name' not in instance:
                instance['name'] = self._get_instance_key(instance)
            instance['skip_event'] = True

        self.generators = {}

        # Set OID batch size
        self.oid_batch_size = int(init_config.get("oid_batch_size", DEFAULT_OID_BATCH_SIZE))

        # Load Custom MIB directory
        self.mibs_path = None
        self.ignore_nonincreasing_oid = False
        if init_config is not None:
            self.mibs_path = init_config.get("mibs_folder")
            self.ignore_nonincreasing_oid = _is_affirmative(
                init_config.get("ignore_nonincreasing_oid", False))

        NetworkCheck.__init__(self, name, init_config, agentConfig, instances)

    def _load_conf(self, instance):
        tags = instance.get("tags", [])
        ip_address = instance["ip_address"]
        metrics = instance.get('metrics', [])
        timeout = int(instance.get('timeout', self.DEFAULT_TIMEOUT))
        retries = int(instance.get('retries', self.DEFAULT_RETRIES))
        enforce_constraints = _is_affirmative(instance.get('enforce_mib_constraints', True))