#!/usr/bin/env python3

# -*- mode: Python; encoding: utf-8; indent-offset: 4; autowrap: nil -*-

# (c) Michael Honkoop <mhonkoop@comsolve.nl>

# License: GNU General Public License v2

import sys
import ldap
import re
from cmk_addons.plugins.edirectory_monitor.lib import (
    format_partition_data,
)

def clean_key(key):
    """Clean and format the key by removing unwanted parts."""
    cleaned_key = ' '.join(key.split(',')[::-1]).replace('cn=Monitor', '').replace('cn=', '').strip()
    return cleaned_key

def clean_value(value):
    """Clean and format the values by removing unwanted parts."""
    cleaned_value = re.sub(' Bytes| KB| MB| ms', '', value)
    return cleaned_value

def print_sections(raw_result):
    separator = 124 # '|';
    lines = []
    def process_item(item):
        """Process an individual item in the raw result."""
        if isinstance(item, list):
            for sub_item in item:
                process_item(sub_item)
        elif isinstance(item, dict):
            for key, value in item.items():
                if isinstance(value, list):
                    value_str = chr(separator).join(value)  # Preserve list information by joining elements
                else:
                    value_str = value
                lines.append(f"{key}={value_str}")
        else:
            if "BackGroundProcInterval" not in str(item):  # Skip irrelevant sections
                lines.append(str(item))
    
    for each_item in raw_result:
        if isinstance(each_item, list):
            print_sections(each_item)  # Recursive call for nested lists
        elif isinstance(each_item, tuple) and len(each_item) == 2:
            dn, attributes = each_item
            if "BackGroundProcInterval" in dn:
                continue  # Skip irrelevant DNs
            lines.append(clean_key(dn))
            for key, value in attributes.items():
                if key == "objectclass":
                    continue  # Skip objectclass attribute
                if isinstance(value, list):  # Handle list values
                    for item in value:
                        try:
                            decoded_value = item.decode("utf-8")
                            if len(decoded_value) != 0:
                                lines.append(f"{key}={clean_value(decoded_value)}")
                        except AttributeError:
                            if len(item) != 0:
                                lines.append(f"{key}={clean_value(item)}")
                else:  # Handle scalar values
                    try:
                        decoded_value = value.decode("utf-8")
                        if len(decoded_value) != 0:
                            lines.append(f"{key}={clean_value(decoded_value)}")
                    except AttributeError:
                        if len(item) != 0:
                            lines.append(f"{key}={clean_value(value)}")
        else:
            process_item(each_item)
    
    if lines:
        print(chr(separator).join(lines))

def main():
    args = sys.argv[1:]
    if len(args) < 3:
        print("Usage: script.py <LDAP_URI> <BIND_DN> <PASSWORD>")
        sys.exit(1)

    ldap_uri = args[0]
    binddn = args[1] 
    pw = args[2]
    basedn = "cn=Monitor"
    searchFilter = "(objectClass=*)"
    searchAttribute = ["*"]
    searchScope = ldap.SCOPE_SUBTREE

    try:
        # ignore TLS certificate checking
        ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
        # Create LDAPObject instance with given uri
        l = ldap.initialize(ldap_uri)
        # Set LDAP protocol version used
        l.protocol_version = ldap.VERSION3
    except ldap.LDAPError as e:
        print(f"Failed to initialize LDAP connection: {e}")
        sys.exit(1)

    try:
        # Attempt to bind with given credentials
        l.simple_bind_s(binddn, pw)
    except ldap.INVALID_CREDENTIALS:
          print("Authentication to the LDAP host has failed.")
          sys.exit(1)
    except ldap.LDAPError as e:
        print(f"LDAP error during bind: {e}")
        sys.exit(1)

    try:
        ldap_result_id = l.search(basedn, searchScope, searchFilter, searchAttribute)
        result_set = []

        while True:
            result_type, result_data = l.result(ldap_result_id, 0)
            if (result_data == []):
                break
            elif result_type == ldap.RES_SEARCH_ENTRY:
                result_set.append(result_data)

        print('<<<edirectory_monitor:sep(124)>>>')
        for i in range(len(result_set)):
            print_sections(result_set[i])

    except ldap.LDAPError as e:
        print(f"LDAP search failed: {e}")

    finally:
        l.unbind_s()

if __name__ == "__main__":
    main()

