<?php
/**
 * Log the User Activity on a page
 * 
 * @since	2.4.5 (rewritten)
 * @author	Max Sternitzke <max.sternitzke@th-luebeck.de>
 */
class Trainingssystem_Plugin_Module_Logger{

	public function __construct() {

	}

	public function logPageView() {
		global $post;

		if(!is_admin() && !is_null($post) && 0 !== get_current_user_id() && !Trainingssystem_Plugin_Public::isUserModusRequest() && isset($_SERVER['HTTP_USER_AGENT'])) {
			$result = new WhichBrowser\Parser($_SERVER['HTTP_USER_AGENT']);

			$trainingssystem_Plugin_Database_Userlogs = new Trainingssystem_Plugin_Database_Userlogs();
            $trainingssystem_Plugin_Database_Userlogs->setPageid($post->ID);
            $trainingssystem_Plugin_Database_Userlogs->setEngineName($result->engine->getName());
            $trainingssystem_Plugin_Database_Userlogs->setIp($this->wp_privacy_anonymize_ip_extended($_SERVER['REMOTE_ADDR'], "*"));
            $trainingssystem_Plugin_Database_Userlogs->setUri($_SERVER['REQUEST_URI']);
            $trainingssystem_Plugin_Database_Userlogs->setReferred("directly");
            if(isset($_SERVER['HTTP_REFERER'])){
                $trainingssystem_Plugin_Database_Userlogs->setReferred($_SERVER['HTTP_REFERER']);
            }
            
			$trainingssystem_Plugin_Database_Userlogs->setDatetime(date ("Y-m-d H:i:s"));
            $trainingssystem_Plugin_Database_Userlogs->setUserid(get_current_user_id());

            $trainingssystem_Plugin_Database_Userlogs->setDeviceType($result->device->type);
            $trainingssystem_Plugin_Database_Userlogs->setBrowserName($result->browser->getName());
            $trainingssystem_Plugin_Database_Userlogs->setBrowserVersion($result->browser->getVersion());
            $trainingssystem_Plugin_Database_Userlogs->setOsName($result->os->getName());
            $trainingssystem_Plugin_Database_Userlogs->setOsVersion($result->os->getVersion());
            $trainingssystem_Plugin_Database_Userlogs->setDeviceModel($result->device->getModel());
			$trainingssystem_Plugin_Database_Userlogs->setDeviceManufaktur($result->device->getManufacturer());
			$trainingssystem_Plugin_Database_Userlogs->setDuration(0);

            $user_log_id = Trainingssystem_Plugin_Database::getInstance()->UserLogs->save($trainingssystem_Plugin_Database_Userlogs);
			
			if(!is_null($user_log_id)) {
				?>
				<script>
					let start = null;
					let fullTime = 0;
					document.addEventListener("load", function (event) {
						start = event.timeStamp;
					});
					document.addEventListener("visibilitychange", function logData(event) {
						if (document.visibilityState === "hidden") {
							let data = new FormData();
							data.append("action", "page_view_update_duration");
							data.append("logid", "<?php echo $user_log_id; ?>");
							fullTime += Math.round(event.timeStamp - start);
							data.append("time", fullTime);

							navigator.sendBeacon("<?php echo admin_url('admin-ajax.php'); ?>", data);
							
						} else {
							start = event.timeStamp;
						}
					});
				</script>
				<?php
			}
		}
	}

	public function page_view_update_duration() {
		if(isset($_POST['logid']) && is_numeric($_POST['logid']) && $_POST['logid'] > 0 &&
			isset($_POST['time']) && is_numeric($_POST['time']) && $_POST['time'] > 0 && 0 !== get_current_user_id()) {
				$userLog = Trainingssystem_Plugin_Database::getInstance()->UserLogs->getUserLog($_POST['logid'], get_current_user_id());
				if(!is_null($userLog)) {
					$time = $_POST['time'];
					// If Log with duration > 0 exists, add time
					// this might happen if page is re-opened from cache, so the log id stays the same
					if($userLog->getDuration() > 0) {
						$time += $userLog->getDuration();
					}
					Trainingssystem_Plugin_Database::getInstance()->UserLogs->updateTime($_POST['logid'], get_current_user_id(), $time);
				}
			}
			wp_die();
	}

	/**
	 * Adjusted wp_privacy_anonymize_ip-Function to support a symobol for IPv4 anonymization 
	 * and extended IPv6 anonymization (80 bits instead of 64 are being null'ed)
	 * 
	 * @return String anonymized IP-Adress
	 */
	function wp_privacy_anonymize_ip_extended( $ip_addr, $symbol = '0', $ipv6_fallback = false ) {
		// Detect what kind of IP address this is.
		$ip_prefix = '';
		$is_ipv6   = substr_count( $ip_addr, ':' ) > 1;
		$is_ipv4   = ( 3 === substr_count( $ip_addr, '.' ) );
	 
		if ( $is_ipv6 && $is_ipv4 ) {
			// IPv6 compatibility mode, temporarily strip the IPv6 part, and treat it like IPv4.
			$ip_prefix = '::ffff:';
			$ip_addr   = preg_replace( '/^\[?[0-9a-f:]*:/i', '', $ip_addr );
			$ip_addr   = str_replace( ']', '', $ip_addr );
			$is_ipv6   = false;
		}
	 
		if ( $is_ipv6 ) {
			// IPv6 addresses will always be enclosed in [] if there's a port.
			$left_bracket  = strpos( $ip_addr, '[' );
			$right_bracket = strpos( $ip_addr, ']' );
			$percent       = strpos( $ip_addr, '%' );
			$netmask       = 'ffff:ffff:ffff:0000:0000:0000:0000:0000';
	 
			// Strip the port (and [] from IPv6 addresses), if they exist.
			if ( false !== $left_bracket && false !== $right_bracket ) {
				$ip_addr = substr( $ip_addr, $left_bracket + 1, $right_bracket - $left_bracket - 1 );
			} elseif ( false !== $left_bracket || false !== $right_bracket ) {
				// The IP has one bracket, but not both, so it's malformed.
				return '::';
			}
	 
			// Strip the reachability scope.
			if ( false !== $percent ) {
				$ip_addr = substr( $ip_addr, 0, $percent );
			}
	 
			// No invalid characters should be left.
			if ( preg_match( '/[^0-9a-f:]/i', $ip_addr ) ) {
				return '::';
			}
	 
			// Partially anonymize the IP by reducing it to the corresponding network ID.
			if ( function_exists( 'inet_pton' ) && function_exists( 'inet_ntop' ) ) {
				$ip_addr = inet_ntop( inet_pton( $ip_addr ) & inet_pton( $netmask ) );
				if ( false === $ip_addr ) {
					return '::';
				}
			} elseif ( ! $ipv6_fallback ) {
				return '::';
			}
		} elseif ( $is_ipv4 ) {
			// Strip any port and partially anonymize the IP.
			$last_octet_position = strrpos( $ip_addr, '.' );
			$ip_addr             = substr( $ip_addr, 0, $last_octet_position ) . '.' . $symbol;
		} else {
			return '0.0.0.0';
		}
	 
		// Restore the IPv6 prefix to compatibility mode addresses.
		return $ip_prefix . $ip_addr;
	}
}
