<?php
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
// PDF creator     +++++++++++++++++++++++++++++++++++++++
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
// include autoloader
require_once dirname(__FILE__).'/dompdf/autoload.inc.php'; 
// reference the Dompdf namespace
use Dompdf\Dompdf;
// instantiate and use the dompdf class
use Dompdf\Options;

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Generated PDF          ++++++++++++++++++++++++++++++++
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
function generatedPDF($input,$historyID,$email){
  $options = new Options();
  $options->set('isRemoteEnabled', true);
  $dompdf = new Dompdf($options);
  $dompdf->loadHtml($input);
  
  // (Optional) Setup the paper size and orientation
  $dompdf->setPaper('A4', 'portrait');
  // Render the HTML as PDF
  $dompdf->render();
  $attachment = $dompdf->output();
  
  $to = $email;
  $subject = 'Servicereport -'.$historyID;
  $message = $input;
  $attachment_name = 'Servicereport -'.$historyID.'.pdf';
  //Send email
  if (!empty($email)){
  send_mail($to, $subject, $message, $attachment, $attachment_name);
  }
}
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
// include PHP Mailer
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
require dirname(__FILE__).'/mail/PHPMailer.php';
require dirname(__FILE__).'/mail/SMTP.php';
require dirname(__FILE__).'/mail/Exception.php';
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Send Mail via PHPMailer++++++++++++++++++++++++++++++++
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
function send_mail($to, $subject, $message, $attachment, $attachment_name){

  include_once dirname(__FILE__,2).'/settings/config_redirector.php';

  $mail = new PHPMailer();
  $mail->CharSet = 'UTF-8';
  $mail->isSMTP(); // Use SMTP protocol
  $mail->Host = email_host_name; // Specify  SMTP server
  $mail->SMTPAuth = true; // Auth. SMTP
  $mail->Username = email; // Mail who send by PHPMailer
  $mail->Password = email_outgoing_pw; // your pass mail box
  $mail->SMTPSecure = email_outgoing_security; // Accept SSL
  $mail->Port = email_outgoing_port; // port of your out server
  $mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS;
  $mail->setFrom(email, mail_from); // Mail to send at
  $mail->addAddress($to); // Add sender
  $mail->addReplyTo(email_reply_to); // Adress to reply
  $mail->isHTML(true); // use HTML message
  $mail->Subject = $subject;
  $mail->Body = $message;
  
  /* +++++++++++ //
  // DEBUG MODE  //
  // +++++++++++ //
    $mail->SMTPDebug = 4;  // Or higher if needed
    $mail->Debugoutput = function($str, $level) {
      debuglog($str);  // Your custom logger
    };
  // +++++++++++ //
  // +++++++++++ */
  
  if (!empty($attachment) || $attachment != ''){
    $mail->AddStringAttachment($attachment, $attachment_name, 'base64', 'application/pdf');
  }

  // SEND
  if( !$mail->send() ){
      // render error if it is
      $tab = array('error' => 'Mailer Error: '.$mail->ErrorInfo );
      debuglog(json_encode($tab));
      exit;
  }
  else{
      // return true if message is send
      return true;
  }

}

//------------------------------------------
// Global functions
//------------------------------------------
function dbConnect($dbcon) {

    include dirname(__FILE__,2).'/settings/settings_redirector.php';

    try {
        // Connect to the MySQL database using the PDO interface
    	$pdo = new PDO('mysql:host=' . $db . ';dbname=' . $dbcon . ';charset=utf8', $dbuser, $dbpw);
        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        return $pdo;
    } catch (PDOException $exception) {
    	// Could not connect to the MySQL database! If you encounter this error, ensure your db settings are correct in the config file!
    	exit('Failed to connect to database!');
    }
}
//------------------------------------------
// Determine URL function
//------------------------------------------
function url($url) {
    if (rewrite_url) {
        $url = preg_replace('/\&(.*?)\=/', '/', str_replace(['index.php?page=', 'index.php'], '', $url));
    }
    return base_url . $url;
}
//------------------------------------------
// Routing function
//------------------------------------------
function routes($urls) {
    foreach ($urls as $url => $file_path) {
        $url = '/' . ltrim($url, '/');
        $prefix = dirname($_SERVER['PHP_SELF']);
        $uri = $_SERVER['REQUEST_URI'];
        if (substr($uri, 0, strlen($prefix)) == $prefix) {
            $uri = substr($uri, strlen($prefix));
        }
        $uri = '/' . ltrim($uri, '/');
        $path = explode('/', parse_url($uri)['path']);
        $routes = explode('/', $url);
        $values = [];
        foreach ($path as $pk => $pv) {
            if (isset($routes[$pk]) && preg_match('/{(.*?)}/', $routes[$pk])) {
                $var = str_replace(['{','}'], '', $routes[$pk]);
                $routes[$pk] = preg_replace('/{(.*?)}/', $pv, $routes[$pk]);
                $values[$var] = $pv;
            }
        }
        if ($routes === $path && rewrite_url) {
            foreach ($values as $k => $v) {
                $_GET[$k] = $v;
            }
            return file_exists($file_path) ? $file_path : 'dashboard.php';
        }
    }
    if (rewrite_url) {
        header('Location: ' . url('index.php'));
        exit;
    }
    return null;
}

//------------------------------------------
// Menu Builder
//------------------------------------------
function filterMenuByProfile($menu, $profileString) {
  // Convert profile string to array
  $profileArray = explode(',', $profileString);
  
  // Initialize result array
  $filteredMenu = [];
  
  // Loop through main menu sections
  foreach ($menu as $sectionKey => $section) {
      $sectionIncluded = in_array($sectionKey, $profileArray);
      $submenuFound = false;
      $firstSubmenuItem = null;
      
      // First check if any submenu items are in profile
      foreach ($section as $itemKey => $item) {
          if ($itemKey !== 'main_menu' && in_array($itemKey, $profileArray)) {
              $submenuFound = true;
              if ($firstSubmenuItem === null) {
                  $firstSubmenuItem = $item;
              }
          }
      }
      
      // Include this section if either section key or any submenu is in profile
      if ($sectionIncluded || $submenuFound) {
          $filteredMenu[$sectionKey] = [];
          
          // Add main_menu - if section not in profile but submenu found, use first submenu as main_menu
          if (!$sectionIncluded && $submenuFound && $firstSubmenuItem !== null) {
              // Create hybrid main_menu - keep name and icon from original, but use URL and selected from submenu
              $hybridMainMenu = $section['main_menu'];
              $hybridMainMenu['url'] = $firstSubmenuItem['url'];
              $hybridMainMenu['selected'] = $firstSubmenuItem['selected'];
              
              $filteredMenu[$sectionKey]['main_menu'] = $hybridMainMenu;
          } else {
              $filteredMenu[$sectionKey]['main_menu'] = $section['main_menu'];
          }
          
          // Add allowed submenu items
          foreach ($section as $itemKey => $item) {
              if ($itemKey !== 'main_menu' && in_array($itemKey, $profileArray)) {
                  $filteredMenu[$sectionKey][$itemKey] = $item;
              }
          }
      }
  }
  
  return $filteredMenu;
}
function menu($selected,$selected_child){

  include dirname(__FILE__,2).'/settings/settings_redirector.php';

  if(isset($_SESSION['country_code'])){
    $api_file_language = dirname(__FILE__,2).'/settings/translations/translations_'.strtoupper($_SESSION['country_code']).'.php';
    if (file_exists($api_file_language)){   
      include $api_file_language; //Include the code
    }
    else {
      include dirname(__FILE__,2).'/settings/translations/translations_US.php';
    }
  }
  else {
    include dirname(__FILE__,2).'/settings/translations/translations_US.php';
  }  
  
  //Define Menu
  $menu = '';

  //filter the main_menu array based on profile
  $filteredMenu = filterMenuByProfile($main_menu, $_SESSION['profile']);

  foreach ($filteredMenu  as $menu_item){
      //Main Item
      $menu .= '<a href="index.php?page='.$menu_item['main_menu']['url'].'"' . ($selected == $menu_item['main_menu']['selected'] ? ' class="selected"' : '') . '><i class="'.$menu_item['main_menu']['icon'].'"></i>'.ucfirst((${$menu_item['main_menu']['name']} ?? 'not specified')).'</a>';
      
      if (count($menu_item) > 1){
      //SUBMENU
      $menu .= '<div class="sub" ' . ($selected == $menu_item['main_menu']['selected'] ? ' class="selected"' : '') . '>';

      foreach ($menu_item as $key => $item){
          //filter out main_menu
          if($key !='main_menu'){
            $menu .= '<a href="index.php?page='.$item['url'].'"' . ($selected == $item['selected'] ? ' class="selected"' : '') . '><span>&#9724;</span>'.ucfirst((${$item['name']}?? 'not specified')).'</a>';
          }
       }
      $menu .= '</div>';
      }
  }
  return $menu;
}

//------------------------------------------
// Template Header
//------------------------------------------
function template_header($title, $selected = 'assets', $selected_child = 'view') {
    
  $base_url = 'https://'.$_SERVER['SERVER_NAME'].'/';
  $site_name = site_name;
  $site_name_footer = site_name_footer;
  $icon_image = icon_image;
  $admin_links = menu($selected,$selected_child);

  $domain = getDomainName($_SERVER['SERVER_NAME']);
  $custom_css = (file_exists(dirname(__FILE__,2).'/custom/'.$domain.'/style/'.$domain.'.css') ? './custom/'.$domain.'/style/'.$domain.'.css' : './style/admin.css');
  
  $user = ucfirst($_SESSION['username']);
  if (filter_var($user, FILTER_VALIDATE_EMAIL)){
    $user = substr($user, 0, strpos($user, "@"));
  }

  if (isset($_SESSION['id'])){$id = $_SESSION['id'];} else{$id='';}

  if(isset($_SESSION['country_code'])){
    $api_file_language = dirname(__FILE__,2).'/settings/translations/translations_'.strtoupper($_SESSION['country_code']).'.php';
    if (file_exists($api_file_language)){   
        include $api_file_language; //Include the code
    }
    else {
        include dirname(__FILE__,2).'/settings/translations/translations_US.php';
    }
    }
    else {
        include dirname(__FILE__,2).'/settings/translations/translations_US.php';
    }  

    $profile = $general_profile;
    $logout = $general_logout;

    $veliti_analytics = '';
    if (veliti_analytics){
      $veliti_analytics = '<script src="./assets/analytics.js"></script>';
    } 

echo <<<EOT
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width,minimum-scale=1">
		<title>$title</title>
        <link rel="icon" type="image/png" href="$icon_image">
		<link href="$custom_css" rel="stylesheet" type="text/css">
    <link rel="stylesheet" href="./style/leaflet.css" />
    <link href="./assets/fontawesome/css/fontawesome.css" rel="stylesheet" />
    <link href="./assets/fontawesome/css/brands.css" rel="stylesheet" />
    <link href="./assets/fontawesome/css/solid.css" rel="stylesheet" />
    <script src="./assets/leaflet.js"></script>
    <script src="./assets/charts.js"></script>
    <script>
        // Wait for DOM to be ready before accessing elements
        document.addEventListener('DOMContentLoaded', function() {
            // Get loading screen element
            const loadingScreen = document.getElementById('loadingScreen');
            
            // Only proceed if the element exists
            if (!loadingScreen) {
                console.error('Loading screen element not found!');
                return;
            }
            
            // Show loading screen
            function showLoading() {
                loadingScreen.classList.add('active');
            }
            
            // Hide loading screen
            function hideLoading() {
                loadingScreen.classList.remove('active');
            }
            
            // Show loading when page initially loads
            showLoading();
            
            // Hide loading when everything is loaded
            window.addEventListener('load', hideLoading);
            
            // In case the page loads very quickly
            setTimeout(hideLoading, 500);
            
            // Intercept form submissions
            setupFormInterception();
            
            // Intercept fetch and XMLHttpRequest
            interceptNetworkRequests();
          
            
            // Intercept all form submissions
            function setupFormInterception() {
                const forms = document.querySelectorAll('form');
                
                forms.forEach(form => {
                    form.addEventListener('submit', function(e) {
                        // Show loading screen before form submission
                        showLoading();
                    });
                });
            }
            
            // Intercept all network requests (fetch and XMLHttpRequest)
            function interceptNetworkRequests() {
                // Track active requests
                let activeRequests = 0;
                
                // Intercept fetch API
                const originalFetch = window.fetch;
                window.fetch = function() {
                    showLoading();
                    activeRequests++;
                    
                    return originalFetch.apply(this, arguments)
                        .then(response => {
                            activeRequests--;
                            if (activeRequests === 0) hideLoading();
                            return response;
                        })
                        .catch(error => {
                            activeRequests--;
                            if (activeRequests === 0) hideLoading();
                            throw error;
                        });
                };
                
                // Intercept XMLHttpRequest
                const originalXHROpen = XMLHttpRequest.prototype.open;
                const originalXHRSend = XMLHttpRequest.prototype.send;
                
                XMLHttpRequest.prototype.open = function() {
                    return originalXHROpen.apply(this, arguments);
                };
                
                XMLHttpRequest.prototype.send = function() {
                    showLoading();
                    activeRequests++;
                    
                    this.addEventListener('loadend', function() {
                        activeRequests--;
                        if (activeRequests === 0) hideLoading();
                    });
                    
                    return originalXHRSend.apply(this, arguments);
                };
            }
        });
    </script>
    $veliti_analytics
	</head>
	<body class="admin">
      <!-- Loading Bar -->
      <div class="loading-container" id="loadingScreen">
          <div class="loading-bar">
              <div class="progress"></div>
          </div>
          <div class="loading-text">Loading, please wait...</div>
      </div>
        <aside class="responsive-width-100 responsive-hidden">
            <h1></h1>
            $admin_links
            <div class="footer">
            $site_name_footer
            </div>
        </aside>
        <main class="responsive-width-100">
            <header>
                <a class="responsive-toggle" href="#">
                    <i class="fas fa-bars"></i>
                </a>
                <div class="space-between"></div>
                <div class="dropdown right">
                    <div>
                      <i class="fas fa-user-circle"></i>
                      $user
                    </div>
                    <div class="list">
                        <a href="index.php?page=profile">$profile</a>
                        <a href="index.php?page=logout">$logout</a>
                    </div>
                </div>
            </header>
EOT;
}
//------------------------------------------
// Template footer
//------------------------------------------
function template_footer($js_script = '') {
        $js_script = $js_script ? '<script>' . $js_script . '</script>' : '';
        $lancode = $_SESSION['language'] ?? 'US';
        $user_mail = $_SESSION['email'] ?? '';
        $veliti_cim = '';
        if (veliti_cim){
          $veliti_cim = '
          <button id="support_btn" class="btn" style="opacity: 0.8;position: fixed;bottom: 23px;right: 28px;background:#4a79b400;font-size:36px;z-index:999;" onclick="openForm()"><img src="./assets/images/tss-persoon.svg" alt="tss-persoon" height="115"></button>
          <div class="form-popup" id="request">
            <iframe src="https://change.veliti.nl/request_popup.php?language='.$lancode.'&email='.$user_mail.'" style="border: solid 1px;border-radius: 5px;min-width:400px;min-height:400px;"></iframe>
          <div class="close">
              <button type="button" style="border: solid 1px;" onclick="closeForm()">X</button>
          </div>
        </div>
        <script>
        function openForm() {
        document.getElementById("request").style.display = "block";
        }

        function closeForm() {
        document.getElementById("request").style.display = "none";
        }
        </script>
        ';
        } 

// DO NOT INDENT THE BELOW CODE
echo <<<EOT
        </main>
        $veliti_cim
        <script src="./assets/admin.js"></script>
        {$js_script}
   
    </body>
</html>
EOT;
}

//------------------------------------------
// Secure Payload
//------------------------------------------
function generate_payload($payload) {

    include dirname(__FILE__,2).'/settings/settings_redirector.php';
	
    $headers = array('alg'=>'HS256','typ'=>'payload');
    $payload = array('payload'=>$payload,'exp'=>(time() + 1200));

    $headers_encoded = base64url_encode(json_encode($headers));
    $payload_encoded = base64url_encode(json_encode($payload));

    $signature = hash_hmac('SHA256', "$headers_encoded.$payload_encoded", $secret, true);
    $signature_encoded = base64url_encode($signature);

    $payload_input = "$headers_encoded.$payload_encoded.$signature_encoded";

    return $payload_input;
}
//------------------------------------------
//ENCRYPT PAYLOAD
//------------------------------------------
function encrypt($input, $password) {

  //CHECK IF INPUT IS ARRAY => THEN SERIALIZE INPUT
  if (is_array($input)){
      $input = serialize($input);
  }

  $method = "AES-256-CBC";
  $key = hash('sha256', $password, true);
  $iv = openssl_random_pseudo_bytes(16);

  $ciphertext = openssl_encrypt($input, $method, $key, OPENSSL_RAW_DATA, $iv);
  $hash = hash_hmac('sha256', $ciphertext . $iv, $key, true);

  return $iv . $hash . $ciphertext;
}


//------------------------------------------
// Decode Payload
//------------------------------------------
function decode_payload($payload_input) {
    include dirname(__FILE__,2).'/settings/settings_redirector.php';
    // split the jwt
    $tokenParts = explode('.', $payload_input);
    $header = base64_decode($tokenParts[0]);
    $payload = base64_decode($tokenParts[1]);
    $signature_provided = $tokenParts[2];

    $expiration = json_decode($payload)->exp;
    $is_token_expired = ($expiration - time()) < 0;

    // build a signature based on the header and payload using the secret
    $base64_url_header = base64url_encode($header);
    $base64_url_payload = base64url_encode($payload);
    $signature = hash_hmac('SHA256', $base64_url_header . "." . $base64_url_payload, $secret, true);
    $base64_url_signature = base64url_encode($signature);

    // verify it matches the signature provided in the jwt
    $is_signature_valid = ($base64_url_signature === $signature_provided);

    if ($is_token_expired || !$is_signature_valid) {
        return FALSE;
    } else {
            $tokenParts = explode('.', $payload_input);
            $payload = base64_decode($tokenParts[1]);
            return $payload_decoded = json_decode($payload)->payload;
    }
}
//------------------------------------------
// Decrypt payload
//------------------------------------------
function decrypt($ivHashCiphertext, $password) {
  $method = "AES-256-CBC";
  $iv = substr($ivHashCiphertext, 0, 16);
  $hash = substr($ivHashCiphertext, 16, 32);
  $ciphertext = substr($ivHashCiphertext, 48);
  $key = hash('sha256', $password, true);

  if (!hash_equals(hash_hmac('sha256', $ciphertext . $iv, $key, true), $hash)) return null;

  $decrypted =  openssl_decrypt($ciphertext, $method, $key, OPENSSL_RAW_DATA, $iv);

  //UNSERIALE AND CHECK IF 
  $data = @unserialize($decrypted);
  if ($data !== false) {
      $decrypted = unserialize($decrypted);
  } 

  //RETURN DECRYPTED DATA
  return $decrypted;  
}

function base64url_encode($data) {
    return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}

//------------------------------------------
// JWT Function for CommunicationTOken
//------------------------------------------
function generate_jwt($headers, $payload) {
	
    include dirname(__FILE__,2).'/settings/settings_redirector.php';

    $headers_encoded = base64url_encode(json_encode($headers));
	$payload_encoded = base64url_encode(json_encode($payload));

	$signature = hash_hmac('SHA256', "$headers_encoded.$payload_encoded", $secret, true);
	$signature_encoded = base64url_encode($signature);

	$jwt = "$headers_encoded.$payload_encoded.$signature_encoded";

	return $jwt;
}
function is_jwt_valid($jwt) {

    include dirname(__FILE__,2).'/settings/settings_redirector.php';
	// split the jwt
	$tokenParts = explode('.', $jwt);
	$header = base64_decode($tokenParts[0]);
	$payload = base64_decode($tokenParts[1]);
	$signature_provided = $tokenParts[2];

	$expiration = json_decode($payload)->exp;
	$is_token_expired = ($expiration - time()) < 0;

	// build a signature based on the header and payload using the secret
	$base64_url_header = base64url_encode($header);
	$base64_url_payload = base64url_encode($payload);
	$signature = hash_hmac('SHA256', $base64_url_header . "." . $base64_url_payload, $secret, true);
	$base64_url_signature = base64url_encode($signature);

	// verify it matches the signature provided in the jwt
	$is_signature_valid = ($base64_url_signature === $signature_provided);

	if ($is_token_expired || !$is_signature_valid) {
		return FALSE;
	} else {
		return TRUE;
	}
}

//------------------------------------------
// createCommunicationToken
//------------------------------------------
function createCommunicationToken($input){
    $headers = array('alg'=>'HS256','typ'=>'JWT');
    $payload = array('token'=>$input, 'exp'=>(time() + 2100));
    $token = generate_jwt($headers, $payload);
    return $token;
}

//------------------------------------------
// getUserKey
//------------------------------------------
function getUserKey($jwt){

    include dirname(__FILE__,2).'/settings/settings_redirector.php';
	$tokenParts = explode('.', $jwt);
	$payload = base64_decode($tokenParts[1]);
	$token = json_decode($payload)->token;

	return $token;
}

//------------------------------------------
// get_bearer_token
//------------------------------------------

function get_authorization_header(){
	$headers = null;

	if (isset($_SERVER['Authorization'])) {
		$headers = trim($_SERVER["Authorization"]);
	} else if (isset($_SERVER['HTTP_AUTHORIZATION'])) {
		$headers = trim($_SERVER["HTTP_AUTHORIZATION"]);
	} else if (function_exists('apache_request_headers')) {
		$requestHeaders = apache_request_headers();
		$requestHeaders = array_combine(array_map('ucwords', array_keys($requestHeaders)), array_values($requestHeaders));
		if (isset($requestHeaders['Authorization'])) {
			$headers = trim($requestHeaders['Authorization']);
		}
	}

	return $headers;
}
function get_bearer_token() {
    $headers = get_authorization_header();

    if (!empty($headers)) {
        if (preg_match('/Bearer\s(\S+)/', $headers, $matches)) {
            return $matches[1];
        }
    }
    return null;
}

//------------------------------------------
// APIto/fromServer
//------------------------------------------
function ioServer($api_call, $data){

    include dirname(__FILE__,2).'/settings/settings_redirector.php';
  
    $token = $_SESSION['userkey'] ?? 'authorization_request';
    $bearertoken = createCommunicationToken($token);
        
    $url = $baseurl.$api_call;

    $curl = curl_init($url);
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    
    $headers = array(
            "Authorization: Bearer $bearertoken",
            "Content-Type: application/json",
    );
    
    curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
  
    if (!empty($data)){
        curl_setopt($curl, CURLOPT_POST, true);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
    }

    $resp = curl_exec($curl);
    $http_status = curl_getinfo($curl) ?? '200';
    curl_close($curl);
    
    //Check If errorcode is returned
    if($http_status['http_code'] == '403' || $http_status['http_code'] == '400') {$resp = generate_payload('NOK');}
    
    if (debug){
      $message = $date.';'.$api_call;
      debuglog($message);
    }

    //Response
    return $resp;
}

//------------------------------------------
// API TO API version 1
//------------------------------------------
function ioAPI($api_call, $data, $token){

  include dirname(__FILE__,2).'/settings/settings_redirector.php';

  $bearertoken = createCommunicationToken($token);
      
  $url = $baseurl.$api_call;

  $curl = curl_init($url);
  curl_setopt($curl, CURLOPT_URL, $url);
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  
  $headers = array(
          "Authorization: Bearer $bearertoken",
          "Content-Type: application/json",
  );
  
  curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);

  if (!empty($data)){
      curl_setopt($curl, CURLOPT_POST, true);
      curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
  }

  $resp = curl_exec($curl);
  $http_status = curl_getinfo($curl) ?? '200';
  curl_close($curl);
  
  //Check If errorcode is returned
  if($http_status['http_code'] == '403' || $http_status['http_code'] == '400') {$resp = generate_payload('NOK');}
  
  if (debug){
    $message = $date.';'.$api_call;
    debuglog($message);
  }

  //Response
  return $resp;
}

//------------------------------------------
// API TO API version 2
//------------------------------------------
function ioAPIv2($api_call, $data, $token){

  include dirname(__FILE__,2).'/settings/settings_redirector.php';

  $token = (!empty($token) || $token !='')? $token : 'authorization_request';
  $bearertoken = createCommunicationToken($token);
      
  $url = $baseurl.$api_call;

  $curl = curl_init($url);
  curl_setopt($curl, CURLOPT_URL, $url);
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  
  $headers = array(
          "Authorization: Bearer $bearertoken",
          "Content-Type: application/json",
  );
  
  curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);

  if (!empty($data)){
      curl_setopt($curl, CURLOPT_POST, true);
      curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
  }

  $resp = curl_exec($curl);
  $http_status = curl_getinfo($curl) ?? '200';
  curl_close($curl);

 
  //Check If errorcode is returned
  if($http_status['http_code'] == '403' || $http_status['http_code'] == '400') {$resp = json_encode('NOK');}
  
  if (debug){
    $message = $date.';'.$api_call;
    debuglog($message);
  }

  //Response
  return $resp;
}

//------------------------------------------
// DEFINE WHERECLAUSE BASED ON ACCOUNTHIERARCHY ALL
//------------------------------------------

function getWhereclause($table_name,$permission,$partner,$method){

  //api_name converter to table
  $table =[
    "equipment" => "e.accounthierarchy",
    "products" => "p.accounthierarchy",
    "profile" => "partnerhierarchy",
    "text_variables" => "tv.accounthierarchy",
    "products_attributes_items" => "pat.accounthierarchy",
    "products_attributes_groups" => "pag.accounthierarchy",
    "pricelists" => "pls.accounthierarchy",
    "pricelists_items" => "pli.accounthierarchy"
  ];

  $table = ($table_name != '') ? $table[$table_name] : 'accounthierarchy';
  $type = ($method == 'get') ? 'WHERE ' : ' AND '; 
  //SoldTo is empty
  if (empty($partner->soldto) || $partner->soldto == ''){$soldto_search = '%';} else {$soldto_search = '-%';}

  //default whereclause
  $whereclause = '';

  switch ($permission) {    
      case '4': 
          $whereclause = '';
          break;
      case '3':
          $condition = '__salesid___'.$partner->salesid.'___soldto___%';
          $whereclause = $type.$table.' like "'.$condition.'"';
          break;
      case '2':
          $condition = '__salesid___'.$partner->salesid.'___soldto___'.substr($partner->soldto, 0, strpos($partner->soldto, "-")).$soldto_search;
          $whereclause = $type.$table.' like "'.$condition.'"';
          break;
      default:
          $condition = '__salesid___'.$partner->salesid.'___soldto___'.substr($partner->soldto, 0, strpos($partner->soldto, "-")).$soldto_search.'___shipto___'.substr($partner->shipto, 0, strpos($partner->shipto, "-")).'%___location___'.substr($partner->location, 0, strpos($partner->location, "-")).'%';
          $whereclause = $type.$table.' like "'.$condition.'"';
          break;
  } 

  return array($whereclause,$condition);
}

//------------------------------------------
// DEFINE WHERECLAUSE BASED ON ACCOUNTHIERARCHY SALES AND SOLD
//------------------------------------------
function getWhereclauselvl2($table_name,$permission,$partner,$method){

  //api_name converter to table
  $table =[
    "pricelist" => "pls.accounthierarchy",
    "communications" => "salesID",
    "partners" => "salesID",
    "discounts" => "d.accounthierarchy",
    "invoice" => "inv.accounthierarchy",
    "attributes" => "pat.accounthierarchy",
    "config" => "pc.accounthierarchy",
    "software" => "p.accounthierarchy",
    "transactions" => "tx.accounthierarchy",
    "dealers" => "d.accounthierarchy",
    "categories" => "c.accounthierarchy"
  ];

  $table = ($table_name != '') ? $table[$table_name] : 'accounthierarchy';
  $type = ($method == 'get') ? 'WHERE ' : ' AND '; 
  
  //SoldTo is empty
  if (empty($partner->soldto) || $partner->soldto == ''){$soldto_search = '%';} else {$soldto_search = '-%';}

  //default whereclause
  $whereclause = '';

  switch ($permission) {    
    case '4':
        $whereclause = '';
        break;
    case '3':
        $condition = '__salesid___'.$partner->salesid.'___soldto___%';
        $whereclause = $type.$table.' like "'.$condition.'" ';
        break;  
    default:
        $condition = '__salesid___'.$partner->salesid.'___soldto___'.substr($partner->soldto, 0, strpos($partner->soldto, "-")).$soldto_search;
        $whereclause = $type.$table.' like "'.$condition.'"';
        break;
} 

  return array($whereclause,$condition);
}

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//get user profile||$profile=settings, $permision = userright()
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
function getProfile($profile, $permission){
  
  include_once dirname(__FILE__,2).'/settings/config_redirector.php';

  if ($profile != ''){
      $profile = (defined($profile)) ? constant($profile) : standard_profile;
  }
  else {
    switch ($permission) {
      case '4': //Admin++
      $profile = adminplus_profile;
      break;
      case '3': //Admin
      $profile = admin_profile;
      break;
      case '2': //Super User
      $profile = superuser_profile;
      break;
      default: // Readonly & create&update
      $profile = standard_profile;
      break;
    }
  }
  return $profile;
  }
  
  //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  //Is allowed  (yes=1)++++++++++++++++++++++++++++++++++++++++
  //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  function isAllowed($page,$profile,$permission,$action){    
    
    //Include settingsa
    include dirname(__FILE__,2).'/settings/settings_redirector.php';

    //GET ALLOWED ACTIONS
    $user_permission = ${'permission_'.$permission};
    
    //CHECK ALLOWED
    $page_action = str_contains($user_permission,$action) > 0 ? 1 : 0; //CHECK IF USER IS ALLOWED TODO THE ACTION
    $page_access = str_contains($profile,$page) > 0 ? 1 : 0; //CHECK USER IS ALLOWED TO ACCESS PAGE
    
    //RETURN CODE
    if ($page_access == 1 && $page_action == 1){
        $user_access = 1;
    } else {
        //Not Allowed
        $user_access = 0;
    }
    return $user_access;
  }
  

//------------------------------------------
// userRight standaridazation helper
//------------------------------------------
function userRights($input){
	
// From User assigned view gets allowed data view level 
// Admin and Admin+ = all - levels
// SuperUser = soldto - and lower
// CreateUpdate = shipto and lower
// Read-only = shipto and lower
$permission = '';

	switch ($input) {
		case '1':
			//SuperUser
			$permission = 2;
			break;
		case '2':
			//create & update
			$permission = 1;
			break;
		case '3':
			//read-only
			$permission = 0;
			break;
		case '4':
			//admin
			$permission = 3;
			break;
		case '5':
			//admin
			$permission = 4;
			break;
	}
	return $permission;
}

//------------------------------------------
// Retrieve all $_GET from URL
//------------------------------------------
function urlGETdetails($input){
    //GET Details from URL
    if(isset($input) && !empty($input)){
        $GET_VALUES = '';
        foreach ($input as $KEY => $VALUE){
            $GET_VALUES .= $KEY.'='.$VALUE;
            $GET_VALUES .= '&';
        }
        return $GET_VALUES = rtrim($GET_VALUES, "&");
    } 
    else {
        return $GET_VALUES = '';
    }

}
//------------------------------------------
// Retrieve all $_GET from URL for FILTER AND SORT
//------------------------------------------
function urlGETdetailsFilter($input){
  if(isset($input) && !empty($input)){
    $view = '';
    foreach ($_GET as $key => $value){
      if ($key != 'search'){
      $view .= '<input type="hidden" name="'.$key.'" value="'.$value.'">';
      }
    }
    return $view;
  }
  else {
    return $view = '';
  }
}

//------------------------------------------
// Translate name of Partner
//------------------------------------------
function getPartnerName($str){
    if (!empty($str)){
        $prefix = strtok($str, '-').'-';
        if (str_starts_with($str, $prefix)) {
        $str2 = substr($str, strlen($prefix));
        }
        else {
        $str2 = $str;
        }
        return $str2;  
    }
}

//------------------------------------------
// GET ID of Partner
//------------------------------------------
function getPartnerID($str){
  $partner_id = explode("-",$str) ?? ''; 
  return $partner_id[0];
}

//------------------------------------------
// overview Indicators
//------------------------------------------
function overviewIndicators($warranty, $service, $sw_version, $sw_version_latest){
  include dirname(__FILE__,2).'/settings/settings_redirector.php';
  include dirname(__FILE__,2).'/settings/systemfirmware.php';
  $indicator ='';
  //In warranty
  if (!empty($warranty ) && $warranty > $warrantydate){
    $indicator .= '<span class="dot" style="background-color: #13b368;">W</span>';
  } else {
    $indicator .= '<span class="dot" style="background-color: #eb8a0d;">W</span>';
  }
  //Out of Service
  if (!empty($service) && $service < $servicedate){
    $indicator .= '<span class="dot" style="background-color: #eb8a0d;">S</span>';
  } else {
     $indicator .= '<span class="dot" style="background-color: #13b368;">S</span>';
  }

  //Firmware
  if (isset($sw_version_latest)){   
        if($sw_version_latest == 1){
            $indicator .= '<span class="dot" style="background-color: #13b368;">F</span>';
        } else {
          if ($sw_version == ''){
            $indicator .= '<span class="dot" style="background-color: #81848a">F</span>';
          } else {
            $indicator .= '<span class="dot" style="background-color: #eb8a0d;">F</span>';
          }
        }
  }
    
  return $indicator;
}


//------------------------------------------
// Check service status
//------------------------------------------

function warrantyStatus($input){

    include dirname(__FILE__,2).'/settings/settings_redirector.php';
    //INCLUDE TRANSLATION FILE
    if(isset($_SESSION['country_code'])){
    $api_file_language = dirname(__FILE__,2).'/settings/translations/translations_'.strtoupper($_SESSION['country_code']).'.php';
    if (file_exists($api_file_language)){   
        include $api_file_language; //Include the code
    }
    else {
        include dirname(__FILE__,2).'/settings/translations/translations_US.php';
    }
    }
    else {
        include dirname(__FILE__,2).'/settings/translations/translations_US.php';
    }  

    $warranty_date_due ='<span class="status">Unknown</span>';

    if (!empty($input) && $input < $warrantydate){
        $warranty_date_due = '<span class="status warranty_outdated">'.$warranty_outdated_text.'</span>';
    } else {
        $warranty_date_due ='<span class="status warranty">'.$warranty_recent.' ('.date('Y-m-d', strtotime($input. ' + 365 days')).')</span>';
    }

    return $warranty_date_due;
}

//------------------------------------------
// Check service status
//------------------------------------------

function serviceStatus($input){

    include dirname(__FILE__,2).'/settings/settings_redirector.php';

    //INCLUDE TRANSLATION FILE
    if(isset($_SESSION['country_code'])){
      $api_file_language = dirname(__FILE__,2).'/settings/translations/translations_'.strtoupper($_SESSION['country_code']).'.php';
      if (file_exists($api_file_language)){   
          include $api_file_language; //Include the code
      }
      else {
          include dirname(__FILE__,2).'/settings/translations/translations_US.php';
      }
    }
    else {
        include dirname(__FILE__,2).'/settings/translations/translations_US.php';
    }  

    $service_date_due ='<span class="status">Unknown</span>';

    if (!empty($input) && $input < $servicedate){
        $service_date_due = '<span class="status service_renewal">'.$service_renewal_text.'</span>';
    } else {
        $service_date_due ='<span class="status service">'.$service_recent.' ('.date('Y-m-d', strtotime($input. ' + 365 days')).')</span>';
    }

    return $service_date_due;
}
//------------------------------------------
// Check available firmware
//------------------------------------------

function availableFirmware($sw_version,$sw_version_latest){

  //INCLUDE TRANSLATION FILE
  if(isset($_SESSION['country_code'])){
    $api_file_language = dirname(__FILE__,2).'/settings/translations/translations_'.strtoupper($_SESSION['country_code']).'.php';
    if (file_exists($api_file_language)){   
        include $api_file_language; //Include the code
    }
    else {
        include dirname(__FILE__,2).'/settings/translations/translations_US.php';
    }
  }
  else {
      include dirname(__FILE__,2).'/settings/translations/translations_US.php';
  } 

  switch ($sw_version_latest) {
    case 1:
      $message = '<span class="status firmware_recent">'.$firmware_recent_text.'</span>';
    break;
    
    case 0:
      $message = '<span class="status firmware_update">'.$firmware_update_text.'</span>';
    break;
    
    default:
     $message ='<span class="status">Unknown</span>';
    break;
  }
   
  return $message;
}

//------------------------------------------
// show serviceEvents available
//------------------------------------------
function serviceEvents ($messages,$page){

    include dirname(__FILE__,2).'/settings/settings_redirector.php'; 

    //INCLUDE TRANSLATION FILE
    if(isset($_SESSION['country_code'])){
    $api_file_language = dirname(__FILE__,2).'/settings/translations/translations_'.strtoupper($_SESSION['country_code']).'.php';
      if (file_exists($api_file_language)){   
          include $api_file_language; //Include the code
      }
      else {
          include dirname(__FILE__,2).'/settings/translations/translations_US.php';
      }
    }
    else {
        include dirname(__FILE__,2).'/settings/translations/translations_US.php';
    }  
    
    $view_header = '<table class="sortable">
                <thead>
                <tr>
                    <th>'.$equipment_label2.'</th>
                    <th>'.$equipment_label8.'</th>
                    <th>'.$equipment_label9.'</th>
                    <th>'.$equipment_label3.'</th>
                    <th>'.$general_createdby.'</th>
                    <th>'.$general_created.'</th>
                    <th>'.$view_asset_actions.'</th>
                </tr>
                </thead>
                <tbody>';
    
    $view_data = '';
    
    foreach ($messages as $message){
        
        if ($message->type == $type14 && str_contains($message->description, 'serialnumber')){
       
            //Get service date
            $service_date = (new DateTime($message->created))->format('Y-m-d');
            $service_renewal_date = (new DateTime($message->created))->modify('+365 days')->format('Y-m-d');
            
            $TETS = json_decode($message->description);
            $test = $TETS->maintenance_test ?? '';

            //+++++++++++++++++++++++++++++++++++++++++++++++
            // Maintenance Test
            //++++++++++++++++++++++++++++++++++++++++++++++
            //GET from DB
            $pdo = dbConnect($dbname);
            $sql = 'SELECT description FROM equipment_history WHERE rowID = "'.$test.'"';
            $stmt = $pdo->query($sql);
            $stmt->execute();
            $result = $stmt->fetch();

            $test_string = $result['description'] ?? '';
            //+++++++++++++++++++++++++++++++++++++++++++++++++++++++
            // Check if false test found
            // +++++++++++++++++++++++++++++++++++++++++++++++++++++++
          
            if (str_contains($test_string, "false")){
                $service_status = '<span class="status warranty_outdated">'.$service_report_outcome_attention.'</span>';
                $service_renewal_date = $service_report_outcome_attention; // leave service-renewal empty when errors are found
            } else {
                $service_status = '<span class="status warranty">'.$service_report_outcome_good.'</span>';
            }
            
            $view_data .= '<tr>
                        <td>'.$TETS->serialnumber.'</td>
                        <td>'.$service_date.'</td>
                        <td>'.$service_renewal_date.'</td>
                        <td>'.$service_status.'</td>
                        <td>'.$message->createdby.'</td>
                        <td>'.getRelativeTime($message->created).'</td>
                        <td><a href="index.php?page=servicereport&equipmentID='.$message->equipmentID.'&historyID='.$message->historyID.'" class="btn_link">'.$general_view.'</a></td>
                        <td><a href="index.php?page=render_service_report&historyID='.$message->historyID.'" class="btn_link">PDF</a></td>
                    </tr>';
        }
  
    }
    //CHECK IF OUTPUT IS MORE THAN X (config setting)
    if (count($messages) == $page_rows_equipment_servicereporst && $page == 'equipment'){
      $view_data .=  '<tr>
                        <td><a href="index.php?page=servicereports&equipmentid='.$message->h_equipmentid.'" class="btn_link">'.$general_actions_more.'</a></td>
                    </tr>';  
    }

    if ($view_data == ''){
        $view_data =  '<tr>
                            <td colspan="4" style="text-align:center;">'.$service_report_no_text.'</td>
                        </tr>';
    }

    $view_data .= '</tbody>';
    $view_footer = '</table>';

    $view = $view_header.$view_data.$view_footer;
    
    return $view;
}
//------------------------------------------
// Service report //Input = servicereport
//------------------------------------------

function serviceReport($history, $request, $country_code)
{

  if(isset($country_code) && $country_code != ''){
    $api_file_language = dirname(__FILE__,2).'/settings/translations/translations_'.strtoupper($country_code).'.php';
      if (file_exists($api_file_language)){   
          include $api_file_language; //Include the code
      }
      else {
          include dirname(__FILE__,2).'/settings/translations/translations_US.php';
      }
  }
  else {
      include dirname(__FILE__,2).'/settings/translations/translations_US.php';
  }  

  include dirname(__FILE__,2).'/settings/settings_redirector.php';
  include dirname(__FILE__,2).'/settings/systemservicetool.php';
  
    $json_array = json_decode($history->description);
    $service_exe_date = (new DateTime($history->created))->format('Y-m-d');
    $service_renewal_date = (new DateTime($history->created))->modify('+365 days')->format('Y-m-d');
    
    if (isset($json_array->maintenance_test)) {     
      //Get Maintenance Test directly from DB
      $pdo = dbConnect($dbname);
      $stmt = $pdo->prepare('SELECT description FROM equipment_history WHERE rowID = ?');
      $stmt->execute([$json_array->maintenance_test]);
      $maintenance_test = $stmt->fetch();
      $test_fail = $maintenance_test['description'];
      $maintenance_test = json_decode($maintenance_test['description']);
      
      function combineAndSortKeys($object) {
        // Convert object properties to arrays if needed
        $key1 = (array)($object->doubletestvalues ?? []);
        $key2 = (array)($object->stringtestvalues ?? []);
        $key3 = (array)($object->booleantestvalues ?? []);
        
        // Combine all rows
        $combined = array_merge($key1, $key2, $key3);
        
        // Group rows based on the "pass" boolean
        $grouped = [
            'failed' => [],
            'passed' => []
        ];
        
        foreach ($combined as $row) {
            // Check if $row is an object and convert if needed
            if (is_object($row)) {
                $row = (array)$row;
            }
            
            if (isset($row['pass']) && $row['pass'] === true) {
                $grouped['passed'][] = $row;
            } else {
                $grouped['failed'][] = $row;
            }
        }
        
        return $grouped;
    }

    // Example usage:
    $sortedTestResults = combineAndSortKeys($maintenance_test);

    //check if maintenance test has false test and update renewal date
      if (str_contains($test_fail, "false")){
        $service_renewal_date = $service_report_outcome_attention;
      }
    }
   
    $servicereport = ''; //empty string

    if ($request != 'display'){
    $servicereport .= '
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <style>
           @page {margin: 220px 50px; }
        
           body {
            font-family: "DejaVu Sans", system-ui, sans-serif;
            color: #035754;
            font-size: 18px;
            line-height: 1.5;
          }
          
          table > thead:first-of-type > tr:last-child {
            page-break-after: avoid;
          }
      
          .servicereport {
            border-collapse: collapse;
            width: 100%;
            border-radius: 5px;
            border-style: hidden;
            margin: auto;
            background-color: #fff;
            margin-top: 20px;
          }
      
          .servicereport.fs-normal td {
            font-size: 18px;
          }
      
          .servicereport.fs-small td {
            font-size: 14px;
          }
      
          .servicereport thead {
            background-color: #2fac66;
            color: #fff;
          }
      
          .servicereport td {
            padding: 5px 15px;
          }
      
          .servicereport thead td {
            font-weight: bold;
          }
      
          .servicereport tbody td.success {
              text-decoration: underline;
              text-decoration-thickness: 2px;
              text-decoration-color: #3ead48;
              text-underline-offset: 2px;
          }
      
          .servicereport tbody td.warning {
              text-decoration: underline;
              text-decoration-thickness: 2px;
              text-decoration-color: #ffc107;
              text-underline-offset: 2px;
          }
      
          .servicereport tbody td.error {
              text-decoration: underline;
              text-decoration-thickness: 2px;
              text-decoration-color: #d1232a;
              text-underline-offset: 2px;
          }
      
          .servicereport .col-key {
            width: 70%;
          }
      
          .servicereport .col-value {
            width: 30%;
          }
      
          .servicereport--details tbody tr {
              border-bottom: 1px solid #035754;
          }
      
          .servicereport--striped tbody tr:nth-child(odd) {
              background-color: #f3fafa;
          }
      
          .servicereport--striped tbody tr:nth-child(even) {
              background-color: #e7f6f6;
          }
      
          .servicereport--striped tbody tr {
              border-bottom: 1px solid #9bdcd9;
          }
      
          .service_summary {
            background-image: linear-gradient(#e7f6f6, #fafdfd);
            margin-top: 20px;
            padding-bottom: 15px;
          }
      
          .service_summary__title {
            background-color: #035754;
            color: #fff;
            font-weight: bold;
            padding: 5px 15px;
          }
      
          .service_notes {
            margin: 15px 15px 0 15px;
            padding: 15px;
            background-color: #fff;
            color: #035754;
          }
      
          #content {
            width: 100%;
            margin: auto;
          }
      
          #header {
            position: fixed;
            left: -50px;
            top: -220px;
            right: -50px;
            height: 200px;
            text-align: center;
            border-radius: 5px;
          }
      
          #header h1 {
            color: #fff;
            font-weight: bold;
            margin: auto;
          }
      
          #header img {
            width: 100%;
          }
      
          #footer {
            position: fixed;
            left: -50px;
            bottom: -280px;
            right: -50px;
            height: 150px;
      
            border-radius: 5px;
          }
      
          #footer img {
            width: 100%;
          }
      
          #footer .page:after {
            content: counter(page, upper-roman);
          }
      
          .page-break {
            page-break-before: always;
          }
      
          .text-center {
            text-align: center;
          }
      
          h4 {
            margin-top: 0;
          }
      
          h4.label {
            padding: 5px 15px;
            background-color: #035754;
            color: #fff;
            margin-top: 20px;
            margin-bottom: 20px;
          }
      
        </style>
      </head>
    <body>
    <div id="header">
      <img src="https://'.$portalURL.'/assets/images/servicereport.png" alt="Service report">
    </div>
    <div id="footer">
      <img src="https://'.$portalURL.'/assets/images/servicereport-footer.png" alt="Service report">
    </div>';        
    }

    $servicereport .= '
    <div id="content">
    <table id="" class="fs-normal servicereport servicereport--details">
    <thead>
      <tr>
        <td class="col-key">'.$service_report_item.'</td>
        <td class="col-value">&nbsp;</td>
      </tr>
    </thead>
    <tbody>
    <tr>
      <td class="col-key">'.$service_report_id.'</td>
      <td class="col-value">'.$history->historyID.'</td>
    </tr>
    <tr>
      <td class="col-key">'.$service_serialnumber.'</td>
      <td class="col-value">'.$json_array->serialnumber.'</td>
    </tr>
    <tr>
      <td class="col-key">'.$service_date.'</td>
      <td class="col-value">'.$service_exe_date.'</td>
    </tr>
    <tr>
      <td class="col-key">'.$service_renewal.'</td>
      <td class="col-value">'.$service_renewal_date.'</td>
    </tr>
    <tr>
      <td class="col-key">'.$service_performed_by.'</td>
      <td class="col-value">'.$history->createdby.'</td>
    </tr>
    </tbody>
    </table>
    <div id="service_summary" class="service_summary">
    <table width="100%">
      <thead>
        <tr>
          <td class="service_summary__title">'.$summary_label1.'</td>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>
            <ul>
    ';
    
    $actions = 0;
    $repairs = 0;
   
   //Check New Report or Legacy
   if (str_contains($history->description, "service_mandatory_question")) { 
    // New Report
    foreach ($json_array->final as $final) {
      if ($final->id == "service_action_clean" && $final->value == 1) {
        $servicereport .= '<li>' . $service_action_clean . '</li>';
        $actions++;
      }
      if ($final->id == "service_action_battery" && $final->value == 1) {
        $servicereport .= '<li>' . $service_action_battery . '</li>';
        $actions++;
      }         
    }
  } elseif (str_contains($history->description, "question25") && !str_contains($history->description, "newHistory")) {
    foreach ($json_array->final as $final) {
      if (($final->id == "action_clean" ||$final->id == "action_serial") && $final->value == 'Yes'){
        $servicereport .= '<li>' . ${$final->id . '_description'}. '</li>';
        $actions++;
      }  
    }
  }
  if ($actions == 0) {$servicereport .= '<li>'.$message1.'</li>';}
   
    //CLOSE summary table and OPENGROUP_HEADER 8 table
    $servicereport .= '
            </ul>
          </td>
        </tr>
      </tbody>
    </table>
    <table width="100%">
      <thead>
        <tr>
          <td class="service_summary__title">'.$group_header_8.'</td>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>
            <ul>
    ';
    if (str_contains($history->description, "service_mandatory_question")) { 
      foreach ($json_array->final as $final) {
        if ($final->id == "service_action_serial" && $final->value == 1) {
          $servicereport .=  '<li>' . $service_action_serial . '</li>';
            $repairs++;
        }
        if ($final->id == "service_action_cover" && $final->value == 1) {
          $servicereport .=  '<li>' . $service_action_cover . '</li>';
            $repairs++;
        }         
        if ($final->id == "service_action_spudger" && $final->value == 1) {
          $servicereport .=  '<li>' . $service_action_spudger . '</li>';
            $repairs++;
        }       
        if ($final->id == "service_action_case" && $final->value == 1) {
          $servicereport .=  '<li>' . $service_action_case . '</li>';
            $repairs++;
        }       
        if ($final->id == "service_action_instructions" && $final->value == 1) {
          $servicereport .=  '<li>' . $service_action_instructions . '</li>';
            $repairs++;
        }       
      } 
    } elseif (str_contains($history->description, "question25") && !str_contains($history->description, "newHistory")) {
      foreach ($json_array->final as $final) {
        if (strpos($final->id, "action_repaired") !==false && $final->value == 'Yes') {
          $servicereport .= '<li>' . ${$final->id . '_description'}. '</li>';
          $repairs++;
        }
        if (strpos($final->id, "action_replacement") !==false && $final->value == 'Yes') {
          $servicereport .= '<li>' . ${$final->id . '_description'}. '</li>';
          $repairs++;
        }
      }
    }
    
    if ($repairs == 0) {$servicereport .= '<li>' . $message2 . '</li>';}
    
    //CLOSE GROUP_HEADER 8 table
    $servicereport .=' 
            </ul>
          </td>
        </tr>
      </tbody>
    </table>';

    if (str_contains($history->description, "service_mandatory_question")) { 
      //GET NOTES from JSON
      $notes ='';
      foreach ($json_array->final as $final){
        if ($final->id == "service_notes"){
          $notes = $final->value;
        }
      }
    
      //GENERATE NOTES SECTION
      $servicereport .='
        <table width="100%">
          <thead>
            <tr>
              <td class="service_summary__title">'.$group_header_7.'</td>
            </tr>
          </thead>
          <tbody>';
      if ($notes != '') {
        $servicereport .= '<tr><td id="service_notes" class="service_notes">'.$notes.'</td></tr>';
      } 
      else {
        $servicereport .= '<tr><td id="service_notes" class="service_notes">'.$service_report_no_comments.'</td></tr>';  
      }

      $servicereport .='</tbody>
        </table> ';
    }
    $servicereport .= '</div>';
    
    //+++++++++++++++++++++++++++++++++++++++++++++++
    // Maintenance Test
    //++++++++++++++++++++++++++++++++++++++++++++++

      if (isset($json_array->maintenance_test)) {
        
        if (!empty($maintenance_test)) {
    
        $servicereport .='
        <div class="page_break"></div>
        <table id="" class="fs-small servicereport servicereport--striped">
        <thead>
            <tr>
            <td class="col-key">'.$service_report_maintenance_test.'</td>
            <td class="col-value text-center">'.$service_report_maintenance_test_status.'</td>
            </tr>
        </thead>      
        <tbody>';

        //SHOW FAILED VALUES
        foreach($sortedTestResults['failed'] as $key => $value)       
            {
              $servicereport .='
              <tr>
              <td class="col-key">'.$value['name'].'</td>
              <td class="col-value text-center error">'.$service_maintenance_test_fail.'</td>
              </tr>
            ';
            }
        //SHOW PASSED VALUES
        foreach($sortedTestResults['passed'] as $key => $value)       
            {            
            $servicereport .='
                <tr>
                <td class="col-key">'.$value['name'].'</td>
                <td class="col-value text-center success">'.$service_maintenance_test_pass.'</td>
                </tr>
            ';
            }      
        $servicereport .= '
        </tbody>
    </table>
    ';
     }
            
    }
   //++++++++++++++++++++++++++++++++++++++++++++++
    //GEt visualinspection
    //++++++++++++++++++++++++++++++++++++++++++++++
    if (isset($json_array->visualinspection)) {

        //Get visualinspection directly from DB
        $pdo = dbConnect($dbname);
        $stmt = $pdo->prepare('SELECT description FROM equipment_history WHERE rowID = ?');
        $stmt->execute([$json_array->visualinspection]);
        $visualinspection = $stmt->fetch();

        $visualinspection_legacy = $visualinspection['description'];
        $visualinspection = json_decode($visualinspection['description']);
    

        if (!empty($visualinspection)) {
        
        //Check if visualinspection comes from ServiceTool else inhouse
            if (isset($visualinspection->serviceReport->questionItems)) {
            $visualinspection_array = $visualinspection->serviceReport->questionItems;
                        }
            else {
            //inhousetool
            $visualinspection_array = $visualinspection;
            }
        //Check Legacy API
            if (str_contains($visualinspection_legacy, "question1")) {
            //Legacy API Questions
            $question_array = $arrayQuestions_legacy;
            }
            else
            { // New Report
            $question_array = $arrayQuestions_visual;
            }

            $servicereport .= '

            <h4 class="label">' . $summary_label2 . '</h4>';

            foreach ($question_array as $key){
            if ($key['Group_sequence'] == '3'){
                $servicereport .= '<div class="page_break"></div>'; // pagebreak
            }
            $servicereport .= '
            <table id="" class="fs-small servicereport servicereport--striped">
            <thead>
                <tr>
                  <td class="col-key">'.$key['Group'].'</td>
                  <td class="col-value text-center">'.$service_report_maintenance_test_status.'</td>
                </tr>
            </thead>
            <tbody>';
            foreach ($key['Questions_in_group'] as $questions){
                
                $servicereport .=  '<tr>
                                    <td class="col-key">'; 
                        $response = (substr(${$questions['QuestionID']}, -1) == '?') ? substr(${$questions['QuestionID']}, 0, strpos(${$questions['QuestionID']}, "?")) : ${$questions['QuestionID']};
                        //$response = $questions['QuestionID'];
                        $servicereport .=  ' '.$response.'
                        </td>';
                            foreach ($visualinspection_array as $inspection){
                                if ($inspection->id == $questions['QuestionID']){

                                  if (isset($inspection->responseID)){
                                    if (in_array($inspection->responseID,$negative_results)){
                                      $style2 = 'error';
                                      }
                                      else 
                                      {
                                      $style2 = 'success';
                                      }
                                      $translated_value = ${'service_allowed_label'.$inspection->responseID};
                                  }else{
                                    if (in_array($inspection->id,$negative_results)){
                                    $style2 = 'error';
                                    }
                                    else 
                                    {
                                    $style2 = 'success';
                                    }
                                    $translated_value = $inspection->value;
                                  }

                            $servicereport .= '<td class="col-value text-center '.$style2.'">'.$translated_value.'</td>';
                            }
                        }
                        $servicereport .= ' 
                    </tr>';
                }
    
            $servicereport .= '</tbody></table>';
         }
        
        }
    }

    //++++++++++++++++++++++++++++++++++++++++++++++
    //Legacy Code
    //++++++++++++++++++++++++++++++++++++++++++++++
    
    if (isset($json_array->question25) && isset($json_array->newHistory)) {
      $servicereport .= '
      
      <h4>'.$summary_label2.'</h4>
      <table class="fs-normal servicereport servicereport--details">
      <thead>
      <tr>
          <td>&nbsp;</td>
          <td>'.$summary_label3.'</td>
          <td>'.$summary_label4.'</td>
      </tr>
      </thead>
      <tbody>
      <tr>
          <td>'.$question10.'</td>
          <td>
          '.$service_allowed_label9.'
          </td>
          <td>
              '; if (isset($json_array->{$question10.'b'})){$servicereport .=  $json_array->{$question10.'b'};} else {$servicereport .=  $servicereport5;} $servicereport .= '
            </td>
        </tr>
      <tr>
          <td>'.$question11.'</td>
          <td>
              '; if (isset($json_array->{$question11.'a'})){$servicereport .=  $json_array->{$question11.'a'};} else {$servicereport .=  $servicereport5;} $servicereport .= '
          </td>
          <td>
              '; if (isset($json_array->{$question11.'b'})){$servicereport .=  $json_array->{$question11.'b'};} else {$servicereport .=  $servicereport5;} $servicereport .= '
            </td>
      </tr>
      <tr>
          <td>'.$question12.'</td>
          <td>
              '; if (isset($json_array->{$question12.'a'})){$servicereport .=  $json_array->{$question12.'a'};} else {$servicereport .=  $servicereport5;} $servicereport .= '
          </td>
          <td>
              '; if (isset($json_array->{$question12.'b'})){$servicereport .=  $json_array->{$question12.'b'};} else {$servicereport .=  $servicereport5;} $servicereport .= '
            </td>
      </tr>
      <tr>
          <td>'.$question13.'</td>
          <td>
              '; if (isset($json_array->{$question13.'a'})){$servicereport .=  $json_array->{$question13.'a'};} else {$servicereport .=  $servicereport5;} $servicereport .= '
          </td>
          <td>
              '; if (isset($json_array->{$question13.'b'})){$servicereport .=  $json_array->{$question13.'b'};} else {$servicereport .=  $servicereport5;} $servicereport .= '
            </td>
        </tr>
      <tr>
          <td>'.$question14.'</td>
          <td>
              '; if (isset($json_array->{$question14.'a'})){$servicereport .=  $json_array->{$question14.'a'};} else {$servicereport .=  $servicereport5;} $servicereport .= '
          </td>
          <td>
              '; if (isset($json_array->{$question14.'b'})){$servicereport .=  $json_array->{$question14.'b'};} else {$servicereport .=  $servicereport5;} $servicereport .= '
            </td>
          </tr>
      <tr>
          <td>'.$question15.'</td>
          <td>
          '.$service_allowed_label9.'
          </td>
          <td>
            '; if (isset($json_array->{$question15.'b'})){$servicereport .=  $json_array->{$question15.'b'};} else {$servicereport .=  $servicereport5;} $servicereport .= '
            </td>
        </tr>
      <tr>
          <td>'.$question16.'</td>
          <td>
          '.$service_allowed_label9.'
          </td>
          <td>
          '; if (isset($json_array->{$question16.'b'})){$servicereport .=  $json_array->{$question16.'b'};} else {$servicereport .=  $servicereport5;} $servicereport .= '
            </td>
        </tr>
      <tr>
          <td>'.$question17.'</td>
          <td>
            '.$service_allowed_label9.'
          </td>
          <td>
            '; if (isset($json_array->{$question17.'b'})){$servicereport .=  $json_array->{$question17.'b'};} else {$servicereport .=  $servicereport5;} $servicereport .= '
            </td>
        </tr>
      <tr>
          <td>'.$question18.'</td>
          <td>
          '; if (isset($json_array->{$question18.'a'})){$servicereport .=  $json_array->{$question18.'a'};} else {$servicereport .=  $servicereport5;} $servicereport .= '
          </td>
          <td>
          '; if (isset($json_array->{$question18.'b'})){$servicereport .=  $json_array->{$question18.'b'};} else {$servicereport .=  $servicereport5;} $servicereport .= '
            </td>
        </tr>
        </tbody>
      </table>';
    }
      
    $servicereport .='</div>';
    
    if ($request != 'display'){
      $servicereport .= '
            </body>
            </html>';
    }

  return $servicereport;
}

//------------------------------------------
// LIST PARTNER 
//------------------------------------------
function listPartner($partnertype, $user_right, $input, $required)
{
  include dirname(__FILE__,2).'/settings/settings_redirector.php';

//BASED ON USERRIGHT DEFINE SQL AND DATA RETURNED
if ($user_right != 3 || $user_right !=4) {
    //NOT ADMIN USER
    $partner = json_decode($_SESSION['partnerhierarchy']);
    //SoldTo is empty
    if (empty($partner->soldto) || $partner->soldto == ''){$soldto_search = '%';} else {$soldto_search = '-%';}
    //BUILD CONDITION
    $condition = '__salesid___'.$partner->salesid.'___soldto___'.substr($partner->soldto, 0, strpos($partner->soldto, "-")).$soldto_search;
    $whereclause = 'AND salesID like ?';
}
else {//ADMIN USERS
      $whereclause = '';
      }

  $pdo = dbConnect($dbname);
  $sql = 'SELECT distinct partnerID, partnername FROM partner WHERE partnertype = ? AND status = 1 '.$whereclause.'';
  $stmt = $pdo->prepare($sql);
  $stmt->execute([$partnertype, $condition]);
  $partners = $stmt->fetchAll(PDO::FETCH_ASSOC);

if ($input !='' && !empty($input)){
    $partner_available  = '<option value="'.$input.'" selected>'.$input.'</option><option value=" "> </option>';
} else {
    $partner_available  = '<option></option>';
}

$view ='
    <input list="'.$partnertype.'" name="'.$partnertype.'" placeholder="'.$input.'" value="'.$input.'" class="datalist" '.((isset($required) && $required != '') ? ' required' : '').'>
    <datalist id="'.$partnertype.'">
    '.$partner_available.'
';

foreach ($partners as $row) {
$view .= '<option value="'.$row["partnerID"].'-'.$row["partnername"].'">'.$row["partnerID"].' - '.$row["partnername"].'</option>';
}

$view .= '</datalist>
';
return $view;
}

//------------------------------------------
// LIST ACCOUNTS
//------------------------------------------
function listAccounts($type, $user_right, $input)
{
  include dirname(__FILE__,2).'/settings/settings_redirector.php';

//BASED ON USERRIGHT DEFINE SQL AND DATA RETURNED
if ($user_right != 3 || $user_right !=4) {
    //NOT ADMIN USER
    $partner = json_decode($_SESSION['partnerhierarchy']);
    //SoldTo is empty
    if (empty($partner->soldto) || $partner->soldto == ''){$soldto_search = '%';} else {$soldto_search = '-%';}
    //BUILD CONDITION
    $condition = '__salesid___'.$partner->salesid.'___soldto___'.substr($partner->soldto, 0, strpos($partner->soldto, "-")).$soldto_search;
    $whereclause = 'AND salesID like ?';
}
else {//ADMIN USERS
      $whereclause = '';
      }

  $pdo = dbConnect($dbname);
  $sql = 'SELECT distinct partnerID, partnername FROM partner WHERE partnertype = ? AND status = 1 '.$whereclause.'';
  $stmt = $pdo->prepare($sql);
  $stmt->execute(['soldto', $condition]);
  $partners = $stmt->fetchAll(PDO::FETCH_ASSOC);

if ($input !='' && !empty($input)){
    $partner_available  = '<option value="'.$input.'" selected>'.$input.'</option><option value=" "> </option>';
} else {
    $partner_available  = '<option></option>';
}

$view ='
    <input list="'.$type.'" name="'.$type.'" placeholder="'.$input.'" class="datalist">
    <datalist id="'.$type.'">
    '.$partner_available.'
';

foreach ($partners as $row) {
$view .= '<option value="'.$row["partnerID"].'-'.$row["partnername"].'">'.$row["partnerID"].' - '.$row["partnername"].'</option>';
}

$view .= '</datalist>
';
return $view;
}


//------------------------------------------
// UPLOAD PICTURE for PRODUCTS
//------------------------------------------
function uploadProduct($name){

$target_dir = dirname(__FILE__)."/images/products/";
$input_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);
$imageFileType = strtolower(pathinfo($input_file,PATHINFO_EXTENSION));
$target_file = $target_dir . $name.'.jpg';
$file_input_check = getimagesize($_FILES["fileToUpload"]["tmp_name"]);

//Do when JPG or PNG or JPEG or GIF and smaller than 5MB
if(($imageFileType == "jpg" || $imageFileType == "png" || $imageFileType == "jpeg" || $imageFileType == "gif" || $imageFileType == "png") && $_FILES["fileToUpload"]["size"] < 5000000 && $file_input_check !== false) {
  //Upload picture  
  if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
    echo "Done";
  } else {
    echo "Error";
  }
  //}
}
}

//------------------------------------------
// UPLOAD PICTURE for DEALERS
//------------------------------------------
function uploadDealers($name){

  $target_dir = dirname(__FILE__)."/images/dealers/";
  $input_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);
  $imageFileType = strtolower(pathinfo($input_file,PATHINFO_EXTENSION));
  $target_file = $target_dir . $name.'.jpg';
  $file_input_check = getimagesize($_FILES["fileToUpload"]["tmp_name"]);
  
  //Do when JPG or PNG or JPEG or GIF and smaller than 5MB
  if(($imageFileType == "jpg" || $imageFileType == "png" || $imageFileType == "jpeg" || $imageFileType == "gif" || $imageFileType == "png") && $_FILES["fileToUpload"]["size"] < 5000000 && $file_input_check !== false) {
    //Upload picture  
    if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
      echo "Done";
    } else {
      echo "Error";
    }
    //}
  }
}

//------------------------------------------
// UPLOAD PICTURE for CARTEST
//------------------------------------------
function uploadrequest($key){ 
  $target_dir = dirname(__FILE__)."/images/cartests/";
  $input_file = $target_dir . basename($_FILES["fileToUpload"]["name"][$key]);
  $imageFileType = strtolower(pathinfo($input_file,PATHINFO_EXTENSION));
  $file_input_check = getimagesize($_FILES["fileToUpload"]["tmp_name"][$key]);
  $location = "./assets/images/cartests/".basename($_FILES["fileToUpload"]["name"][$key]);
  //Do when JPG or PNG or JPEG or GIF and smaller than 5MB
  if(($imageFileType == "jpg" || $imageFileType == "png" || $imageFileType == "jpeg" || $imageFileType == "gif" || $imageFileType == "png") && $_FILES["fileToUpload"]["size"][$key] < 5000000 && $file_input_check !== false) {
    //Upload picture  
    if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"][$key], $input_file)) {
        //ADD FILELOCATION TO POST VARIABLE
        $_POST['questions'][$key] = $location;
    } else {
    }
  } 
}  
  //------------------------------------------
  // displayImages
  //------------------------------------------
  function displayImages($requestid,$request_type){
  
      include dirname(__FILE__,2).'/settings/settings_redirector.php';
      
      $pdo = dbConnect($dbname);
      
      switch ($request_type) {
          case 'request':
              $whereclause = 'requestid = "'.$requestid.'"';
              break;
          case 'request_line':
              $whereclause = 'request_line_id = "'.$requestid.'"';
              break;
  
          default:
              # code...
              break;
      }
      $sql = 'SELECT * FROM images WHERE '.$whereclause;
      $stmt = $pdo->prepare($sql);
      $stmt->execute();
      $images = $stmt->fetchAll(PDO::FETCH_ASSOC);
      
      $output = '';
     
      if($images){
      $output .= '<div class="content-block media-page">
          <div class="media">';
            
          foreach ($images as $image){
          $output .= '<img class="image" src="./assets/images/requests/'.$image['image_name'].'" loading="lazy">';
          }
      $output .= '   </div>
      </div>';
      }
      return $output;
  }
//------------------------------------------
// debuglog
//------------------------------------------
function debuglog($error){
  include_once dirname(__FILE__,2).'/settings/config_redirector.php';
  $test = $error.PHP_EOL;
    $filelocation = dirname(__FILE__,2).'/log/log_'.date('d').'.txt';
    error_log($test, 3, $filelocation);
}

//------------------------------------------
// getRowID
//------------------------------------------

function getrowID($database, $id, $table, $where){
  // Connect to DB
  $pdo = dbConnect($database);
  // Define query $where f.e. sn=2423
  $sql = 'SELECT '.$id.' from '.$table.' where '.$where.'';
  $stmt = $pdo->prepare($sql);
  $stmt->execute();
  $rowid = $stmt->fetch();
  //ReturnId
  return $rowid;
}

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
// downloader       ++++++++++++++++++++++++++++++++++++++
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
function downloadFile($file) {

	if (!isset($_SESSION['loggedin']) && $_SESSION['loggedin'] !== false) {
		header('location: index.php');
		exit;
	}
    header('Content-Description: File Transfer');
    header('Content-Type: application/octet-stream, application/download, application/force-download');
    header('Content-Disposition: attachment; filename=' . basename($file));
    ob_clean();
    flush();
    readfile($file);
    exit;
}

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
// visual forecast for service and warranty+++++++++++++++
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
function serviceforecast($messages,$type){
  
  if ($messages){
    $number = (($type == 'warranty')? 1 : 1);
    //GET TOTAL SERVICE COUNT
    $totalcount = 0;
    $year_in_scope = date("Y") - 1;
    foreach ($messages as $message){
      if ($message['year'] >= $year_in_scope){
        $totalcount += $message['count'];
      }
    }

   $view = '<div style="margin-bottom: 30px;">
      <ul style="width: 100%;max-width:100%" class="chart">
      ';
    foreach ($messages as $message){
        if ($message['year'] >= $year_in_scope){
          $height = ($message['count'] / $totalcount) * 100;
          $fc_year = $message['year'] + $number;
          $title = 'Q'.$message['quarter'].' '.$fc_year;
          $view .='<li style="text-align:center;">' . $message['count'] . '<span style="height:' . $height . '%" title="' . $title . '"></span></li>';
        }
    }
    $view .='</ul></div>';

    return $view;
  }
}


// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
// changelog
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
function changelog($database,$object,$objectID,$object_field,$object_value,$createdby){
  /*
  database = database to connect to
  object = data object being changed (table name)
  object_field = field being changed
  object_value = new value
  */
  // Connect to DB
  $pdo = dbConnect($database);
  //Update query
  $sql = 'INSERT INTO changelog (object,objectID,object_field,object_value,createdby) VALUES (?,?,?,?,?)';
  //Prepare SQL AND EXECUTE
  $stmt = $pdo->prepare($sql);
  $stmt->execute([$object,$objectID,$object_field,$object_value,$createdby]);
}
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
// show changelog (front-end only)
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
function showlog($object,$objectID){
  
  //INCLUDE TRANSLATIONS
  if(isset($_SESSION['country_code'])){
    $api_file_language = dirname(__FILE__,2).'/settings/translations/translations_'.strtoupper($_SESSION['country_code']).'.php';
      if (file_exists($api_file_language)){   
          include $api_file_language; //Include the code
      }
      else {
          include dirname(__FILE__,2).'/settings/translations/translations_US.php';
      }
  }
  else {
      include dirname(__FILE__,2).'/settings/translations/translations_US.php';
  } 
  include dirname(__FILE__,2).'/settings/settings_redirector.php'; 
  
  // Connect to DB
  $pdo = dbConnect($dbname);
  //Update query
  $sql = 'SELECT * FROM changelog WHERE object = ? AND objectID = ?';
  //Prepare SQL AND EXECUTE
  $stmt = $pdo->prepare($sql);
  $stmt->execute([$object,$objectID]);
  $changes = $stmt->fetchAll(PDO::FETCH_ASSOC);

  $view = '<label for="productcode">Changelog</label>';
  foreach($changes as $change){
    
    $object_value = $change['object_value'];

    //UPDATE TO HUMANREADABLE STATUS
    if ($object == 'equipment' && $change['object_field'] == 'status'){
      $object_text = 'status'.$change['object_value'].'_text';
      $object_value = $$object_text;
    }
    $view .= '<input id="name" type="text" value="'.$change['object_field'].' - '.$object_value.' - '.$change['created'].' - '.$change['createdby'].'" readonly>';
  }
  
  return $view;
}

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
// visual changelog                        +++++++++++++++
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
function changeLogVisual($totals,$details){
  if ($totals){
    //GET TOTAL COUNT
    $totalcount = 0;
    foreach ($totals as $total){
        $totalcount += $total['total'];
    }

   $view = '<div style="margin-bottom: 30px;">
      <ul style="width: 100%;max-width:100%" class="chart">
      ';
    foreach ($totals as $total){        
      //GET SERIALNUMBERS
      $url_input = ''; //used to collect serialnumber for onclick event 
      foreach ($details as $detail){
        if ($detail['WoW'] == $total['WoW'] && $detail['DoW'] == $total['DoW']){
          $url_input .= $detail['serialnumber'].',';
        }    
      }
      $height = ($total['total'] / $totalcount) * 100;
      $title = $total['DoW'].'/'.$total['WoW'];
      $view .='<li style="text-align:center;" onclick="location.href=\'index.php?page=equipments&serialnumber='.substr($url_input,0,-1).'\'">' . $total['total'] . '<span style="height:' . $height . '%" title="' . $title . '"></span></li>';
    }
    $view .='</ul></div>';

    return $view;
  }
}


// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
// download to excell function
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
function downloadToExcel($collection, $data_input){

//Conver to ARRAY
$data_input = json_decode(json_encode($data_input), true);

// Excel file name for download 
$fileName = $collection.date('Y-m-d').".xls"; 

//GET KEYS of first row returned
$header_fields = array_keys($data_input[0]); 

// Display column names as first row 
$excelData = implode("\t", array_values($header_fields)) . "\n"; 
 
// Fetch records from database 
if($data_input){ 
    // Output each row of the data 
    foreach ($data_input as $data_row){ 
        //array_walk($message, 'filterData'); 
        $excelData .= implode("\t", array_values($data_row)) . "\n"; 
    } 
} 

// Headers for download 
header("Content-Type: application/vnd.ms-excel"); 
header("Content-Disposition: attachment; filename=\"$fileName\""); 
 
// Render excel data 
echo $excelData;  
exit;
}

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Create Partner - when not exists
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
function createPartner($user_salesid,$user_soldto,$p_name,$p_type, $token){
	
  $p_return = '';
  
  //BUILD POST DATA
  $data = json_encode(array("partnerID" => '' , "salesid" => $user_salesid , "soldto" => $user_soldto, "partnername" => $p_name, "partnertype" => $p_type  , "partnernotes" => 'system generated'), JSON_UNESCAPED_UNICODE);
  //Secure data
  $payload = generate_payload($data);
  //API call
  $responses = ioAPI('/v1/partners', $payload, $token);
  
  if ($responses === 'NOK'){
      // Do Nothing
  } 
  else {
      //GET PARTNER DATA - CALL TO API WITH PARTNERNAME
      $api_url = '/v1/partners/partnername='.$p_name;
      $responses = ioAPI($api_url,'',$token);
      //Decode Payload
      if (!empty($responses)){
      //If response received, check END of array for latest partner details
          $responses = decode_payload($responses);
          $p_responses = end($responses);
          $p_return = $p_responses->partnerID.'-'.$p_responses->partnername;  
      } 
  }
  return $p_return;
  }

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Update GEOlOCATION
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
function geolocationUpdate($token){
  include dirname(__FILE__,2).'/settings/settings_redirector.php'; 

  //GET ALL WARRANTY REGISTRATIONS WHERE NO GEOLOCATION SET
  $sql = 'SELECT h.equipmentid, h.description FROM equipment e join equipment_history h on e.rowID = h.equipmentid where h.type = "Warranty" AND e.geolocation is Null';
  $pdo = dbConnect($dbname);
  $stmt = $pdo->prepare($sql);
  $stmt->execute();
  $messages = $stmt->fetchAll(PDO::FETCH_ASSOC);

  //FOR ALL RECORDS RETURN FIND GEOLOCATION AT OSM
  foreach ($messages as $message){
    $warranty = json_decode($message['description']);
    
    //API URL OSM
    $api_url = 'https://nominatim.openstreetmap.org/search?format=json&city='.urlencode($warranty->city).'&country='.urlencode($warranty->country);
    $api_url = str_replace(' ','%20',$api_url);
    
    //BUILD UP FILESTREAM 
    $httpOptions = [
        "http" => [
            "method" => "GET",
            "header" => "User-Agent: Nominatim-Test"
        ]
    ];

    $streamContext = stream_context_create($httpOptions);
    $geo_feedback = file_get_contents($api_url, false, $streamContext);
    $geo_feedback = json_decode($geo_feedback, true);
    $lat = (isset($geo_feedback[0]["lat"]) && ($geo_feedback[0]["lat"] !='' || $geo_feedback[0]["lat"] != null))?$geo_feedback[0]["lat"]:0;
    $long = (isset($geo_feedback[0]["lon"]) && ($geo_feedback[0]["lon"] !='' || $geo_feedback[0]["lon"] != null))?$geo_feedback[0]["lon"]:0;

    if ($lat == 0){
      //CHECK FOR COUNTRY
      $api_url = 'https://nominatim.openstreetmap.org/search?format=json&country='.urlencode($warranty->country);
      $api_url = str_replace(' ','%20',$api_url);
      $streamContext = stream_context_create($httpOptions);
      $geo_feedback = file_get_contents($api_url, false, $streamContext);
      $geo_feedback = json_decode($geo_feedback, true);
      $lat = (isset($geo_feedback[0]["lat"]) && ($geo_feedback[0]["lat"] !='' || $geo_feedback[0]["lat"] != null))?$geo_feedback[0]["lat"]:0;
      $long = (isset($geo_feedback[0]["lon"]) && ($geo_feedback[0]["lon"] !='' || $geo_feedback[0]["lon"] != null))?$geo_feedback[0]["lon"]:0;
    }
    
    if ($lat !=0){
      $geo_feedback = array($lat,$long);    
      //JSON ENCODE GEOLOCATION RECEIVED AND SENT TO EQUIPMENT API
      $geo_feedback =  json_encode($geo_feedback);
      //BUILD POST DATA
      $data = json_encode(array("rowID" => $message['equipmentid'] , "geolocation" => $geo_feedback), JSON_UNESCAPED_UNICODE);
      //Secure data
      $payload = generate_payload($data);
      //API call
      $responses = ioAPI('/v1/equipments', $payload, $token);
    
    }
  }   
}
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
// getQuestions
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++

function getQuestions($type){

  switch ($type) {
    case 'cartest':
      include './settings/systemcartest.php';
      $arrayQuestions = $arrayQuestions_cartest;
      break;
    
    default:
      $arrayQuestions = '';
      break;
  }

  if ($arrayQuestions !=''){
    foreach($arrayQuestions as $group){
        
      //CREATE GROUP_ID
      $group_id = 'group'.$group['Group_sequence'];

      $view .= '<h4 onClick="showDetails(\''.$group_id.'\')">'.$group['Group'].' &#9661;</h4>
      <div id="'.$group_id.'" style="'.$style.'">';

      foreach($group['Questions_in_group'] as $question){
          
        $view .= '<label for="" id="'.$question['QuestionID'].'" class="form-label">'.$question['Question'].'</label>';

        switch ($question['Type']) {
          case 'Dropdown':
            $view .= '<select id="" name="'.$question['QuestionID'].'">';
            foreach ($question['Response'] as $response){
                      $view .= '<option value="'.$response['response_value'].'">'.$response['response_text'].'</option>';  
            }
            $view .= '</select>';
            break;

          case 'Checkbox':
            $view .= '<ul>';
      
            foreach ($question['Response'] as $response){
              //ADD ARRAY OPTION '.$question['QuestionID'].'[]
              $view .= '<li style="list-style:none;">
                        <input type="checkbox" id="" name="" value="'.$response['response_value'].'" />
                        <label for="">'.$response['response_text'].'</label>
                        </li>';
            }
            $view .= '</ul>';
            break;

            case 'slider':     
                //CREATE SLIDER FOR DISTANCE 
                $view .= ' 
                <input type="text" id="city" placeholder="'.$city.'" value="">
                <input type="text" id="country" placeholder="'.$country.'" value="" onchange="findLocation();">
                <input type="hidden" name="lat" id="lat" value="0">
                <input type="hidden" name="lng" id="lng" value="0">
                <input type="range" name="range" id="distanceId" value="'.$question['Response'][1].'" min="'.$question['Response'][0].'" max="'.$question['Response'][2].'" oninput="distanceOutputId.value = distanceId.value"><output id="distanceOutputId">'.$question['Response'][1].'</output>';
                
              break;
        }
      }
    $view .= '</div>';
    }
  }
}
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
// convert cartest FROM equipment_history to cartest table
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
function convertCartest(){

include dirname(__FILE__,2).'/settings/settings_redirector.php';

//GET CARTEST FROM equipment_history TABLE
$pdo = dbConnect($dbname);
$sql = 'SELECT * FROM equipment_history WHERE type="cartest"';
$stmt = $pdo->prepare($sql);
//Excute Query
$stmt->execute();
//Get results
$messages = $stmt->fetchAll(PDO::FETCH_ASSOC);

//FOR EACH CARTEST TRANSFER TO CARTEST TABLE
  foreach ($messages as $message){
      //GET VARIABLES
      $cartest = json_decode($message['description'],true) ?? '';
      $carbrand = ucfirst($cartest["CarBrand"] ?? 'Unknown');
      $cartype = ucfirst($cartest["CarType"] ?? 'Unknown');
      $questions = json_encode($cartest["Questions"] ??'');
      $datapoints = json_encode($cartest["plugDataPoints"] ?? '');
      $nametester = $cartest["NameTester"] ?? 'Unknown';
      $plug_sn = $cartest["SN"] ?? 0;
      $accounthierarchy = '';

      //get header data only
      unset($cartest["Questions"]);
      unset($cartest["plugDataPoints"]);
      $header = json_encode($cartest);

      //GET ACCOUNTHIERARCHY FROM SN OF 
      if ($plug_sn !=0){
        $sql ='SELECT accounthierarchy FROM equipment WHERE serialnumber = ?';
        $stmt = $pdo->prepare($sql);
        //Excute Query
        $stmt->execute([$plug_sn]);
        //Get results
        $messages = $stmt->fetchAll(PDO::FETCH_ASSOC);
        $accounthierarchy = $messages[0]['accounthierarchy'];
      }

      //INSERT INTO CARTEST
      $sql = 'INSERT INTO cartest (carbrand, cartype,header,questions,datapoints,createdby,accounthierarchy) VALUES (?,?,?,?,?,?,?)';
      $stmt = $pdo->prepare($sql);
      //Excute Query
      $stmt->execute([$carbrand,$cartype,$header,$questions,$datapoints,$nametester,$accounthierarchy]);

      //MARK HISTORY ITEM FOR DELETATION
      $sql = 'UPDATE equipment_history SET type = "delete", updatedby = "system" WHERE rowID = '.$message['rowID'];
      $stmt = $pdo->prepare($sql);
      //Excute Query
      $stmt->execute();
  }
}
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ML data preparations
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++

function traintotalMeasurement(){

  include dirname(__FILE__,2).'/settings/settings_redirector.php'; 

  //total measurement internal array
  $total_measurement = [];
  
  //Connect to DB
  $pdo = dbConnect($dbname);

  //GET DATA
  $sql = 'SELECT h.rowID, h.description,h.equipmentid,p.productcode,e.hw_version FROM equipment_history h JOIN equipment e ON h.equipmentid = e.rowID JOIN products p ON e.productrowid = p.rowID where p.healthindex = 1 and h.type="Maintenance_Test" and h.description like "%doubletestvalues%"';
  $stmt = $pdo->prepare($sql);
  $stmt->execute();
  $messages = $stmt->fetchAll(PDO::FETCH_ASSOC);  

  foreach ($messages as $message){
    //Cleanup input array
    $dataset = json_decode($message['description'],true);
    $dataset = $dataset["doubletestvalues"];
    foreach ($dataset as $measure){
        //Filter out correct measurements
        if ($measure['pass'] === true){
            $hw_version = (!empty($message['hw_version']))? $message['hw_version'] : 'blank';
            $measurementid = $message['rowID'];
            $total_measurement[$message['productcode']][$hw_version][$measure['name']][$measurementid] = $measure['measure'];
        }
    }
  }
  return $total_measurement;
}

function statisticalAnalyses($total_measurement){

  //result array
  $total_results = [];

  //STATISTICAL ANALYSES INTERNAL ARRAY 
  foreach ($total_measurement as $productcode => $versions){ 
    foreach ($versions as $version => $ver){

        foreach ($ver as $measurement => $value){
            $average = $total_results[$productcode][$version][$measurement]['average'] = average($value);
            $median = $total_results[$productcode][$version][$measurement]['median'] = calculateMedian($value);
            $stdev = $total_results[$productcode][$version][$measurement]['stdev'] = standDeviation($value);
            $total_results[$productcode][$version][$measurement]['n'] = count($value);
            //GET STDEV -/+
            $total_results[$productcode][$version][$measurement]['stdev-1'] = $average - $stdev;
            $total_results[$productcode][$version][$measurement]['stdev+1'] = $average + $stdev;
            $total_results[$productcode][$version][$measurement]['stdev-2'] = $average - (2*$stdev);
            $total_results[$productcode][$version][$measurement]['stdev+2'] = $average + (2*$stdev);
            $total_results[$productcode][$version][$measurement]['stdev-3'] = $average - (3*$stdev);
            $total_results[$productcode][$version][$measurement]['stdev+3'] = $average + (3*$stdev);
        }           
    }
}

  return $total_results;
}

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Main statiscal functions for ML
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
function standDeviation($arr)
{
    $num_of_elements = count($arr);
    $variance = 0.0;
    // Calculate mean using array_sum() method
    $average = array_sum($arr) / $num_of_elements;
    foreach($arr as $i)
    {
        // Sum of squares of differences between all numbers and means.
        $variance += pow(($i - $average), 2);
    }
    return (float)sqrt($variance / $num_of_elements);
}
function average($arr)
{
    $num_of_elements = count($arr);
    $average = array_sum($arr) / $num_of_elements;   
    return $average;
}
function calculateMedian($array) {
    if (empty($array)) {
        return null;
    } else {
        sort($array);
        $lowMiddle = $array[floor((count($array) - 1) / 2)];
        $highMiddle = $array[ceil((count($array) - 1) / 2)];
        return ($lowMiddle + $highMiddle) / 2;
    }
}

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
// visual forecast for service and warranty+++++++++++++++
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
function usageView($messages){
    
  //GET TOTAL SERVICE COUNT
  $totalcount = 0;
  foreach ($messages as $message){
      $totalcount += $message['count'];
  }
    
  $view = '
  <smaller>Service = '.$totalcount.'  </smaller>  
  <div style="margin-bottom: 30px;">   
      <ul style="width: 100%;max-width:100%" class="chart">
  ';
  foreach ($messages as $message){
          $height = ($message['count'] / $totalcount) * 100;
          $fc_year = $message['year'];

          $dateObj   = DateTime::createFromFormat('!m', $message['month']);
          $title = $dateObj->format('F').' '.$fc_year;
          $view .='<li style="text-align:center;">' . $message['count'] . '<span style="height:' . $height . '%" title="' . $title . '"></span></li>';
  }
  
  $view .='</ul>
  </div>
  ';  

  return $view;
}

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
// overview of service events per servicekit ++++++++++++++
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
function usageBilling($messages){
    // Create an array to store sums by year, quarter, and month
    $totals = [];
  
    // Loop through the data and aggregate the counts by year, quarter, and month
    foreach ($messages as $entry) {
        $year = $entry['year'];
        $quarter = $entry['quarter'];
        //$dateObj   = DateTime::createFromFormat('!m', $entry['month']);
        //$month = $dateObj->format('F');
        $month = $entry['month'];
        $count = $entry['count'];
    
        // Initialize arrays if not already set for year, quarter, and month
        if (!isset($totals[$year])) {
            $totals[$year] = ['total' => 0, 'quarters' => []];
        }
    
        if (!isset($totals[$year]['quarters'][$quarter])) {
            $totals[$year]['quarters'][$quarter] = ['total' => 0, 'months' => []];
        }
    
        if (!isset($totals[$year]['quarters'][$quarter]['months'][$month])) {
            $totals[$year]['quarters'][$quarter]['months'][$month] = 0;
        }
    
        // Add count to the corresponding year, quarter, and month
        $totals[$year]['total'] += $count;
        $totals[$year]['quarters'][$quarter]['total'] += $count;
        $totals[$year]['quarters'][$quarter]['months'][$month] += $count;
      } 
      
      return $totals;
}
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
// close contract when expired             +++++++++++++++
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
function closeContract(){

include dirname(__FILE__,2).'/settings/settings_redirector.php'; 

$pdo = dbConnect($dbname);

//SELECT ALL ACTIVE CONTRACTS
$sql = 'SELECT * FROM contracts WHERE status = 1';
$stmt = $pdo->prepare($sql);
$stmt->execute();
$messages = $stmt->fetchAll(PDO::FETCH_ASSOC);

foreach ($messages as $message){
  //Calculate contract end date
  $end_date = date('Y-m-d', strtotime('+'.$message['duration'].' months', strtotime($message['start_date'])));

  //Validate if contract end date is in the past change contact status to closed and set users to not active
  if (date("Y-m-d") > $end_date){
    //Contract expired -> change status to closed (2)
    $sql = 'UPDATE contracts SET status = ?, updatedby = ? WHERE rowID = ?';
    $stmt = $pdo->prepare($sql);
    $stmt->execute([2,"system",$message['rowID']]);
    
    //CHECK FOR ASSIGNED USER END SET SERVICE TO INACTIVE
    foreach (json_decode($message['assigned_users']) as $user_assigned){

      //check user exist
      $sql = 'SELECT * FROM users WHERE username = ?';
      $stmt = $pdo->prepare($sql);
      $stmt->execute([$user_assigned]);
      $user_assigned = $stmt->fetch();

      if (!empty($user_assigned)){
          $id_exist_user = $user_assigned['id'];
          $sql = 'UPDATE users SET service = ? WHERE id = ? ';
          $stmt = $pdo->prepare($sql);
          //Remove serviceflag from user when status is Closed
          $stmt->execute(['',$id_exist_user]);
        }
      }
    }
  }  
}

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
// store measurement data into product_version  ++++++++++
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++

function storeMeasurementProduct($total_results, $token){

  include dirname(__FILE__,2).'/settings/settings_redirector.php'; 

  $pdo = dbConnect($dbname);

  //Check if product version exists (else create) => store related measurement
  foreach ($total_results as $products => $product){

    //Product level
      foreach ($product as $versions => $version){

      //Version level
      //Check version exist
      $sql = 'SELECT p.*, pv.rowID as versionID, pv.productrowid as productID FROM products p JOIN products_versions pv ON p.rowID = pv.productrowid WHERE p.healthindex = 1 and p.productcode = ? and version = ?;';
      $stmt = $pdo->prepare($sql);
      $versions = ($versions != 'blank')? $versions : '';
      $stmt->execute([$products,$versions]);
      $output = $stmt->fetchAll(PDO::FETCH_ASSOC);

      //Prep data for api call
      $api_url = '/v2/products_versions/';
      $measurement = json_encode($version,JSON_UNESCAPED_UNICODE);

      if (!empty($output)){
          //Update version with latest measurement
          $data = json_encode(array("rowID" => $output[0]['versionID'], "productrowid" => $output[0]['productID'], "status" => 1, "version" => $versions, "measurement" => $measurement), JSON_UNESCAPED_UNICODE);
          ioApi($api_url,$data,$token);
      } 
      else {
          //Insert new version

          //GET PRODUCT ID
          $sql = 'SELECT * FROM products WHERE productcode = ?';
          $stmt = $pdo->prepare($sql);
          $stmt->execute([$products]);
          $output = $stmt->fetchAll(PDO::FETCH_ASSOC);
      
          //CALL API
          $data = json_encode(array("productrowid" => $output[0]['rowID'], "status" => 1, "version" => $versions , "measurement" => $measurement), JSON_UNESCAPED_UNICODE);
          ioApi($api_url,$data,$token);
      }
    }
  }
}

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
// store measurement data into equipment data ++++++++++
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
function storeMeasurementEquipment($serialnumber){
  
  include dirname(__FILE__,2).'/settings/settings_redirector.php'; 

  //Connect to DB
  $pdo = dbConnect($dbname);

  //CHECK FOR SERIALNUMBER PROVIDED
  $clause = (!empty($serialnumber) || $serialnumber !='')? 'e.serialnumber = "'.$serialnumber.'" AND': '';

  //GET DATA
  $sql = 'SELECT h.rowID, h.description,h.equipmentid,p.productcode,e.hw_version FROM equipment_history h JOIN equipment e ON h.equipmentid = e.rowID JOIN products p ON e.productrowid = p.rowID where '.$clause.' type="Maintenance_Test" and description like "%doubletestvalues%"';
  $stmt = $pdo->prepare($sql);
  $stmt->execute();
  $messages = $stmt->fetchAll(PDO::FETCH_ASSOC);  

  $tests[] ='';
  foreach ($messages as $message){
      $dataset = json_decode($message['description'],true);
      $dataset = $dataset["doubletestvalues"];
      foreach ($dataset as $measure){
   
          //Filter out correct measurements
          if ($measure['pass'] === true){
              $measurementid = $message['productcode'].'||'.$message['hw_version'].'||'.$message['equipmentid'].'||'.$message['rowID'];
              $tests[$measurementid] [$measure['name']]= $measure['measure'];
          }
      }
  }
     
  //COMPARISON -- CHECK DEVIATIONS FROM STANDARD
  //LOOP over all test results
  foreach ($tests as $test => $test_values){
      
    //GET the productcode and version from Test result
    if (str_contains($test,'||')){
      
      $identification = explode('||',$test);
      
      //GET RELATED PRODUCT DATA
      $sql = 'SELECT pv.measurement FROM products_versions pv JOIN products p ON pv.productrowid = p.rowID WHERE p.productcode = ? AND pv.version = ?';
      $stmt = $pdo->prepare($sql);
      $stmt->execute([$identification[0],$identification[1]]);
      $product_measurements = $stmt->fetchAll(PDO::FETCH_ASSOC);
      $product_measurements = $product_measurements[0]['measurement']?? '';

      if (!empty($product_measurements)){
        //Only run when there is a product version found
        $product_measurements = json_decode($product_measurements,true);
        
        $equipment_watchlist[] = '';

        //Filter out non array or non objects
        if (is_object($test_values) || is_array($test_values)){
            //get individual test_mesurements
            foreach($test_values as $test_measurement => $measured_value){
                //Loop over the related product measurements
                foreach($product_measurements as $product_measurement => $product_measured_values){
                    //Compare measured test with product measured test
                    if ($test_measurement == $product_measurement){
                        //Get the measured value from test

                        if (($measured_value <= $product_measured_values['stdev-3']) && ($measured_value >= $product_measured_values['stdev+3'])){
                            $equipment_watchlist[$test][] = array(
                                "measurement" => $test_measurement,
                                "value" => $measured_value,
                                "deviation" => 3
                            );
                        }
                        elseif ((($measured_value <= $product_measured_values['stdev-2']) && ($measured_value >= $product_measured_values['stdev-3'])) || (($measured_value >= $product_measured_values['stdev+2']) && ($measured_value <= $product_measured_values['stdev+3']))){
                            $equipment_watchlist[$test][] = array(
                                "measurement" => $test_measurement,
                                "value" => $measured_value,
                                "deviation" => 2
                            );
                        }
                        elseif ((($measured_value <= $product_measured_values['stdev-1']) && ($measured_value >= $product_measured_values['stdev-2'])) || (($measured_value >= $product_measured_values['stdev+1']) && ($measured_value <= $product_measured_values['stdev+2']))){
                            $equipment_watchlist[$test][] = array(
                                "measurement" => $test_measurement,
                                "value" => $measured_value,
                                "deviation" => 1
                            );
                        }      
                    }
                }
            }
          }
      }
    }
  }
  //STORE RESULTS IN EQUIPMENT DATA
  foreach ($equipment_watchlist as $equipment => $data){    
  
      //GET the equipmentid and historyid from watchlist
      if (str_contains($equipment,'||')){
        $identification = explode('||',$equipment);

        //Calculate healthindex
        $healthindex = 100;
        
        foreach ($data as $data_measure){
          switch ($data_measure['deviation']) {
              case 1:
                  $healthindex = $healthindex - $data_measure['deviation'];
                  break;
              case 2:
                  $healthindex = $healthindex - ($data_measure['deviation']*2);
                  break;
              case 3:
                  $healthindex = $healthindex - ($data_measure['deviation']*3);
                  break;
          }
        }
        //json_encode array
        $data = json_encode($data,JSON_UNESCAPED_UNICODE);
        
        //Check if record exists
        $sql = 'SELECT * FROM equipment_data WHERE equipmentid = ? and historyid =?';
        $stmt = $pdo->prepare($sql);
        $stmt->execute([$identification[2],$identification[3]]);
        $equipment_data = $stmt->fetchAll(PDO::FETCH_ASSOC);

        if (!empty($equipment_data)){
            //EXIST UPDATE
            $sql = 'UPDATE equipment_data SET measurement =  ?, healthindex = ? WHERE equipmentid = ? and historyid = ?';    
        } 
        else {
            //EXIST INSERT
            $sql = 'INSERT INTO equipment_data (measurement, healthindex, equipmentid, historyid) VALUES (?,?,?,?)';   
        }

        //EXECUTE QUERY
        $stmt = $pdo->prepare($sql);
        $stmt->execute([$data, $healthindex, $identification[2],$identification[3]]);
        //$equipment_data = $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
  }
}

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
// calculatehealthindex of asset                ++++++++++
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
function assetHealthIndex($prof,$pem,$healthdata,$type){

  $healthindex = 100;
  //Allowed check
  if (isAllowed('equipment_data',$prof,$pem,'R') === 1 && !empty($healthdata)){
         
    //GET last data based on type returned
    //Type
    // 0 = $healthdata per equipmentid
    // 1 = $healthdata per rowID of equipment_data
    switch ($type) {
      case 0:
        $last_data_measurement = end($healthdata);
        break;   
      default:
        $last_data_measurement = $healthdata;
        
        break;
    }
    //Ensure $last_data_measurement is an array
    $last_data_measurement = (is_object($last_data_measurement))? (array) $last_data_measurement : $last_data_measurement;

    foreach (json_decode($last_data_measurement['measurement'],true) as $data_measure){
        
        switch ($data_measure['deviation']) {
            case 1:
                $healthindex = $healthindex - $data_measure['deviation'];
                break;
            case 2:
                $healthindex = $healthindex - ($data_measure['deviation']*2);
                break;
            case 3:
                $healthindex = $healthindex - ($data_measure['deviation']*3);
                break;
        }
    }

  } 
  //Not allowed or no data return 100% health  
return $healthindex;
}

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Block contracts                          ++++++++++++++
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
function blockContracts($token){

  include dirname(__FILE__,2).'/settings/settings_redirector.php';

  //CALL TO API
  $api_url = '/v2/contracts/status=1&type=0';
  $responses = ioAPIv2($api_url,'',$token);
  //Decode Payload
  if (!empty($responses)){$responses = json_decode($responses,true);}else{$responses = null;}

  foreach ($responses as $response){

    //GET BILLING DATA
    $billing_plan = $response['billing_plan'];
    $billing_max = $response['service_count'];

    //DECODE ARRAYs
    $servicetools = json_decode($response['servicetool'],true) ?? ''; 
    $assigned_users = json_decode($response['assigned_users'],true) ?? ''; 
    $ignore_lists = json_decode($response['ignore_list'],true) ?? ''; 

    //get all assigned serialnumbers
    $url_input = '';
    foreach($servicetools as $service_tool){
        $url_input .= $service_tool.',';
    }
    //get ignore list
    $ignored_serialnumbers = '';
    if (!empty($ignore_lists)){ 
        foreach($ignore_lists as $list){
            $ignored_serialnumbers .= $list.',';
        }
        $ignored_serialnumbers = '&ignore='.substr($ignored_serialnumbers,0,-1);
    }
    //GET END DATA
    $contract_end_date = date('Y-m-d', strtotime('+'.$response['duration'].' months', strtotime($response['start_date'])));
                
    //Return report_usage_servicereports
    $api_url = '/v2/application/type=ServiceReport&serialnumber='.substr($url_input,0,-1).$ignored_serialnumbers.'&between='.$response['start_date'].'||'.$contract_end_date.'/contract_usage_servicereports';
    $contract_usage_servicereports = ioAPIv2($api_url,'',$token);

    //Decode Payload
    if (!empty($contract_usage_servicereports)){$contract_usage_servicereports = json_decode($contract_usage_servicereports,true);}else{$contract_usage_servicereports = null;}

    //GET USAGE BILLING INFORMATION
    $usage_billing = usageBilling($contract_usage_servicereports);
    $billing_cylce_usage = (($billing_plan == 1 && isset($usage_billing[$curYear]['quarters'][$curQuarter]['months'][$curMonth])) ? $usage_billing[$curYear]['quarters'][$curQuarter]['months'][$curMonth] : (($billing_plan == 2 && isset($usage_billing[$curYear]['quarters'][$curQuarter])) ? $usage_billing[$curYear]['quarters'][$curQuarter]: (($billing_plan == 3 && isset($usage_billing[$curYear])) ? $usage_billing[$curYear]: 0 )));

    //CHECK FOR OVERRUN
    if ($billing_cylce_usage >= $billing_max){
        //overrun - set contract status to 3 - block and Inactivate service for all assigned users
        $data = json_encode(array("rowID" => $response['rowID'], "status" => "3", "assigned_users" => $assigned_users), JSON_UNESCAPED_UNICODE);
        //API call
        ioAPIv2('/v2/contracts', $data,$token);
    }  
  }
}

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
// check date is in range                   ++++++++++++++
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
function dateInRange($start_date, $end_date, $date_check)
{
  // Convert to timestamp
  $start_ts = strtotime($start_date);
  $end_ts = strtotime($end_date);
  $check_ts = strtotime($date_check);

  // Check that user date is between start & end
  return (($check_ts >= $start_ts) && ($check_ts <= $end_ts));
}

function getLatestVersion($productcode,$token){

  //CALL TO API TO GET ALL ACTIVE CONTRACTS
  $api_url = '/v2/products_software/productcode='.$productcode;
  $responses = ioAPIv2($api_url,'',$token);
  
  //Decode Payload
  if (!empty($responses)){$responses = json_decode($responses,true);
  }
  else{
    $responses =  $output = array(
                            "productcode" => "",
                            "version"=> "",
                            "mandatory"=> "",
                            "latest"=> "",
                            "software"=> "",
                            "source" => "",
                            "source_type" => ""
                          );
                    ;}

  //DEFAULT OUTPUT
  return $responses;  
}

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Timestamp converter                      ++++++++++++++
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
function getRelativeTime($timestamp) {

  if (!empty($timestamp) || $timestamp != ""){
    //GET TRANSLATION FILE
    if(isset($_SESSION['country_code'])){
      $api_file_language = dirname(__FILE__,2).'/settings/translations/translations_'.strtoupper($_SESSION['country_code']).'.php';
      if (file_exists($api_file_language)){   
          include $api_file_language; //Include the code
      }
      else {
          include dirname(__FILE__,2).'/settings/translations/translations_US.php';
      }
      }
      else {
          include dirname(__FILE__,2).'/settings/translations/translations_US.php';
      }  

    // Ensure the timestamp is a valid integer
    $timestamp = is_numeric($timestamp) ? $timestamp : strtotime($timestamp);
    
    // Get current timestamp and calculate difference
    $now = time();
    $diff = $now - $timestamp;
    
    // Define time periods
    $minute = 60;
    $hour = $minute * 60;
    $day = $hour * 24;
    $week = $day * 7;
    $month = $day * 30;
    $year = $day * 365;
    
    // Handle future timestamps
    if ($diff < 0) {
        $diff = abs($diff);
        $suffix = $time_from_now;
    } else {
        $suffix = $time_ago;
    }
    
    // Determine the appropriate time description
    if ($diff < $minute) {
        return $time_just_now;
    } elseif ($diff < $hour) {
        $minutes = floor($diff / $minute);
        return $minutes.(($minutes != 1) ? $time_minutes : $time_minute) . " $suffix";
    } elseif ($diff < $day) {
        $hours = floor($diff / $hour);
        return $hours.(($hours != 1) ? $time_hours : $time_hour) . " $suffix";
    } elseif ($diff < $week) {
        $days = floor($diff / $day);
        
        // Special handling for today and yesterday
        if ($days == 0) {
            return $time_today;
        } elseif ($days == 1) {
            return $time_yesterday;
        }
        
        return $days.(($days != 1)?$time_days:$time_day) . " $suffix";
    } elseif ($diff < $month) {
        $weeks = floor($diff / $week);
        return $weeks.(($weeks != 1)?$time_weeks:$time_week) . " $suffix";
    } elseif ($diff < $year) {
        $months = floor($diff / $month);
        return $months.(($months != 1)?$time_months:$time_month) . " $suffix";
    } else {
        $years = floor($diff / $year);
        return $years.(($years != 1)?$time_years:$time_year) . " $suffix";
    }
  }
}

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Generate language files                  ++++++++++++++
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++

function generateLanguageFile($language_key,$token){

  function generateFile($language_key,$token){
  //GET TRANSLATION RECORDS
  $api_url = '/v2/translations/generatefile='.$language_key;
  $responses = ioAPIv2($api_url,'',$token);

    if (!empty($responses)){
      //define translation variable
      $translation = '<?php'.PHP_EOL;
      
      //decode the API response
      $responses = json_decode($responses,true);
      
      //loop through translation records and create variables
      foreach ($responses as $response){
        //create variable_name = translation per item
        $translation .= '$'.$response['variable'].' = \''.$response['translation'].'\';'.PHP_EOL;  
      }
      //ADD closure tag for PHP
      $translation .= '?>';
      //Target dir
      $target_dir = dirname(__FILE__,2).'/settings/translations/';
      //Filename
      $input_file = $target_dir.'translations_'.strtoupper($language_key).'.php';
      //store translation to the file
      file_put_contents($input_file, $translation);
    } 
  }

  if ($language_key != ''){
      generateFile($language_key,$token);
  } else {
      include dirname(__FILE__,2).'/settings/settingsmenu.php';

      foreach ($supportedLanguages as $language){
        generateFile($language,$token);
    }
  }
  
}
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Removekeys from array                    ++++++++++++++
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
function removeKeysRecursive(array &$array, array $keysToRemove): void {
  foreach ($array as $key => &$value) {
      // Remove the key if it exists in our removal list
      if (in_array($key, $keysToRemove, true)) {
          unset($array[$key]);
          continue;
      }
      
      // If value is an array, recursively process it
      if (is_array($value)) {
          removeKeysRecursive($value, $keysToRemove);
          
          // If array is empty after processing, remove it
          if (empty($value)) {
              unset($array[$key]);
          }
      }
  }
}
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Catalogprocessor                         ++++++++++++++
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
function processProductCollection($products) {
  $processedProducts = [];
  
  foreach ($products as $key => $product) {
      // Check if product has versions
      if (isset($product['versions']) && !empty($product['versions'])) {
          // Check if there's only one version
          $singleVersion = count($product['versions']) === 1;
          
          // For each version, create a new product entry
          foreach ($product['versions'] as $version) {
              // Create a copy of the base product
              $versionProduct = $product;
              
              // Remove the versions array
              unset($versionProduct['versions']);
              
              // Add version specific data
              $versionProduct['version_id'] = $version['version_id'];
              $versionProduct['config_setting'] = $version['config_setting'];
              $versionProduct['configurations'] = $version['configurations'];
              
              // Only modify identifiers if there's more than one version
              if (!$singleVersion) {
                  // Create a unique rowID for the new product
                  $versionProduct['rowID'] = $versionProduct['rowID'] . '_v' . $version['version_id'];
                  
                  // Add version suffix to productcode and url_slug
                  $versionProduct['productcode'] = $versionProduct['productcode'] . '_v' . $version['version_id'];
                  if (!empty($versionProduct['url_slug'])) {
                      $versionProduct['url_slug'] = $versionProduct['url_slug'] . '_v' . $version['version_id'];
                  }
                  
                  // Add version to product name if needed
                  $versionProduct['productname'] = $versionProduct['productname'] . ' (v' . $version['version_id'] . ')';
              }
              
              // Add to processed products
              $processedProducts[] = $versionProduct;
          }
      } else {
          // If no versions, add product as is
          $processedProducts[] = $product;
      }
  }
  
  return $processedProducts;
}

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
// CalculateTotalPrice based on options     ++++++++++++++
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
function calculateTotalPrice($product_data, $selected_options) {
  $base_price = floatval($product_data['price']);
  $total_price = $base_price;
  $selected_item_names = [];

  foreach ($product_data['configurations'] as $config) {
      // Handle group configurations
      if (isset($config['attributes']) && 
          isset($selected_options[$config['assignment']])) {
          
          $selected_group_attributes = $selected_options[$config['assignment']];

          foreach ($selected_group_attributes as $selected_attribute_id) {
              foreach ($config['attributes'] as $attribute) {
                  if ($attribute['attribute_id'] == $selected_attribute_id) {
                      $total_price += $attribute['price_modifier'] == 1 
                          ? floatval($attribute['price']) 
                          : -floatval($attribute['price']);
                      
                      // Collect item names
                      $selected_item_names[] = $attribute['item_name'];
                  }
              }
          }
      }
      
      // Handle additional products
      if (isset($selected_options['products']) && 
          $config['type'] == 'product' && 
          in_array($config['assignment'], $selected_options['products'])) {
          
          /*/Include Pricing of optional products 
          $total_price += $config['price_modifier'] == 1 
              ? floatval($config['price']) 
              : -floatval($config['price']);
          */
          // Collect product names
          $selected_item_names[] = $config['assignment_name'];
      }
  }

  return [
      'total_price' => $total_price,
      'selected_items' => implode(', ', $selected_item_names)
  ];
}

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ShoppingCartCalulator                    ++++++++++++++
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
class ShoppingCartCalculator {
  private $products;
  private $selected_country;
  private $selected_shipping_method;
  private $business_type;
  private $discount_code;
  private $db;
  private $discount_message;
  private $tax_rate;

  public function __construct($products, $selected_country, $selected_shipping_method, $business_type, $discount_code, $db) {
      $this->products = $products;
      $this->selected_country = $selected_country;
      $this->selected_shipping_method = $selected_shipping_method;
      $this->business_type = strtolower($business_type);
      $this->discount_code = $discount_code;
      $this->db = $db;
      $this->discount_message = '';
      $this->tax_rate = $this->getTaxRate();
  }

  public function calculateTotals() {
      // Calculate basic totals
      $subtotal = $this->calculateSubtotal();
      $weighttotal = $this->calculateWeightTotal();
      $shippingtotal = $this->calculateShippingTotal($subtotal, $weighttotal,$this->selected_shipping_method);
      $discounttotal = $this->calculateDiscountTotal();
      $taxtotal = $this->calculateTaxTotal($subtotal - $discounttotal + $shippingtotal);
      
      // Calculate final total based on business type
      $total = $this->calculateFinalTotal($subtotal, $shippingtotal, $discounttotal, $taxtotal);


      return [
          'cart_details' => [
              'products' => $this->products,
              'selected_country' => $this->selected_country,
              'selected_shipping_method' => $this->selected_shipping_method,
              'business_type' => $this->business_type,
              'discount_code' => $this->discount_code
              
          ],
          'totals' => [
              'subtotal' => number_format($subtotal, 2, '.', ''),
              'weighttotal' => number_format($weighttotal, 2, '.', ''),
              'shippingtotal' => number_format($shippingtotal, 2, '.', ''),
              'discounttotal' => number_format($discounttotal, 2, '.', ''),
              'discount_message' => $this->discount_message,
              'tax_rate' => number_format($this->tax_rate, 2, '.', '') . '%',
              'taxtotal' => number_format($taxtotal, 2, '.', ''),
              'total' => number_format($total, 2, '.', '')
          ]
      ];
  }


  private function getTaxRate() {
      $sql = "SELECT rate FROM taxes WHERE id = ?";
      $stmt = $this->db->prepare($sql);
      $stmt->execute([$this->selected_country]);
      $tax = $stmt->fetch(PDO::FETCH_ASSOC);
      return $tax ? floatval($tax['rate']) : 0;
  }
  
  private function calculateSubtotal() {
      $subtotal = 0;
      foreach ($this->products as $product) {
          $product_price = floatval(str_replace(',', '.', $product['options_price']));
          $subtotal += $product_price * $product['quantity'];
      }
      return $subtotal;
  }

  private function calculateWeightTotal() {
      $weighttotal = 0;
      foreach ($this->products as $product) {
          $options_weight = floatval($product['options_weight']);
          $weighttotal += $options_weight * $product['quantity'];
      }
      return $weighttotal;
  }

  private function calculateDiscountTotal() {
      if (empty($this->discount_code)) {
          $this->discount_message = '';
          return 0;
      }

      $current_date = date('Y-m-d H:i:s');
      
      // First check if discount code exists and is valid
      $sql = "SELECT * FROM discounts WHERE discount_code = ?";
      $stmt = $this->db->prepare($sql);
      $stmt->execute([$this->discount_code]);
      $discount = $stmt->fetch(PDO::FETCH_ASSOC);

      if (!$discount) {
          $this->discount_message = 'Invalid discount code';
          return 0;
      }

      // Check date validity
      if ($current_date < $discount['start_date']) {
          $this->discount_message = 'Discount code not yet active';
          return 0;
      }

      if ($current_date > $discount['end_date']) {
          $this->discount_message = 'Discount code expired';
          return 0;
      }

      // Convert string of IDs to arrays
      $discount_product_ids = !empty($discount['product_ids']) ? 
          array_map('trim', explode(',', $discount['product_ids'])) : [];
      $discount_category_ids = !empty($discount['category_ids']) ? 
          array_map('trim', explode(',', $discount['category_ids'])) : [];

      $discounttotal = 0;
      $eligible_products_found = false;
      $total_eligible_price = 0;

      // Calculate total eligible price
      foreach ($this->products as $product) {
          if ($this->isProductEligibleForDiscount($product, $discount_product_ids, $discount_category_ids)) {
              $eligible_products_found = true;
              $product_price = floatval(str_replace(',', '.', $product['options_price'])) * $product['quantity'];
              $total_eligible_price += $product_price;
          }
      }

      // Calculate discount if eligible products found
      if ($eligible_products_found) {
          if ($discount['discount_type'] == 1) {
              // Percentage discount
              $discounttotal = $total_eligible_price * ($discount['discount_value'] / 100);
          } else {
              // Fixed amount discount
              $discounttotal = min($discount['discount_value'], $total_eligible_price);
          }

          $discount_type = $discount['discount_type'] == 1 ? 
              $discount['discount_value'] . '% discount' : 
              '€' . number_format($discount['discount_value'], 2) . ' discount';
          $this->discount_message = "Discount applied successfully: " . $discount_type;
      } else {
          $this->discount_message = 'No eligible products for this discount code';
          $discounttotal = 0;
      }

      return $discounttotal;
  }

  private function isProductEligibleForDiscount($product, $discount_product_ids, $discount_category_ids) {
      // If no specific products or categories are set, discount applies to all products
      if (empty($discount_product_ids) && empty($discount_category_ids)) {
          return true;
      }

      $product_match = false;
      $category_match = false;

      // Check product ID match
      if (!empty($discount_product_ids)) {
          $product_match = in_array($product['id'], $discount_product_ids);
          
          // If only product IDs are specified (no categories), return the product match result
          if (empty($discount_category_ids)) {
              return $product_match;
          }
      } else {
          // If no product IDs specified, set product_match to true
          $product_match = true;
      }

      // Check category match
      if (!empty($discount_category_ids)) {
          if (isset($product['meta']['category_ids'])) {
              $product_categories = is_array($product['meta']['category_ids']) ? 
                  $product['meta']['category_ids'] : 
                  array_map('trim', explode(',', $product['meta']['category_ids']));
              
              $category_match = !empty(array_intersect($product_categories, $discount_category_ids));
          } else {
              $category_match = false;
          }

          // If only categories are specified (no products), return the category match result
          if (empty($discount_product_ids)) {
              return $category_match;
          }
      } else {
          // If no categories specified, set category_match to true
          $category_match = true;
      }

      // If both product IDs and categories are specified, both must match
      return $product_match && $category_match;
  }

  private function calculateShippingTotal($subtotal, $weighttotal,$selected_shipping_method) {

      
      //USER PROVIDED SHIPMENT METHOD
      $sql = "SELECT price FROM shipping WHERE ID = ?";
      $stmt = $this->db->prepare($sql);
      $stmt->execute([$this->selected_shipping_method]);
     
      $shipping = $stmt->fetch(PDO::FETCH_ASSOC);
      return $shipping ? floatval($shipping['price']) : 0;
  }

  private function calculateTaxTotal($amount_to_tax) {
      $sql = "SELECT rate FROM taxes WHERE id = ?";
      $stmt = $this->db->prepare($sql);
      $stmt->execute([$this->selected_country]);
      $tax = $stmt->fetch(PDO::FETCH_ASSOC);
      
      return $tax ? ($amount_to_tax * ($tax['rate'] / 100)) : 0;
  }

  private function calculateFinalTotal($subtotal, $shippingtotal, $discounttotal, $taxtotal) {
      $base = $subtotal - $discounttotal + $shippingtotal;
      
      if ($this->business_type === 'b2c') {
          // Tax is included in final price
          return $base;
      } else {
          // Tax is added on top for B2B
          return $base + $taxtotal;
      }
  }
}

function validateCheckoutData($post_content) {
  $errors = [];
  
  // Required fields for checkout input
  $required_checkout_fields = [
      'cart' => 'Products',
      'checkout_input.selected_country' => 'Country',
      'checkout_input.selected_shipment_method' => 'Shipping method',
      'checkout_input.business_type' => 'Business type',
      'checkout_input.payment_method' => 'Payment method'
  ];
  
  // Required fields for customer details
  $required_customer_fields = [
      'customer_details.email' => 'Email',
      'customer_details.first_name' => 'First name',
      'customer_details.last_name' => 'Last name',
      'customer_details.address_street' => 'Street address',
      'customer_details.address_city' => 'City',
      'customer_details.address_zip' => 'ZIP code',
      'customer_details.address_country' => 'Country',
      'customer_details.address_phone' => 'Phone number'
  ];
  
  // Validate checkout input fields
  foreach ($required_checkout_fields as $field => $label) {
      $keys = explode('.', $field);
      if (count($keys) === 1) {
          if (!isset($post_content[$keys[0]]) || empty($post_content[$keys[0]])) {
              $errors[] = "$label is required";
          }
      } else {
          if (!isset($post_content[$keys[0]][$keys[1]]) || empty($post_content[$keys[0]][$keys[1]])) {
              $errors[] = "$label is required";
          }
      }
  }
  
  // Validate customer details fields
  foreach ($required_customer_fields as $field => $label) {
      $keys = explode('.', $field);
      if (!isset($post_content[$keys[0]][$keys[1]]) || empty($post_content[$keys[0]][$keys[1]])) {
          $errors[] = "$label is required";
      }
  }
  
  // Additional validation for email format
  if (isset($post_content['customer_details']['email']) && !empty($post_content['customer_details']['email'])) {
      if (!filter_var($post_content['customer_details']['email'], FILTER_VALIDATE_EMAIL)) {
          $errors[] = "Invalid email format";
      }
  }
  
  // Additional validation for phone number (basic format check)
  if (isset($post_content['customer_details']['address_phone']) && !empty($post_content['customer_details']['address_phone'])) {
      if (!preg_match("/^[0-9\-\(\)\/\+\s]*$/", $post_content['customer_details']['address_phone'])) {
          $errors[] = "Invalid phone number format";
      }
  }
  
  return $errors;
}

function validateTransactionData($post_content) {
  $errors = [];
  
  // Required fields for customer details
  $required_fields = [
      'customer_details.email' => 'Email',
      'customer_details.first_name' => 'First name',
      'customer_details.last_name' => 'Last name',
      'customer_details.address_street' => 'Street address',
      'customer_details.address_city' => 'City',
      'customer_details.address_zip' => 'ZIP code',
      'customer_details.address_country' => 'Country',
      'total.payment_amount' => 'Payment_amount',

  ];
    
  // Validate customer details fields
  foreach ($required_fields as $field => $label) {
      $keys = explode('.', $field);
      if (!isset($post_content[$keys[0]][$keys[1]]) || empty($post_content[$keys[0]][$keys[1]])) {
          $errors[] = "$label is required";
      }
  }

  return $errors;
}

function getCountryNamesByIds($countries, $idString) {
  // Create a lookup array where ID is the key and country name is the value
  $countryMap = array_column($countries, 'country', 'id');
  
  // Convert comma-separated string to array
  $ids = explode(',', $idString);
  
  // Get country names for each ID
  $countryNames = [];
  foreach ($ids as $id) {
      $id = trim($id);
      if (isset($countryMap[$id])) {
          $countryNames[] = $countryMap[$id];
      }
  }
  
  return $countryNames;
}

function transformOrderData(array $orderData): array {
  // Initialize the result array with the first row's common data
  $firstRow = $orderData[0];
  
  $result = [
      'header' => [
        "id" => $firstRow['id'],
        "txn_id" => $firstRow['txn_id'],
        "payment_status" => $firstRow['payment_status'],
        "payment_method" => $firstRow['payment_method'],
        "shipping_method" => $firstRow['shipping_method'],
        "discount_code" => $firstRow['discount_code'],
        "created" => $firstRow['created'],
        "updated " => $firstRow['updated']
      ],
      'customer' => [
          'account_id' => $firstRow['account_id'],
          'email' => $firstRow['payer_email'],
          'name' => $firstRow['first_name'] . ' ' . $firstRow['last_name'],
          'street' => $firstRow['address_street'],
          'zip' => $firstRow['address_zip'],
          'state' => $firstRow['address_state'],
          'city' => $firstRow['address_city'],
          'country' => $firstRow['address_country'],
          'phone' => $firstRow['address_phone'],
          'language' => $firstRow['user_language'],
      ],
      'products' => [],
      'invoice' => [
          'id' => $firstRow['invoice'],
          'created' => $firstRow['invoice_created'],
          'payment_status' => $firstRow['payment_status']
      ],
      'pricing' => [
          'subtotal' => 0,
          'shipping_total' => $firstRow['shipping_amount'],
          'tax_total' => $firstRow['tax_amount'],
          'discount_total' => $firstRow['discount_amount'],
          'payment_amount' => $firstRow['payment_amount']
      ]
  ];
  
  // Process products from all rows
  foreach ($orderData as $row) {
      // Decode JSON string for item options
      $itemOptions = json_decode($row['item_options'], true) ?? [];
      
      // Calculate line total
      $lineTotal = floatval($row['item_price']) * intval($row['item_quantity']);
      
      // Add to subtotal
      $result['pricing']['subtotal'] += $lineTotal;
      
      // Add product information
      $result['products'][] = [
          'item_id' => $row['item_id'],
          'productcode' => $row['productcode'],
          'product_name' => $row['productname'],
          'options' => $itemOptions,
          'quantity' => $row['item_quantity'],
          'price' => $row['item_price'],
          'line_total' => number_format($lineTotal, 2, '.', '')
      ];
  }
  
  // Format monetary values
  $result['pricing']['subtotal'] = number_format($result['pricing']['subtotal'], 2, '.', '');
  $result['pricing']['shipping_total'] = number_format(floatval($result['pricing']['shipping_total']), 2, '.', '');
  $result['pricing']['tax_total'] = number_format(floatval($result['pricing']['tax_total']), 2, '.', '');
  $result['pricing']['discount_total'] = number_format(floatval($result['pricing']['discount_total']), 2, '.', '');
  $result['pricing']['payment_amount'] = number_format(floatval($result['pricing']['payment_amount']), 2, '.', '');
  
  return $result;
}

function transformOrders($inputData){

  // Define which fields are item-specific (will go into the items array)
$itemFields = ['item_id', 'item_name', 'item_price', 'item_quantity', 'item_options', 'full_path'];

// Process the data
$combinedData = [];

foreach ($inputData as $row) {
    $txnId = $row['txn_id'];
    
    // Create header and item arrays for the current row
    $headerData = [];
    $itemData = [];
    
    foreach ($row as $key => $value) {
        if (in_array($key, $itemFields)) {
            // This is an item field
            $itemData[$key] = $value;
        } else {
            // This is a header field
            $headerData[$key] = $value;
        }
    }
    
    // Check if this transaction ID already exists in our result array
    if (!isset($combinedData[$txnId])) {
        // First occurrence of this transaction - create the structure
        $combinedData[$txnId] = [
            'header' => $headerData,
            'items' => [$itemData]
        ];
    } else {
        // Transaction already exists - just add the item data
        $combinedData[$txnId]['items'][] = $itemData;
    }
}

// Convert associative array to indexed array if needed
$finalResult = array_values($combinedData);

return $finalResult;
}
//=============================================
// Use giftcart
//=============================================

function useGiftCart($pdo, $discount_code, $accounthierarchy){
   
  // Get the current date
  $end_date = date("Y-m-d H:i:s");

  //Check if Giftcard already exists
  $stmt = $pdo->prepare('SELECT * from discounts WHERE discount_code = ? AND accounthierarchy = ?');
  $stmt->execute([$discount_code,$accounthierarchy]);
  $discount_exist = $stmt->fetchAll(PDO::FETCH_ASSOC);

  if (!empty($discount_exist) || $discount_exist != '') {
      //Update Giftcard end data
      $stmt = $pdo->prepare('UPDATE discounts SET end_date = ? WHERE discount_code = ? AND accounthierarchy = ?');
      $stmt->execute([$end_date,$discount_code, $accounthierarchy]);
  }
}

function createGiftCart($pdo, $orderID, $giftcard_categoryID,$accounthierarchy){
   
  //Check if Giftcard is ordered
  $stmt = $pdo->prepare('SELECT t.payer_email as email, ti.id as id, t.txn_id as txn, ti.item_price as item_price, ti.item_quantity as item_quantity FROM transactions t INNER JOIN transactions_items ti ON t.txn_id = ti.txn_id INNER JOIN products_categories p ON ti.item_id = p.product_id WHERE p.category_id = ? AND ti.txn_id = ? AND accounthierarchy = ?');
  $stmt->execute([$giftcard_categoryID,$orderID,$accounthierarchy]);
  $giftcards = $stmt->fetchAll(PDO::FETCH_ASSOC);
  
  if ($giftcards) {
      foreach ($giftcards as $giftcard) {
       
          //For each quantity
          $x = 0;
         
          while ($x < $giftcard['item_quantity']){
              
              //Generate discount code = TXN/ID/X
              $discount_code = $giftcard['txn'].'#'.$giftcard['id'].'#'.$x;
              $value = $giftcard['item_price'];

              // Get the current date
              $start_date = date("Y-m-d H:i:s");
              $end_date = date("Y-m-d H:i:s", strtotime("+5 years"));;

              //Check if Giftcard already exists
              $stmt = $pdo->prepare('SELECT * from discounts WHERE discount_code = ? AND accounthierarchy = ?');
              $stmt->execute([$discount_code,$accounthierarchy]);
              $discount_exist = $stmt->fetchAll(PDO::FETCH_ASSOC);
              
              if (empty($discount_exist) || $discount_exist == '') {
                  //Insert Giftcard
                  $discount_type = 0; //Fixed
                  //SQL Insert
                  $stmt = $pdo->prepare('INSERT INTO discounts (discount_code,discount_type,discount_value,start_date,end_date,accounthierarchy) VALUES (?,?,?,?,?,?)');
                  $stmt->execute([$discount_code, $discount_type, $value, $start_date, $end_date,$accounthierarchy]);
              }
              $x++;
          }    
      } 
      
  }
}

//=======================================
// findGitCommitHash
//=======================================
function findShortGitCommitHash($string) {
  // Step 1: Find all hexadecimal sequences
  preg_match_all('/[0-9a-f]+/i', $string, $matches);
  $allHexMatches = $matches[0] ?? [];
  
  // Step 2: Filter to only include those with exactly 6 or 7 characters
  $commitHashes = array_filter($allHexMatches, function($match) {
      return strlen($match) === 6 || strlen($match) === 7;
  });
  
  return array_values($commitHashes); // Re-index array
}

function compareCommitCodes($stringA, $stringB) {
  // Get commit codes from both strings
  $commitCodesA = findShortGitCommitHash($stringA);
  $commitCodesB = findShortGitCommitHash($stringB);
  
  // Case 1: Check if there are matching commit codes between A and B
  foreach ($commitCodesA as $codeA) {
      if (in_array($codeA, $commitCodesB)) {
          return $codeA; // Return the first matching commit code
      }
  }
  
  // Case 2: If A has commit code but B doesn't
  if (count($commitCodesA) > 0 && count($commitCodesB) === 0) {
      return $commitCodesA[0]; // Return the first commit code from A
  }
  
  // Case 3: If A has no commit code but B does
  if (count($commitCodesA) === 0 && count($commitCodesB) > 0) {
      return $commitCodesB[0]; // Return the first commit code from B
  }
  
  // Case 4: Neither has commit code
  return "";
}
//=======================================
// Function to find the first existing view
//=======================================

function findExistingView($viewsArray, $defaultView, $ignoreViews) {
  foreach ($viewsArray as $view) {

      $file_to_check = $view.'.php';

      if (in_array($view, $ignoreViews)) {
        continue;
      }

      if (file_exists($file_to_check)) {
          return $view;
      }
  }
  // If no view exists, return the default
  return $defaultView;
}
//=======================================
// Function to find the domain
//=======================================
function getDomainName($hostname) {
  // Extract the domain parts
  $parts = explode('.', $hostname);
  $count = count($parts);
  
  // For hostnames with enough parts to have a subdomain (at least 3 parts)
  if ($count >= 3) {
      // Return the second-to-last and third-to-last parts
      return $parts[$count - 2];
  } 
  // For hostnames with just domain and TLD (2 parts)
  else if ($count == 2) {
      // Return just the domain part (without the TLD)
      return $parts[0];
  }
  // If it's a single part hostname
  else {
      return $hostname;
  }
}

//=======================================
// encode ID to UUID
//=======================================
function encodeUuid($number) {
  $alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%&?-';
  $base = strlen($alphabet);
  
  $encoded = '';
  while ($number) {
      $encoded = $alphabet[$number % $base] . $encoded;
      $number = floor($number / $base);
  }
  
  $encoded = $encoded ?: '0';
  
  // Pad with leading zeros from the alphabet (which is '0') if shorter than 5 characters
  while (strlen($encoded) < 5) {
      $encoded = '0' . $encoded;
  }
  
  return $encoded;
}
//=======================================
// decode UUID to ID
//=======================================
function decodeUuid($encoded) {
  $encoded = strtoupper($encoded);

  $alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%&?-';
  $base = strlen($alphabet);
  
  $number = 0;
  $length = strlen($encoded);
  
  for ($i = 0; $i < $length; $i++) {
      $char = $encoded[$i];
      $position = strpos($alphabet, $char);
      
      if ($position === false) {
          // Character not found in alphabet
          return false;
      }
      
      $number = $number * $base + $position;
  }
  
  return $number;
}

/**
 * Generate marketing content for a spa/hot tub company based on business criteria
 * 
 * @param string $companyName The name of the company
 * @param string $city The city location
 * @param bool $gardenCenter Whether the company is a garden center
 * @param string $brandType Single brand or Multi brand
 * @param string $showroomSize Normal, Large, or Extra Large
 * @param string $offering Economy-Premium or Premium-Highend
 * @param string $dealerType Local, Professional, or Corporate
 * @param bool $multipleLocations Whether the company has multiple locations
 * @return array An array containing short description, long description, and unique selling points
 */
function generateSpaCompanyContent($companyName, $city, $gardenCenter, $brandType, $showroomSize, $offering, $dealerType, $multipleLocations) {
  // Determine content template to use based on criteria combination
  $templateIndex = determineTemplateIndex($gardenCenter, $brandType, $offering, $dealerType, $multipleLocations);
  
  // Get content templates
  $shortDescTemplates = getShortDescriptionTemplates();
  $longDescTemplates = getLongDescriptionTemplates();
  $uspTemplates = getUniqueSellingPointsTemplates();
  
  // Replace placeholders in templates
  $shortDescription = str_replace(
      ['{CompanyName}', '{City}', '{BrandType}', '{ShowroomSize}'],
      [$companyName, $city, $brandType, $showroomSize],
      $shortDescTemplates[$templateIndex]
  );
  
  $longDescription = str_replace(
      ['{CompanyName}', '{City}', '{BrandType}', '{ShowroomSize}'],
      [$companyName, $city, $brandType, $showroomSize],
      $longDescTemplates[$templateIndex]
  );
  
  $usps = [];
  foreach ($uspTemplates[$templateIndex] as $usp) {
      $usps[] = str_replace(
          ['{CompanyName}', '{City}', '{BrandType}', '{ShowroomSize}'],
          [$companyName, $city, $brandType, $showroomSize],
          $usp
      );
  }
  
  return [
      'short_description' => $shortDescription,
      'long_description' => $longDescription,
      'usp1' => $usps[0],
      'usp2' => $usps[1],
      'usp3' => $usps[2]
  ];
}

/**
* Determine which template to use based on company criteria
*/
function determineTemplateIndex($gardenCenter, $brandType, $offering, $dealerType, $multipleLocations) {
  // This is a simplified method to select a template
  // In a real implementation, you might want more sophisticated logic
  if ($gardenCenter) {
      if (strpos($offering, 'Premium') !== false) {
          return 3; // Garden Center Premium
      } else {
          return 7; // Garden Center High-End
      }
  }
  
  if ($dealerType == 'Local') {
      if ($brandType == 'Single brand') {
          return strpos($offering, 'Economy') !== false ? 0 : 4; // Local Economy Single Brand or Local High-End Single Brand
      }
  }
  
  if ($dealerType == 'Professional') {
      if ($brandType == 'Single brand') {
          return 9; // Professional Single Brand Specialist
      } else {
          return strpos($offering, 'Economy') !== false ? 5 : 1; // Professional Economy Multi-Brand or Professional Premium Multi-Brand
      }
  }
  
  if ($dealerType == 'Corporate') {
      if ($multipleLocations) {
          return 2; // Corporate High-End Multi-Location
      } else {
          return 8; // Corporate Premium Multi-Brand
      }
  }
  
  if ($multipleLocations && strpos($offering, 'Economy') !== false) {
      return 6; // Multi-Location Economy Single Brand
  }
  
  // Default to template 0 if no conditions match
  return 0;
}

/**
* Get all short description templates
*/
function getShortDescriptionTemplates() {
  return [
      // 0. Local Economy Single Brand
      "{CompanyName} is {City}'s trusted provider of quality hot tubs and spas at affordable prices, featuring the complete {BrandType} collection in our {ShowroomSize} showroom.",
      
      // 1. Professional Premium Multi-Brand
      "{CompanyName} brings premium spa experiences to {City} with our curated selection of luxury brands in our {ShowroomSize} professional showroom.",
      
      // 2. Corporate High-End Multi-Location
      "With locations across the region including {City}, {CompanyName} delivers exceptional high-end spa solutions backed by corporate reliability and service excellence.",
      
      // 3. Garden Center Premium
      "{CompanyName} combines garden expertise with premium spa offerings in {City}, creating the perfect outdoor relaxation destinations within our {ShowroomSize} garden center.",
      
      // 4. Local High-End Single Brand
      "{CompanyName} is {City}'s exclusive dealer for {BrandType} luxury spas, offering personalized service in an intimate {ShowroomSize} showroom experience.",
      
      // 5. Professional Economy Multi-Brand
      "As {City}'s professional spa specialists, {CompanyName} presents affordable solutions from leading brands in our {ShowroomSize} showroom designed for every budget.",
      
      // 6. Multi-Location Economy Single Brand
      "{CompanyName} makes quality relaxation accessible across multiple locations including {City}, specializing exclusively in the reliable {BrandType} collection.",
      
      // 7. Garden Center High-End
      "Elevate your garden oasis with {CompanyName}'s selection of high-end spas and hot tubs, showcased within our {ShowroomSize} {City} garden center.",
      
      // 8. Corporate Premium Multi-Brand
      "{CompanyName} combines corporate expertise with personalized service in {City}, offering premium spa solutions from the industry's most respected brands.",
      
      // 9. Professional Single Brand Specialist
      "{City}'s dedicated {BrandType} specialists at {CompanyName} provide expert guidance and professional support in our {ShowroomSize} showroom."
  ];
}

/**
* Get all long description templates
*/
function getLongDescriptionTemplates() {
  return [
      // 0. Local Economy Single Brand
      "Welcome to {CompanyName}, {City}'s dedicated hot tub and spa center where affordability meets quality. Our {ShowroomSize} showroom exclusively features the complete {BrandType} line, offering reliable relaxation solutions for every home and budget. As a locally owned business, we take pride in providing personalized service to our neighbors while maintaining competitive pricing. Our knowledgeable staff guides you through the entire process from selection to installation, ensuring your perfect spa experience.",
      
      // 1. Professional Premium Multi-Brand
      "{CompanyName} has established itself as {City}'s premier destination for premium spa experiences. Our professional team showcases a carefully selected range of luxury brands in our {ShowroomSize} showroom, each chosen for superior craftsmanship and innovative features. We combine technical expertise with a consultative approach, helping clients discover the perfect spa solution for their lifestyle and wellness goals. From initial design consultation through professional installation and ongoing maintenance, our comprehensive service ensures a seamless ownership experience.",
      
      // 2. Corporate High-End Multi-Location
      "With our flagship location in {City} and showrooms across the region, {CompanyName} delivers unparalleled access to high-end spa solutions. Our corporate structure ensures consistent quality, competitive pricing, and exceptional service at every location. The {ShowroomSize} {City} showroom features our complete collection of luxury spa brands, each representing the pinnacle of design, technology, and comfort. Our team of spa professionals provides expert guidance backed by our company-wide commitment to customer satisfaction and long-term support.",
      
      // 3. Garden Center Premium
      "At {CompanyName}, we've expanded our {City} garden expertise to include premium spa and hot tub solutions that complement your outdoor living space. Our {ShowroomSize} garden center now showcases a thoughtfully curated selection of quality spas designed to transform your backyard into a year-round wellness retreat. Our unique perspective combines landscaping knowledge with spa technology expertise, allowing us to help you create integrated outdoor environments where garden beauty meets relaxation therapy. Visit our {City} location to explore how our premium spa offerings can enhance your garden sanctuary.",
      
      // 4. Local High-End Single Brand
      "{CompanyName} brings exclusive {BrandType} luxury spas to discerning clients throughout {City}. Our intimate {ShowroomSize} showroom creates a personalized shopping experience where you can explore every detail of these exceptional wellness products. As {City}'s dedicated {BrandType} specialists, we offer unmatched product knowledge and customization options not available elsewhere. Our commitment to white-glove service extends from your first consultation through years of ownership, with dedicated support from our team who knows your installation personally.",
      
      // 5. Professional Economy Multi-Brand
      "{CompanyName} was founded on the belief that quality relaxation should be accessible to everyone in {City}. Our {ShowroomSize} showroom features carefully selected spa brands that deliver reliable performance without premium price tags. Our professional team applies the same expertise and attention to detail regardless of your budget, helping you navigate options to find the perfect balance of features and affordability. We handle everything from site preparation to installation and maintenance education, ensuring a stress-free experience that matches our stress-relieving products.",
      
      // 6. Multi-Location Economy Single Brand
      "With {CompanyName}'s expanding presence across the region, including our {City} location, we've streamlined operations to bring you exceptional value through our exclusive partnership with {BrandType}. Our {ShowroomSize} showrooms showcase the complete range of these reliable spas, with consistent pricing and service standards at every location. By focusing on a single trusted manufacturer, we've developed specialized expertise that benefits our customers through knowledgeable guidance, efficient service, and optimized inventory that ensures prompt delivery and installation.",
      
      // 7. Garden Center High-End
      "{CompanyName} has evolved our {City} garden center concept to include a curated collection of high-end spas and hot tubs that represent the perfect fusion of nature and luxury. Our {ShowroomSize} showroom displays these premium wellness products in contextual settings that help you envision the transformation of your own outdoor space. Our unique approach combines horticultural expertise with spa technology knowledge, allowing us to create integrated relaxation environments that function beautifully through every season. Experience the difference at our {City} location, where garden artistry meets wellness innovation.",
      
      // 8. Corporate Premium Multi-Brand
      "As {City}'s corporate-backed premium spa provider, {CompanyName} combines the reliability of organizational strength with the personal touch of dedicated local experts. Our {ShowroomSize} showroom presents a comprehensive selection of premium brands, each meeting our rigorous standards for quality, innovation, and value. Our structured approach ensures consistency through every phase of ownership, from transparent pricing and professional needs assessment through expert installation and scheduled maintenance programs. Experience the confidence that comes from working with {City}'s most established spa provider.",
      
      // 9. Professional Single Brand Specialist
      "{CompanyName} has dedicated our {City} business to becoming the region's foremost experts in {BrandType} spas and hot tubs. Our {ShowroomSize} showroom is designed to showcase every model and feature in this exceptional line, with working displays that demonstrate the unique benefits of these wellness systems. Our professional staff undergoes specialized factory training, making them uniquely qualified to help you select, customize, and maintain your {BrandType} spa. Choose {City}'s only dedicated {BrandType} specialists for an ownership experience as refined as the products we represent."
  ];
}

/**
* Get all unique selling points templates
*/
function getUniqueSellingPointsTemplates() {
  return [
      // 0. Local Economy Single Brand
      [
          "Exclusive {BrandType} dealer offering the full product line at competitive prices",
          "Locally owned with personalized service from neighbors who care about your experience",
          "Complete solutions from selection through installation with no hidden costs"
      ],
      
      // 1. Professional Premium Multi-Brand
      [
          "Curated selection of premium brands chosen for superior quality and innovation",
          "Professional consultation process that matches your lifestyle with the perfect spa",
          "Comprehensive service from design consultation through lifetime maintenance"
      ],
      
      // 2. Corporate High-End Multi-Location
      [
          "Regional presence with consistent high-end offerings across all locations",
          "Corporate buying power delivering competitive pricing on luxury products",
          "Standardized excellence in customer care backed by substantial resources"
      ],
      
      // 3. Garden Center Premium
      [
          "Integrated approach to outdoor living combining garden expertise with spa technology",
          "Contextual showroom displays demonstrating how spas enhance garden environments",
          "Year-round wellness solutions that complement your existing garden investments"
      ],
      
      // 4. Local High-End Single Brand
      [
          "Exclusive {City} source for the complete {BrandType} luxury collection",
          "Intimate showroom experience with personalized attention to your specific needs",
          "Specialized knowledge of customization options not available at general retailers"
      ],
      
      // 5. Professional Economy Multi-Brand
      [
          "Carefully vetted affordable brands that maximize features while minimizing cost",
          "Professional guidance typically reserved for luxury customers, at every price point",
          "Transparent pricing with no compromise on installation quality or service"
      ],
      
      // 6. Multi-Location Economy Single Brand
      [
          "Specialized {BrandType} expertise developed through exclusive brand focus",
          "Consistent pricing and service standards across all regional locations",
          "Optimized inventory management ensuring faster delivery and installation"
      ],
      
      // 7. Garden Center High-End
      [
          "Unique perspective integrating luxury spas into complete garden environments",
          "Seasonal expertise ensuring your spa enhances your outdoor space year-round",
          "One-stop resource for creating cohesive outdoor relaxation destinations"
      ],
      
      // 8. Corporate Premium Multi-Brand
      [
          "Organizational strength providing stability and reliability throughout ownership",
          "Structured approach from consultation through installation and maintenance",
          "Corporate accountability backing every product sold and service performed"
      ],
      
      // 9. Professional Single Brand Specialist
      [
          "Deep {BrandType} expertise through specialized factory training and certification",
          "Complete demonstration capability showing every model in working condition",
          "Unmatched product knowledge of the complete {BrandType} feature set and options"
      ]
  ];
}


// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Generate dealer information               ++++++++++++++
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++

function generateDealerInformation($token){

  //INCLUDE US LANGUAGE
  include dirname(__FILE__,2).'/settings/translations/translations_US.php';

  //GET ALL DEALERS
  $api_url = '/v2/dealers/list=';
  $responses = ioAPIv2($api_url,'',$token);
  $log_results =[];

  if(!empty($responses)){
     //decode the API response
      $responses = json_decode($responses,true);
      
      //loop through translation records and create variables
      foreach ($responses as $response){

        $new_content = [];
        //Generate content for missing data
        $keysToCheck = ['short_description', 'long_description', 'usp1', 'usp2', 'usp3'];
      
        foreach ($keysToCheck as $key) {

          $gc = ($response['garden_center'] == 0 ? false : true);
          $ml = ($response['locations'] == 0 ? false : true);

          //GENERATE DATA
          $generated_content = generateSpaCompanyContent(
              $response['name'],    // Company name
              $response['city'],           // City
              $gc,                // Garden center (yes/no)
              ${'brand_type_'.$response['brand_type']},       // Brand type
              ${'showroom_size_'.$response['showroom_size']},              // Showroom size
              ${'focus_offering_'.$response['focus_offering']},  // Offering
              ${'dealer_type_'.$response['dealer_type']},              // Dealer type
              $ml                 // Multiple locations
          );

          if (isset($response[$key]) && (empty($response[$key]) || $response[$key] == '')) {
              $new_content['rowID'] = encodeUuid($response['rowID']);
              $new_content[$key] = $generated_content[$key]; 
          }
        }

         //GET ALL POST DATA
         $payload = json_encode($new_content, JSON_UNESCAPED_UNICODE);
         //API call
         $api_call = ioAPIv2('/v2/dealers', $payload,$token);
         $api_response = json_decode($api_call ,true);
         
         //Provide feedback
         $log_results[$response['rowID']] = $api_response['rowID'].' '.$api_response['status'];
      }
    } 
  return $log_results;
}
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function to check if origin matches allowed patterns
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++

 function isOriginAllowed($origin, $allowedPatterns) {
  if (empty($origin)) {
      return false;
  }
  
  // Parse the origin to get the host part
  $parsedOrigin = parse_url($origin);
  $host = $parsedOrigin['host'] ?? '';
  
  if (empty($host)) {
      return false;
  }
  
  // Check if the host matches any of our patterns (exact match or subdomain)
  foreach ($allowedPatterns as $pattern) {
      // Check for exact match
      if ($host === $pattern) {
          return true;
      }
      
      // Check for subdomain match (domain.example.com)
      $patternWithDot = '.' . $pattern;
      if (substr($host, -strlen($patternWithDot)) === $patternWithDot) {
          return true;
      }
  }
  
  return false;
}

function removeTrailingElement($string,$element) {
  // Trim whitespace from the end
  $trimmed = rtrim($string);
  
  // Check if the trimmed string is not empty and ends with a comma
  if (!empty($trimmed) && substr($trimmed, -1) === $element) {
      // Remove the last character (the comma)
      return substr($trimmed, 0, -1);
  }
  
  // Return original string if it doesn't end with a comma
  return $trimmed;
}

function processPostContent(array $post_content): array
{
    // Use provided values if they exist and are not empty
    if (isset($post_content['budget']) && !empty($post_content['budget'])) {
        $budget = $post_content['budget'];
    }

    if (isset($post_content['showroom_quality']) && !empty($post_content['showroom_quality'])) {
        $showroom_quality = $post_content['showroom_quality'];
    }

    if (isset($post_content['brand_category']) && !empty($post_content['brand_category'])) {
        $brand_category = $post_content['brand_category'];
    }

    // Check if 'focus_offering' is available and not empty
    if (isset($post_content['focus_offering']) && !empty($post_content['focus_offering'])) {
        // 1. Add budget based on focus_offering if budget wasn't provided
        if (!isset($budget)) {
            $post_content['budget'] = $post_content['focus_offering'];
        }

        // Ensure 'dealer_type' is available for showroom_quality logic
        if (isset($post_content['dealer_type'])) {
            $dealer_type = $post_content['dealer_type'];

            // 2, 3, 4. Determine showroom_quality if it wasn't provided
            if (!isset($showroom_quality)) {
                if ($post_content['focus_offering'] == 0 && $dealer_type == 0) {
                    $post_content['showroom_quality'] = 0;
                } elseif (($post_content['focus_offering'] == 0 && $dealer_type == 1) || ($post_content['focus_offering'] == 1 && $dealer_type == 0)) {
                    $post_content['showroom_quality'] = 1;
                } elseif ($post_content['focus_offering'] == 1 && $dealer_type == 1) {
                    $post_content['showroom_quality'] = 2;
                }
            }
        }
    }

    // 5. Determine brand_category based on showroom_quality if it exists and brand_category wasn't provided
    if (isset($post_content['showroom_quality']) && !isset($brand_category)) {

      if ($post_content['showroom_quality'] == 2){
        $post_content['brand_category'] = 2;
      } elseif ($post_content['showroom_quality'] == 0){
        $post_content['brand_category'] = 0;
      } else {
        $post_content['brand_category'] = 1;
      }
    }

    if (isset($post_content['name']) && (isset($post_content['dealer_slug']) && $post_content['dealer_slug'] == '')){
      $trimmedString = trim($post_content['name']);
      $post_content['dealer_slug'] = str_replace(" ", "_", $trimmedString);
    }
    
    return $post_content;
}